@true-directive/base
Version:
The set of base classes for the TrueDirective Grid
629 lines (628 loc) • 25.7 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
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 { SelectionMode, LazyLoadingMode, EditorShowMode } from './classes/enums';
import { FilterShowEvent } from './classes/events';
import { DataSource } from './classes/data-source.class';
import { PageInfo } from './classes/page-info.class';
import { ColumnCollection } from './classes/column-collection.class';
import { DataQuery } from './classes/data-query.class';
import { CellPosition } from './classes/cell-position.class';
import { Selection } from './classes/selection.class';
import { GridLayout } from './classes/grid-layout.class';
import { GridExporter } from './classes/grid-exporter.class';
import { Utils } from './common/utils.class';
import { AxInject } from './classes/ax-inject.class';
import { AxInjectConsumer } from './classes/ax-inject-consumer.class';
import { GridSettings } from './classes/grid-settings.class';
import { GridUIHandler } from './handlers/grid-ui.handler';
import { GridCheckHandler } from './handlers/grid-check.handler';
import { GridDragHandler } from './handlers/grid-drag.handler';
import { GridLazyLoadHandler } from './handlers/grid-lazy-load.handler';
import { LayoutsHandler } from './handlers/layouts.handler';
/**
* Grid's state. Contains:
* - grid's settings
* - provided column's list
* - column's lists for every part of the grid (only main area in the current version)
* - sorting info
* - drag-n-drop state
* - current page info
* Receives changes of the state and provides it for all parts.
*/
var GridState = /** @class */ (function (_super) {
__extends(GridState, _super);
function GridState() {
var _this = _super.call(this) || this;
// -- etc --
_this.IE = Utils.detectIE();
_this.iOS = Utils.detectIOS();
_this.android = Utils.detectAndroid();
_this.safari = Utils.detectSafari();
_this.pageInfo = new PageInfo(0, 1);
/**
* The width of viewport's visible area.
* This property is used for column's width calculation
* with setting columnAutoWidth=true.
*/
_this._clientWidth = 0;
_this._clientHeight = 0;
/**
* Index of the first row is displayed according to current scroll position.
*/
_this._displayedStartIndex = 0;
/**
* Data query counter
*/
_this._dataQueryCounter = 0;
_this.registerHandlers();
_this.updateInjections();
return _this;
}
Object.defineProperty(GridState.prototype, "settings", {
get: function () { return this._settings; },
set: function (s) {
this._settings = s;
this.updateInjections();
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "st", {
get: function () { return this._settings; } // Short alias
,
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "ds", {
get: function () { return this.dataSource; },
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "sta", {
get: function () { return this.settings.appearance; } // Short alias
,
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "model", {
get: function () {
return this.dataSource.model;
},
/**
* Данные грида
*/
set: function (rows) {
this.dataSource.model = rows;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "columns", {
get: function () {
return this.columnCollection.columns;
},
set: function (v) {
this.columnCollection.columns = v;
this.layoutsHandler.setLayoutsVisibility();
this.updateLayouts();
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "layout", {
get: function () {
return this.layoutsHandler.layout;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "layoutDrag", {
get: function () {
return this.layoutsHandler.layoutDrag;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "showFixedLeft", {
// Это всё мы передадим в обработчики
get: function () {
return false;
},
set: function (v) { },
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "showFixedRight", {
get: function () {
return false;
},
set: function (v) { },
enumerable: true,
configurable: true
});
/**
* Gets column by field name
* @param f Field name
* @return Column if exists
*/
GridState.prototype.columnByFieldName = function (f) {
return this.columnCollection.columnByFieldName(f);
};
Object.defineProperty(GridState.prototype, "isTree", {
/**
* Отображать ли данные в виде дерева
*/
get: function () {
// Текущая версия не поддерживает отображение дерева
return false;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "maxLevel", {
/**
* Уровень вложенности - ноль
*/
get: function () {
return 0;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "clientWidth", {
get: function () {
return this._clientWidth;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "clientHeight", {
get: function () {
return this._clientHeight;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "layouts", {
/**
* The list of grid parts
*/
get: function () {
return this.layoutsHandler.layouts;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "touchMode", {
/**
* The device supporting touch events is used.
*/
get: function () {
return this.iOS || this.android;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GridState.prototype, "displayedStartIndex", {
get: function () {
return this._displayedStartIndex;
},
set: function (index) {
this._displayedStartIndex = index;
this.layouts.forEach(function (l) { return l.selection.updateDisplayedStartIndex(index); });
},
enumerable: true,
configurable: true
});
// ---------------------------------------------------------------------------
GridState.prototype.checkClientWidth = function (v) {
if (this._clientWidth !== v) {
this._clientWidth = v;
this.updateLayouts();
return true;
}
return false;
};
GridState.prototype.checkClientHeight = function (v) {
var res = false;
if (this._clientHeight !== v) {
res = true;
}
this._clientHeight = v;
return res;
};
/**
* Recalculation of rows in accordance with the specified filters,
* sorting and other.
*/
GridState.prototype.recalcData = function () {
var _this = this;
return new Promise(function (resolve) {
_this.ds.recalcData();
resolve();
});
};
GridState.prototype.getQuery = function (subject) {
if (subject === void 0) { subject = null; }
return this.ds.getQuery(++this._dataQueryCounter, subject);
};
/**
* Request data from an observer.
* @param counter Query counter value
* @param subject Observer
*/
GridState.prototype.doQuery = function (subject, force) {
if (subject === void 0) { subject = null; }
if (force === void 0) { force = false; }
if (this.lazyLoader.query(0, false, force)) {
// Если запрос сделает ленивый загрузчик, то выходим
return;
}
this.events.dataQueryEvent(this.getQuery());
};
/**
* Initiation of data update with all recalculations.
* @param async Recalculation in the asynchronous thread.
*/
GridState.prototype.updateData = function (async) {
var _this = this;
if (async === void 0) { async = true; }
if (this.st.lazyLoading === LazyLoadingMode.FRAGMENTARY) {
if (this.ds.totalRowCount > 0) {
// Force current page update
this.lazyLoader.query(this.pageInfo.offset, false, true);
return;
}
}
if (this.settings.requestData || this.settings.lazyLoading !== LazyLoadingMode.NONE) {
// Необходимо запросить данные
this.doQuery(null, true);
// НО! Нужно обновить колонки.
this.events.columnsChangedEvent();
return;
}
// Запрашивать не нужно, считаем всё сами
if (async) {
// Асинхронное обновление
this.recalcData().then(function () {
_this.fetchData(new DataQuery(_this._dataQueryCounter));
});
}
else {
// Синхронное
this.ds.recalcData();
this.fetchData(new DataQuery(this._dataQueryCounter));
}
};
// Принимаем данные извне
GridState.prototype.fetchData = function (query, data, totalRowCount) {
if (data === void 0) { data = null; }
if (totalRowCount === void 0) { totalRowCount = null; }
if (this.settings.lazyLoading !== LazyLoadingMode.NONE) {
this.lazyLoader.fetch(data, query, totalRowCount);
}
else {
// Если счетчик не совпадает, то позднее был новый запрос. И в этих данных смысла
// уже нет
if (this._dataQueryCounter !== query.queryId) {
return;
}
if (data !== null) {
// Если данные пересчитаны извне..
this.ds.fetchData(data, totalRowCount);
}
}
// Обновить нужно. Потому что уровни дерева могли поменяться
this.updateLayouts();
// Обновляем галки колонок
this.check.updateCheckColumns();
// Обновляем индексы строк выделенных областей
this.layoutsHandler.updateSelectionIndices();
// Отправляем информацию о том, что данные получены
this.events.dataFetchEvent(query);
};
// Обновляем отображаемые данные в основном компоненте
GridState.prototype.queryChanged = function () {
// Генерируем событие о необходимости обновления данных
// Проверяем ленивую загрузку с флагом сбрасывания данных
//if (!this.lazyLoader.query(0, true)) {
// Если не ленивая загрузка, то как всегда.
// Иначе ленивая загрузка сама отправит данные
this.events.queryChangedEvent(this.ds.getQuery());
//}
// вроде как здесь не нужна эта тема с ленивой загрузкой, т.к. при
// updateData всё происходит
};
// Делаем так, чтобы ничего не было выделено
GridState.prototype.clearSelection = function () {
this.selection.clearAll();
};
// -- LAYOUTS ----------------------------------------------------------------
// Обновление состояния дочерних компонентов
GridState.prototype.updateLayouts = function () {
var _this = this;
if (!this.columns) {
throw new Error('GRID: Columns are not defined');
}
// Все секции. Хотя пока у нас и одна только..
// Автоматическая ширина колонок только в основной секции
this.layouts.forEach(function (l) { return l.update(_this.columns, _this.st.widthUnit, _this.st.levelIndent, _this.clientWidth, l === _this.layout && _this.st.columnAutoWidth); });
// Это для нас обновление сопутствующих дел
this.resizeLayouts();
this.layoutsHandler.updateLayoutSelections();
};
GridState.prototype.resizeLayouts = function () {
var _this = this;
this.layouts.forEach(function (l) { return l.resize(_this.st.widthUnit, _this.st.levelIndent, _this.clientWidth, l === _this.layout && _this.st.columnAutoWidth); });
};
// Фильтр
GridState.prototype.showFilter = function (e, c) {
var f = this.ds.getFilter(c);
f = f ? f.clone(true) : c.createFilter(this.selection.focusedValue(c));
this.events.filterShowEvent(new FilterShowEvent(e.target, f));
};
// Установка фильтра
GridState.prototype.setFilter = function (f) {
this.ds.setFilter(f);
this.queryChanged();
};
// Очистка фильтра по заданной колонке
GridState.prototype.resetFilter = function (f) {
if (this.ds.removeFilter(f.fieldName)) {
this.queryChanged();
}
};
/**
* Data sorting
* @param sortings List of sortings
*/
GridState.prototype.sort = function (sortings, update) {
if (update === void 0) { update = true; }
this.ds.sort(sortings);
if (update) {
this.queryChanged();
}
};
/**
* Data filtering
* @param filter List of filters
*/
GridState.prototype.filter = function (filters, update) {
if (update === void 0) { update = true; }
this.ds.filter(filters);
if (update) {
this.queryChanged();
}
};
/**
* Sort by given column
* @param col Column
* @param add Если true, то оставляем предыдущую сортировку (с зажатым shift)
*/
GridState.prototype.sortByColumn = function (col, add) {
if (!this.st.allowSorting) {
return;
}
this.ds.sortByColumn(col, add);
this.queryChanged();
};
/**
* Сортировать по полю
* @param fieldName Наименование поля
* @param add Добавить сортировку к другим сортировкам
*/
GridState.prototype.sortByField = function (fieldName, add) {
var col = this.columnByFieldName(fieldName);
this.sortByColumn(col, add);
};
// -- COLUMN RESIZING & REORDERING -------------------------------------------
// Изменение ширины колонки
GridState.prototype.resizeColumn = function (col, newWidth) {
col.width = newWidth;
this.updateLayouts();
this.events.columnsChangedEvent();
};
GridState.prototype.hideColumn = function (col) {
col.visible = false;
this.updateLayouts();
this.events.columnsChangedEvent();
};
// Чиним состояние после drag-n-drop
GridState.prototype.fixDrag = function (target) { };
// Перемещение бэнда
GridState.prototype.reorderBand = function (targetBand, dropInfo) {
if (this.columnCollection.reorderBand(targetBand, dropInfo)) {
this.updateLayouts();
this.events.columnsChangedEvent();
}
};
// Перемещение колонки
GridState.prototype.reorderColumn = function (target, dropInfo, commit) {
if (commit === void 0) { commit = true; }
if (this.columnCollection.reorderColumn(target, dropInfo)) {
this.updateLayouts();
this.events.columnsChangedEvent();
}
};
// -- PAGING -----------------------------------------------------------------
// Проверка необходимости установки страницы отображаемых данных
GridState.prototype.needSetPage = function (i0, i1) {
return i0 < this.pageInfo.offset || i1 > (this.pageInfo.offset + this.pageInfo.limit);
};
// Установка страницы отображаемых данных
GridState.prototype.setPage = function (offset, limit) {
this.pageInfo.offset = offset;
this.pageInfo.limit = limit;
};
// Фокус сместился
GridState.prototype.focusChanged = function (cp) {
if (this.st.editorShowMode === EditorShowMode.ON_MOUSE_DOWN) {
this.ui.stopEditing(this.ui.editor, cp !== null);
this.ui.startEditing(cp);
}
else {
this.ui.stopEditing(this.ui.editor, cp !== null);
}
};
// Выделить заданную строку
GridState.prototype.selectRow = function (r, ri) {
return this.selection.selectRow(this.layouts, r, ri, '', this.settings.keyField);
};
// Выделение заданной строки
GridState.prototype.locateRow = function (r) {
var ri = this.ds.resultRows.indexOf(r);
if (ri >= 0) {
this.selectRow(r, ri);
return true;
}
return false;
};
// Выделение строки по значению поля-идентифиатора
GridState.prototype.locateByKey = function (keyValue, keyField) {
if (keyField === void 0) { keyField = ''; }
if (keyField === '') {
keyField = this.settings.keyField;
}
if (this.ds.resultRowCount === 0) {
return false;
}
var found = this.ds.resultRows.find(function (r) { return r[keyField] === keyValue; });
if (found) {
var ri = this.ds.resultRows.indexOf(found);
if (ri >= 0) {
this.selectRow(found, ri);
return true;
}
}
return false;
};
// -- HEADER CONTEXT MENU ----------------------------------------------------
GridState.prototype.headerContextMenu = function (e, column) {
this.events.headerContextMenuEvent({ originalEvent: e, column: column });
};
// -- SUMMARIES --------------------------------------------------------------
GridState.prototype.updateSummaries = function () {
this.ds.summaries(this.columns);
};
// Добавляет суммирование
GridState.prototype.addSummary = function (column, t) {
column.addSummary(t);
this.events.summariesChangedEvent(column);
};
// Заменяет суммирование
GridState.prototype.setSummary = function (column, t, a) {
if (a === void 0) { a = null; }
column.setSummary(t, a);
this.events.summariesChangedEvent(column);
};
// -- ROW DRAG ---------------------------------------------------------------
GridState.prototype.canDrop = function (draggedRows, dropRow, dropPos) {
return this.ds.canDrop(draggedRows, dropRow, dropPos);
};
GridState.prototype.moveRows = function (draggedRows, dropTarget, dropPos) {
this.ds.moveRows(draggedRows, dropTarget, dropPos);
this.updateData();
};
GridState.prototype.headerContextMenuEvent = function (e, column) {
// Not implemented
};
GridState.prototype.getSelectedData = function (selection) {
return GridExporter.dataToExport(this.layouts, selection, this.st.selectionMode, this.ds.resultRows, this.ds.valueFormatter);
};
GridState.prototype.selectAll = function (sel) {
var firstCol = GridLayout.firstColumn(this.layouts);
var lastCol = GridLayout.lastColumn(this.layouts);
var rr = this.ds.resultRows;
sel.startSelect(new CellPosition(rr[0], 0, firstCol.fieldName));
sel.proceedToSelect(new CellPosition(rr[rr.length - 1], rr.length - 1, lastCol.fieldName), false);
return sel;
};
// -- Data to export
GridState.prototype.dataToExport = function () {
return GridExporter.dataToExport(this.layouts, this.selectAll(new Selection()), SelectionMode.RANGE, this.ds.resultRows, this.ds.valueFormatter);
};
// -- CUSTOM CELL EVENTS -----------------------------------------------------
GridState.prototype.emitCustomCellEvent = function (e) {
this.events.customCellEvent(e);
};
GridState.prototype.registerHandlers = function () {
this.handlers = {
'settings': GridSettings,
'columns': ColumnCollection,
'selection': Selection,
'dataSource': DataSource,
'check': GridCheckHandler,
'ui': GridUIHandler,
'lazyLoader': GridLazyLoadHandler,
'dragDrop': GridDragHandler,
'layouts': LayoutsHandler
};
};
__decorate([
AxInject('dataSource'),
__metadata("design:type", DataSource)
], GridState.prototype, "dataSource", void 0);
__decorate([
AxInject('selection'),
__metadata("design:type", Selection)
], GridState.prototype, "selection", void 0);
__decorate([
AxInject('check'),
__metadata("design:type", GridCheckHandler)
], GridState.prototype, "check", void 0);
__decorate([
AxInject('dragDrop'),
__metadata("design:type", GridDragHandler)
], GridState.prototype, "dragDrop", void 0);
__decorate([
AxInject('ui'),
__metadata("design:type", GridUIHandler)
], GridState.prototype, "ui", void 0);
__decorate([
AxInject('lazyLoader'),
__metadata("design:type", GridLazyLoadHandler)
], GridState.prototype, "lazyLoader", void 0);
__decorate([
AxInject('events'),
__metadata("design:type", Object)
], GridState.prototype, "events", void 0);
__decorate([
AxInject('layouts'),
__metadata("design:type", LayoutsHandler)
], GridState.prototype, "layoutsHandler", void 0);
__decorate([
AxInject('columns'),
__metadata("design:type", ColumnCollection)
], GridState.prototype, "columnCollection", void 0);
__decorate([
AxInject('settings'),
__metadata("design:type", GridSettings)
], GridState.prototype, "_settings", void 0);
return GridState;
}(AxInjectConsumer));
export { GridState };