@true-directive/grid
Version:
Angular Data Grid from Yopsilon.
1,030 lines • 147 kB
JavaScript
import * as tslib_1 from "tslib";
/**
* Copyright (c) 2018-2019 Aleksey Melnikov, True Directive Company.
* @link https://truedirective.com/
* @license MIT
*/
import { Directive, ElementRef, Input, EventEmitter, Output, Renderer2, Injector, ComponentFactoryResolver, ApplicationRef } from '@angular/core';
// Base
import { GridLayout } from '@true-directive/base';
import { ColumnType, RenderMode } from '@true-directive/base';
import { CellHighlighter } from '@true-directive/base';
// Classes
import { RowCell } from './row-cell.class';
// Services
import { GridStateService } from './grid-state.service';
// Editor components
import { EditorTextComponent } from './editors/editor-text.component';
import { EditorSelectTrueComponent } from './editors/editor-select-true.component';
import { EditorNumberComponent } from './editors/editor-number.component';
import { EditorDateComponent } from './editors/editor-date.component';
// Cell components
import { CellHtmlComponent } from './cells/cell-html.component';
import { CellRefComponent } from './cells/cell-ref.component';
/**
* Grid row directive. It's all about speed.
*/
let RowDirective = class RowDirective {
constructor(_renderer, _cfResolver, _appRef, _injector, elementRef) {
this._renderer = _renderer;
this._cfResolver = _cfResolver;
this._appRef = _appRef;
this._injector = _injector;
this.elementRef = elementRef;
/**
* Indicates we're an empty line and we don't need to do anything.
*/
this.empty = false;
/**
* Horizontal scroll position
*/
this.viewPortLeft = -1;
/**
* Scrollbox width
*/
this.viewPortWidth = -1;
/**
* Locale
*/
this.locale = '';
/**
* Event - clicking on the checkbox - will cause the value to change
*/
this.toggleCheckbox = new EventEmitter();
this._left_rendered = -1;
this._right_rendered = -1;
/**
* Cell list
*/
this.cells = [];
/**
* Cell selection levels
*/
this.selectionMap = [];
/**
* View was initialized
*/
this._viewInitialized = false;
/**
* One of the cells was in edit mode before destroying the row
*/
this._wasEditor = null;
/**
* Row height in previous render
*/
this._height0 = null;
/**
* Locale in previous render
*/
this._locale0 = '';
// Применение стилей помеченных записей
this._checkedAppearance = false;
// Подписки на изменения в редакторе
this._subscribes = [];
/**
* Предыдущее значение общего текстового фильтра
*/
this._filter0 = '';
this._editorRef = null;
this._customCellRefs = [];
this._skips = [];
}
/**
* Data of the displayed row
*/
get rowData() {
return this.state.dataSource.rowData(this.row);
}
get st() {
return this.state.settings;
}
get sta() {
return this.state.settings.appearance;
}
get currentRowIndex() {
return this.axI + this.layout.selection.displayedStartIndex;
}
get children() {
return this.elementRef.nativeElement.children;
}
firstCellRect() {
for (let i = 0; i < this.children.length; i++) {
const el = this.children[i];
// Эти вообще не считаем.
if (el.classList.contains('true-cell-indent')) {
continue;
}
return el.getBoundingClientRect();
}
return null;
}
firstCellClientHeight() {
for (let i = 0; i < this.children.length; i++) {
const el = this.children[i];
if (el.classList.contains('true-cell-indent')) {
continue; // Эти могут быть без бордеров, а остальные с бордерами
}
return el.clientHeight;
}
return null;
}
/**
* Получение поля по координатам
* @param x Координата поля
* @return [description]
*/
cellByXY(x, y) {
let xx = this.cells[0].element.getBoundingClientRect().left;
for (let i = 0; i < this.cells.length; i++) {
const cell = this.cells[i];
const col = this.state.columnByFieldName(cell.fieldName);
const ww = !cell.skipped ? cell.element.offsetWidth : col.displayedWidth;
if (x >= xx && x < xx + ww) {
return cell.fieldName;
}
xx += ww;
}
return '';
}
/**
* Вызывается для получения Х-координаты ячейки с целью прокрутки
* компонента к заданной ячейке
* @param fieldName Наименование поля ячейки
* @return Координаты левого и правого края
*/
cellHorizontalPos(fieldName) {
const x0 = this.cells[0].element.offsetLeft;
let xx = x0;
for (let i = 0; i < this.cells.length; i++) {
const cell = this.cells[i];
const col = this.state.columnByFieldName(cell.fieldName);
// Получить clientWidth
const ww = !cell.skipped ? cell.element.offsetWidth : col.displayedWidth;
if (cell.fieldName === fieldName) {
return {
// Для первой колонки указыаем нулевой offset, чтобы при наличии indents
// прокрутка осуществлялась к самому началу
l: i === 0 ? 0 : xx,
r: xx + ww
};
}
xx += ww;
}
return null;
}
// Очистка выделения
clearSelection() {
this.cells.forEach((cell) => {
cell.setSelected(0);
cell.setCellFocused(false);
});
}
// Генерируем план выделения
getSelectionMap(sel, rowChecked = false) {
const sels = [];
let sel0 = 0;
for (let i = 0; i < this.cells.length; i++) {
sels.push(sel0);
}
for (let j = 0; j < sel.ranges.length; j++) {
const selection = sel.ranges[j];
// По вертикали
let minI = selection.rowIndex;
let maxI = selection.rowIndex + selection.rangeY;
// Меняем местами 'to' and 'from'
if (minI > maxI) {
const t = maxI;
maxI = minI;
minI = t;
}
if (this.currentRowIndex < minI || this.currentRowIndex > maxI) {
continue; // В этой строке ничего не выделено
}
// По горизонтали
const fromIndex = selection.columnIndex;
const toIndex = fromIndex + selection.rangeX;
const selectedColumnIndex = fromIndex;
for (let i = 0; i < this.cells.length; i++) {
if (i >= fromIndex && i <= toIndex || i <= fromIndex && i >= toIndex) {
sels[i]++;
}
}
}
return sels;
}
setCellSelection(cell, idx) {
const sel = this.layout.selection;
const selected = this.selectionMap[idx];
const cellFocused = this.currentRowIndex === sel.focusedRowIndex && idx === sel.focusedColumnIndex;
cell.setSelected(selected);
cell.setCellFocused(cellFocused);
return selected;
}
// Устанавливаем выделение
setSelection() {
const sel = this.layout.selection;
const rowChecked = this.state.check.isRowChecked(this.row);
if (this.state.sta.checkedRowClass != '' && (this.state.sta.enableCheckedAppearance || this._checkedAppearance)) {
if (rowChecked && this.state.sta.enableCheckedAppearance) {
this.elementRef.nativeElement.classList.add(this.sta.checkedRowClass);
}
else {
this.elementRef.nativeElement.classList.remove(this.sta.checkedRowClass);
}
}
this._checkedAppearance = this.sta.enableCheckedAppearance;
if (sel.ranges.length < 1 && !rowChecked) {
this.clearSelection();
return;
}
this.selectionMap = this.getSelectionMap(sel, rowChecked);
this.cells.forEach((cell, i) => {
this.setCellSelection(cell, i);
});
}
// Полная очистка строки
clear(saveH = false) {
if (saveH) {
// Сохраняем высоту строки для редактора
this._height0 = this.firstCellClientHeight();
}
else {
// Сбрасываем высоту строки, чтобы не было недостоверной информации
this._height0 = null;
}
this._subscribes.forEach(s => s.unsubscribe());
this._subscribes = [];
this.cells.splice(0, this.cells.length);
let itemsToRemove = [];
// Fastest way
this.elementRef.nativeElement.innerHTML = '';
if (this._customCellRefs.length > 0) {
this._customCellRefs.forEach(r => r.destroy());
this._customCellRefs.splice(0, this._customCellRefs.length);
}
this.clearEditor();
}
clearEditor() {
this._height0 = this.firstCellClientHeight();
if (this._editorRef && this._wasEditor) {
const cp = this._wasEditor;
this.cells.forEach(cell => {
if (cell.fieldName === cp.fieldName && this.rowData === cp.row) {
cell.element.style.height = 'unset';
this._renderer.removeClass(cell.element, 'true-cell-input');
let itemsToRemove = [];
let i = 0;
while (i < cell.element.children.length) {
itemsToRemove.push(cell.element.children[i]);
i++;
}
itemsToRemove.forEach(item => this._renderer.removeChild(cell.element, item));
const col = this.state.columnByFieldName(cp.fieldName);
const rowData = this.rowData;
const v = this.rowData[col.fieldName];
const v_displayed = this.getDisplayedValue(col, rowData, v);
this.fillCell(cell, col, rowData, false, v, v_displayed);
cell.value = v;
}
/*
this._editorRef.destroy();
this._editorRef = null;
*/
this._wasEditor = null;
});
}
}
renderStub(rowData, cell, col) {
if (col.isBoolean) {
return;
}
const divEl = this._renderer.createElement('span');
const w = 20 + Math.random() * 40;
divEl.style.width = w + '%';
this._renderer.appendChild(cell.element, divEl);
this._renderer.addClass(divEl, 'true-stub');
}
// Чекбокс создается прямо в td. Для того, чтобы его ширина не зависела
// от наличия бордеров и ширины ячейки, было бы неплохо создать
// промежуточный div с display: flex. Но вызов еще одного createElement
// сильно замедляет процесс создания строки.
renderBoolean(rowData, cell, col, v) {
const divEl = this._renderer.createElement('div');
if (this.st.canEditColumnCell(col)) {
this._renderer.addClass(divEl, this.sta.checkboxClass);
this._renderer.listen(divEl, 'mousedown', (e) => e.stopPropagation());
this._renderer.listen(divEl, 'dblclick', (e) => e.stopPropagation());
this._renderer.listen(divEl, 'click', (e) => {
this.toggleCheckbox.emit({ row: rowData, fieldName: col.fieldName });
e.stopPropagation();
});
this._renderer.appendChild(cell.element, divEl);
}
else {
const classes = this.sta.booleanClass.trim().split(' ');
classes.forEach(s => this._renderer.addClass(divEl, s));
this._renderer.appendChild(cell.element, divEl);
}
cell.cbElement = divEl;
cell.setChecked(v);
}
renderCheckbox(cell, col, v) {
const divEl = this._renderer.createElement('div');
this._renderer.addClass(divEl, this.sta.checkboxClass);
if (!this.st.checkByCellClick) {
this._renderer.listen(divEl, 'mousedown', (e) => e.stopPropagation());
this._renderer.listen(divEl, 'dblclick', (e) => e.stopPropagation());
this._renderer.listen(divEl, 'click', (e) => {
this.toggleCheckbox.emit({ row: this.row, fieldName: col.fieldName });
e.stopPropagation();
});
}
cell.cbElement = divEl;
this._renderer.appendChild(cell.element, divEl);
cell.setChecked(v);
}
getEditorComponentType(col) {
let editorType = EditorTextComponent;
if (col.type === ColumnType.DATETIME) {
editorType = EditorDateComponent;
}
if (col.type === ColumnType.NUMBER) {
editorType = EditorNumberComponent;
}
if (col.type === ColumnType.UNSAFE_HTML) {
editorType = EditorSelectTrueComponent;
}
if (col.editorComponentType !== null) {
editorType = col.editorComponentType;
}
return editorType;
}
getDh() {
// Один пиксел добавим, если видны горизонтальные линии
let dh = 0;
if (this.axI !== 0 && !this.state.IE && this.sta.horizontalLines) {
dh = 1;
}
return dh;
}
setEditorHeight(cell) {
// Тест, когда всё редакторы
if (this._height0 === null && this.state.ui.editorHeight !== null) {
// Если в состоянии сохранена высота, то используем её
this._height0 = this.state.ui.editorHeight;
}
else {
// Иначе наоборот - сохраняем высоту
this.state.ui.editorHeight = this._height0;
}
if (this._height0 >= this.state.settings.rowHeight) {
cell.element.style.height = (this._height0 - 1) + 'px';
}
}
renderEditor(rowData, cell, col, v) {
this._renderer.addClass(cell.element, 'true-cell-input');
const editorType = this.getEditorComponentType(col);
const componentFactory = this._cfResolver.resolveComponentFactory(editorType);
this._editorRef = componentFactory.create(this._injector, [], cell.element);
this._appRef.attachView(this._editorRef.hostView);
// Initialization
this._editorRef.instance.state = this.state;
this._editorRef.instance.column = col;
this._editorRef.instance.row = rowData;
this.setEditorHeight(cell);
const dh = this.getDh();
// Изменение значения. Сохраняем измененное.
const s_change = this._editorRef.instance.change.subscribe((v) => {
this.state.ui.editorValue = v;
});
// Подтверждение редактирования. Отправляем в данные
const s_commit = this._editorRef.instance.commit.subscribe((e) => {
this.state.ui.commitEditor(this.row, col.fieldName, e);
});
// Отмена редактирования
const s_cancel = this._editorRef.instance.cancel.subscribe(() => {
let cp = this._wasEditor.clone();
this.state.ui.stopEditing(cp, true, true);
});
this._editorRef.instance.init(this.state.ui.editorValue, this.state.ui.editorValueChanged, this._height0 + dh, this.state.IE, this.state.ui.editorWasShown);
this.state.ui.editorWasShown = true;
// Persisting last editor state
if (this.state.ui.editor) {
this._wasEditor = this.state.ui.editor.clone();
}
//
this._subscribes.push(s_change);
this._subscribes.push(s_commit);
this._subscribes.push(s_cancel);
}
// Пока так
renderCustomCell(rowData, cell, col, v, componentType = CellHtmlComponent) {
this._renderer.addClass(cell.element, 'true-cell-custom');
const componentFactory = this._cfResolver.resolveComponentFactory(componentType);
const cr = componentFactory.create(this._injector, [], cell.element);
// Initialization
cr.instance.state = this.state;
cr.instance.column = col;
cr.instance.row = rowData;
this._appRef.attachView(cr.hostView);
cr.instance.init(this.getDisplayedValue(col, rowData, v));
// Подтверждение редактирования. Отправляем в данные
const s = cr.instance.event.subscribe((e) => {
// вызываем в стэйте
this.state.emitCustomCellEvent(e);
});
this._customCellRefs.push(cr);
this._subscribes.push(s);
}
getDisplayedValue(col, rowData, v) {
return this.state.dataSource.displayedValue(col, v, rowData);
}
fillCell(cell, col, rowData, isFirst, v, v_displayed) {
const classes = this.state.st.cellClass(col).trim().split(' ');
classes.forEach(s => {
if (s !== '') {
this._renderer.addClass(cell.element, s);
}
});
if (col.classField !== '' && rowData[col.classField]) {
this._renderer.addClass(cell.element, rowData[col.classField]);
}
cell.rendered = true;
cell.fieldName = col.fieldName;
if (rowData.__ax === 'empty') {
this.renderStub(rowData, cell, col);
return cell;
}
const tdEl = cell.element;
if (col.isCheckbox) {
// Помечаются не только данные, но и заголовки групп. Поэтому
// апдейтится строка из результирующего набора данных
this.renderCheckbox(cell, col, v);
return cell;
}
if (col.isBoolean) {
// Может быть изменено только значение исходных данных, но не
// заголовков групп. Поэтому отправляется исходная строка
this.renderBoolean(rowData, cell, col, v);
return cell;
}
if (col.type === ColumnType.REFERENCE) {
this.renderCustomCell(rowData, cell, col, v, CellRefComponent);
return cell;
}
if (this.state.ui.editor !== null &&
this.state.ui.editor.fieldName === col.fieldName &&
this.state.ui.editor.row === rowData) {
// Заголовок группы не может быть отредактирован, отправляются исходные
// данные
this.renderEditor(rowData, cell, col, v);
return cell;
}
if (col.cellComponentType !== null) {
// Чтобы кастомная ячейка не путалась, отправляются исходные данные.
// Если ячейка будет создана в заголовке группы - мы это не предусмотрели.
this.renderCustomCell(rowData, cell, col, v, col.cellComponentType);
return cell;
}
if (col.type === ColumnType.HTML) {
// Чтобы кастомная ячейка не путалась, отправляются исходные данные.
// Если ячейка будет создана в заголовке группы - мы это не предусмотрели.
this.renderCustomCell(rowData, cell, col, v);
return cell;
}
let html = col.type === ColumnType.UNSAFE_HTML;
if (this.state.dataSource.searchString !== '' && this.state.st.searchHighlight) {
html = true;
}
if (html) {
const s = this.state.dataSource.searchString;
tdEl.innerHTML = CellHighlighter.highlight(s, col, v, v_displayed);
}
else {
tdEl.innerText = v_displayed;
}
return cell;
}
needRender(col, xPos, isFirst) {
let render = true;
// Не все ячейки рендерятся только при настройке RenderMode.VISIBLE
if (this.st.renderMode !== RenderMode.VISIBLE) {
return render;
}
if (this.viewPortLeft >= 0 && !isFirst) {
// Учитываем вьюпорт
if (xPos > (this.viewPortLeft + this.viewPortWidth)) {
// Мы находимся правее
render = false;
}
if ((xPos + col.headerWidth) < this.viewPortLeft) {
// Мы находимся левее
render = false;
}
}
return render;
}
createTd(span) {
const tdEl = this._renderer.createElement('td');
if (span > 1) {
this._renderer.setAttribute(tdEl, 'colspan', span + '');
}
return tdEl;
}
/**
* Создание ячейки
* @param col Колонка
* @param span Количество объединенных ячеек
* @return Объект RowCell
*/
createCell(col, span = 1, isFirst = false, xPos = -1, render = true) {
const rowData = this.rowData;
const v = rowData !== null ? rowData[col.fieldName] : null;
const cell = new RowCell(col.fieldName, v, null);
cell.element = this.createTd(span);
if (render) {
const v_displayed = this.getDisplayedValue(col, rowData, v);
this.fillCell(cell, col, rowData, isFirst, v, v_displayed);
}
return cell;
}
// Для дерева - проверка необходимости объединения ячеек
needApplySpan() {
return 1;
}
createSkipCell(skipCount) {
const tdEl = this._renderer.createElement('td');
this._renderer.setAttribute(tdEl, 'colspan', skipCount + '');
return tdEl;
}
renderRowEditor() {
for (let i = 0; i < this.layout.columns.length; i++) {
const col = this.layout.columns[i];
if (col.isBoolean) {
continue;
}
const cell = this.cells[i];
if (this.state.ui.editor !== null &&
this.state.ui.editor.fieldName === col.fieldName &&
this.state.ui.editor.row === this.rowData) {
// Заголовок группы не может быть отредактирован, отправляются исходные
// данные
const v = this.rowData[col.fieldName];
this.renderEditor(this.rowData, cell, col, v);
return cell;
}
}
}
// Заполнение строки (создание разметки и вставка данных)
renderRow() {
this._locale0 = this.locale;
this._skips.splice(0, this._skips.length);
this._wasEditor = null;
if (!this.empty) {
this._filter0 = this.state.dataSource.searchString;
}
// Удаление старых ячеек
this.cells.splice(0, this.cells.length);
let firstCell = true;
if (this.empty) {
const tdEl = this._renderer.createElement('td');
this._renderer.setAttribute(tdEl, 'colspan', this.layout.columns.length + '');
this._renderer.appendChild(this.elementRef.nativeElement, tdEl);
return;
}
// const dt = Date.now();
let xPos = 0;
let skipCount = 0;
let skipStart = -1;
let skipEnd = -1;
for (let i = 0; i < this.layout.columns.length; i++) {
const col = this.layout.columns[i];
// Для дерева.. Нам нужен уровень.. И растягивание первой не чекбоксовой колонки
// Но только если мы находимся в самой левой части
let span = 1;
const f = firstCell;
if (firstCell && !col.isCheckbox) {
span = this.needApplySpan();
firstCell = false;
}
// Done
const needRender = this.needRender(col, xPos, f);
const cell = this.createCell(col, span, f, xPos, needRender);
this.cells.push(cell);
if (needRender) {
if (skipCount > 0) {
// Was skips
const skipTd = this.createSkipCell(skipCount);
this._renderer.appendChild(this.elementRef.nativeElement, skipTd);
skipCount = 0;
this._skips.push({ element: skipTd, fromIndex: skipStart, toIndex: skipEnd });
}
// Very resource intensive operation
this._renderer.appendChild(this.elementRef.nativeElement, cell.element);
}
else {
if (skipCount === 0) {
skipStart = i;
}
skipEnd = i;
cell.skipped = true;
skipCount++;
}
xPos += col.headerWidth;
}
if (skipCount > 0) {
const skipTd = this.createSkipCell(skipCount);
this._renderer.appendChild(this.elementRef.nativeElement, skipTd);
this._skips.push({ element: skipTd, fromIndex: skipStart, toIndex: skipEnd });
}
this.setSelection();
this.setDisabledFields();
this._left_rendered = this.viewPortLeft;
this._right_rendered = this.viewPortLeft + this.viewPortWidth;
}
nextEl(el) {
let found = false;
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] === el) {
found = true;
continue;
}
if (found) {
return this.children[i];
}
}
return null;
}
unskip(cell, i) {
for (let j = 0; j < this._skips.length; j++) {
const skip = this._skips[j];
if (i >= skip.fromIndex && i <= skip.toIndex) {
let insertBeforeEl = null;
if (i === skip.fromIndex) {
// Добавляем слева
skip.fromIndex++;
this._renderer.insertBefore(this.elementRef.nativeElement, cell.element, skip.element);
}
else {
if (i === skip.toIndex) {
// Добавляем справа
skip.toIndex--;
const nextEl = this.nextEl(skip.element);
if (nextEl !== null) {
this._renderer.insertBefore(this.elementRef.nativeElement, cell.element, nextEl);
}
else {
this._renderer.appendChild(this.elementRef.nativeElement, cell.element);
}
}
else {
// Добавляем посередине
// Создаем новый скип...
let newEl = this.createSkipCell(i - skip.fromIndex);
this._renderer.insertBefore(this.elementRef.nativeElement, cell.element, skip.element);
this._renderer.insertBefore(this.elementRef.nativeElement, newEl, cell.element);
this._skips.push({ element: newEl, fromIndex: skip.fromIndex, toIndex: i - 1 });
skip.fromIndex = i + 1;
}
}
if (skip.fromIndex > skip.toIndex) {
// Удаляем этот пропуск
this._skips.splice(j, 1);
this._renderer.removeChild(this.elementRef.nativeElement, skip.element);
}
else {
// Меняем его спан
this._renderer.setAttribute(skip.element, 'colspan', (skip.toIndex - skip.fromIndex + 1) + '');
}
cell.skipped = false;
break;
}
}
}
renderByViewPort() {
const rowData = this.rowData;
const right = this.viewPortLeft + this.viewPortWidth;
const left = this.viewPortLeft;
let xPos = 0;
// Первая ячейка всегда отрендерена
for (let i = 0; i < this.layout.columns.length; i++) {
// Подготавливаем данные
const col = this.layout.columns[i];
const cell = this.cells[i];
if (!cell) {
continue;
}
// Решаем, рендерить или нет
let needRender = this.needRender(col, xPos, false);
// Нужно последовательно добавлять...
if (needRender && i > 0) {
if (!cell.rendered) {
const v = cell.value;
const v_displayed = this.getDisplayedValue(col, rowData, v);
this.fillCell(cell, col, rowData, i === 0, v, v_displayed);
}
if (cell.skipped) {
this.unskip(cell, i);
}
}
xPos += col.headerWidth;
}
if (this._right_rendered < (this.viewPortLeft + this.viewPortWidth)) {
this._right_rendered = this.viewPortLeft + this.viewPortWidth;
}
if (this._left_rendered > this.viewPortLeft) {
this._left_rendered = this.viewPortLeft;
}
}
// Проверяем, нужно ли пересоздать по причине включения или выключения редактора
checkEditor() {
if (this._wasEditor === null && this.state.ui.editor === null) {
// Всё ок.
// Редактора и не было и не намечается.
return true;
}
if (this._wasEditor === null && this.state.ui.editor !== null) {
// Не было, но появился
if (this.state.ui.editor.row !== this.rowData) {
// Но строка не наша
return true;
}
}
if (this._wasEditor !== null && this.state.ui.editor !== null) {
// Был и не стало
if (this._wasEditor.row === this.state.ui.editor.row) {
// В этой строке
if (this._wasEditor.fieldName === this.state.ui.editor.fieldName) {
return true; // Не изменилось, оставляем
}
}
}
return false;
}
/**
* We check whether it is necessary to recreate the string when changing the
* column. If there were simple changes (two columns swapped or one of them
* just disappeared), we try to apply these changes without a full rerendering.
* @return True if we don't need a rerender.
*/
checkColumns() {
if (!this.layout) {
return false;
}
if (this.cells.length === 0 && !this.layout.columns) {
return true;
}
// The current number of cells is more than 1 higher than the number
// of columns.
if (this.cells.length > (this.layout.columns.length + 1)) {
return false;
}
if (this.cells.length < (this.layout.columns.length - 1)) {
return false;
}
let i = 0;
let changed = false;
while (i < this.cells.length) {
if (!this.layout || !this.layout.columns[i]) {
return false;
}
if (this.state.isTree && this.layout.columns[i].fieldName !== this.cells[i].fieldName) {
// For a tree, it wouldn't help if we just moved the columns around.
return false;
}
if (this.layout.columns[i].fieldName !== this.cells[i].fieldName) {
// Let's consider three scenarios so that we don't recreate the entire line...
if (i < this.cells.length - 1 &&
this.layout.columns[i].fieldName === this.cells[i + 1].fieldName) {
// 1. The column is missing?
// Removing the cell.
const ww = this.cells[i].element.offsetWidth;
this._renderer.removeChild(this.elementRef.nativeElement, this.cells[i].element);
this.cells.splice(i, 1);
this._skips.forEach(s => {
if (s.toIndex > i) {
s.toIndex--;
}
if (s.fromIndex > i) {
s.fromIndex--;
}
});
continue;
}
else {
if (i < this.cells.length - 2 &&
this.layout.columns[i].fieldName === this.cells[i + 2].fieldName) {
// 1.1. Two columns are missing?
// Remove one cell. The second one will be removed by the next iteration.
this._renderer.removeChild(this.elementRef.nativeElement, this.cells[i].element);
this.cells.splice(i, 1);
this._skips.forEach(s => {
if (s.toIndex > i) {
s.toIndex--;
}
if (s.fromIndex > i) {
s.fromIndex--;
}
});
continue;
}
else {
if (i < this.layout.columns.length - 1 &&
this.cells[i].fieldName === this.layout.columns[i + 1].fieldName) {
// 2. New column?
if (this.cells[i].skipped) {
return false;
}
this.viewPortLeft = -1;
const cell = this.createCell(this.layout.columns[i]);
cell.setDisabled(this.state.dragDrop.disabledFields.indexOf(cell.fieldName) >= 0);
this._renderer.insertBefore(this.elementRef.nativeElement, cell.element, this.cells[i].element);
this.cells.splice(i, 0, cell);
this._skips.forEach(s => {
if (s.toIndex > i) {
s.toIndex++;
}
if (s.fromIndex > i) {
s.fromIndex++;
}
});
// Don't forget to reset selection
changed = true;
i++;
}
else {
// Didn't help, we need to rerender!
return false;
}
}
}
}
i++;
}
// Render what fit on the screen after changing the columns
this.renderByViewPort();
if (changed) {
this.setSelection();
}
return true;
}
checkValues() {
if (!this.layout) {
return false;
}
if (this.cells.length === 0 && !this.layout.columns) {
return true;
}
// Другое количество ячеек
if (this.cells.length !== this.layout.columns.length) {
return false;
}
// Нужно обновить подсветку
if (this._filter0 !== this.state.dataSource.searchString) {
return false;
}
let i = 0;
while (i < this.cells.length) {
const cell = this.cells[i];
const rowData = this.rowData;
const v = rowData !== null ? rowData[cell.fieldName] : null;
if (v !== cell.value) {
if (cell.cbElement) {
cell.setChecked(this.row[cell.fieldName]);
}
else {
// Даём шанс редактору не инициировать перерисовку всей строки
if (this._wasEditor &&
this._wasEditor.fieldName === cell.fieldName &&
this._wasEditor.row === this.rowData) {
i++;
continue;
}
return false;
}
}
i++;
}
return true;
}
setDisabledFields() {
this.cells.forEach(cell => {
cell.setDisabled(this.state.dragDrop.disabledFields.indexOf(cell.fieldName) >= 0);
});
}
setParams(byInit = false) {
if (byInit) {
this.renderRow();
this._viewInitialized = true;
return;
}
if (!this._viewInitialized) {
return;
}
}
checkViewPort() {
return this._left_rendered <= this.viewPortLeft
&& this._right_rendered >= (this.viewPortLeft + this.viewPortWidth);
}
check() {
const localeChanged = this.locale !== this._locale0;
let settingsChanged = false;
if (this._checkedAppearance !== this.sta.enableCheckedAppearance) {
settingsChanged = true;
}
let valuesChanged = false;
//let editorChanged = false;
const columnsChanged = !this.checkColumns();
if (!columnsChanged) {
valuesChanged = !this.checkValues();
//if (!valuesChanged) {
//editorChanged = !this.checkEditor();
//}
}
return !(columnsChanged || valuesChanged || //editorChanged ||
settingsChanged || localeChanged);
}
ngOnChanges(changes) {
this.setParams();
}
ngDoCheck() {
if (!this._viewInitialized) {
return;
}
if (!this.check()) {
// Изменились основные параметры строки (колонки, значения, редактор)
const hasEditor = this.state.ui.editor && this.state.ui.editor.row === this.rowData;
// Очищаем
this.clear(hasEditor);
// И заново формируем строку
this.renderRow();
return;
}
//
if (!this.checkEditor()) {
this.clearEditor();
this.renderRowEditor();
}
// Изменились параметры отображения
if (!this.checkViewPort()) {
// Формируем только те ячейки, которые добавлены к уже отрендеренным
this.renderByViewPort();
}
this.setSelection();
this.setDisabledFields();
}
ngAfterContentInit() {
this.setParams(true);
}
ngOnDestroy() {
this.clear();
}
};
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], RowDirective.prototype, "row", void 0);
tslib_1.__decorate([
Input('true-state'),
tslib_1.__metadata("design:type", GridStateService)
], RowDirective.prototype, "state", void 0);
tslib_1.__decorate([
Input('true-i'),
tslib_1.__metadata("design:type", Number)
], RowDirective.prototype, "axI", void 0);
tslib_1.__decorate([
Input('true-layout'),
tslib_1.__metadata("design:type", GridLayout)
], RowDirective.prototype, "layout", void 0);
tslib_1.__decorate([
Input('true-empty'),
tslib_1.__metadata("design:type", Object)
], RowDirective.prototype, "empty", void 0);
tslib_1.__decorate([
Input('view-port-left'),
tslib_1.__metadata("design:type", Object)
], RowDirective.prototype, "viewPortLeft", void 0);
tslib_1.__decorate([
Input('view-port-width'),
tslib_1.__metadata("design:type", Object)
], RowDirective.prototype, "viewPortWidth", void 0);
tslib_1.__decorate([
Input('true-locale'),
tslib_1.__metadata("design:type", String)
], RowDirective.prototype, "locale", void 0);
tslib_1.__decorate([
Output('toggleCheckbox'),
tslib_1.__metadata("design:type", Object)
], RowDirective.prototype, "toggleCheckbox", void 0);
RowDirective = tslib_1.__decorate([
Directive({
selector: '[true-row]'
}),
tslib_1.__metadata("design:paramtypes", [Renderer2,
ComponentFactoryResolver,
ApplicationRef,
Injector,
ElementRef])
], RowDirective);
export { RowDirective };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm93LmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0B0cnVlLWRpcmVjdGl2ZS9ncmlkLyIsInNvdXJjZXMiOlsic3JjL3Jvdy5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0VBSUU7QUFDRixPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQWEsWUFBWSxFQUFFLE1BQU0sRUFDbEUsU0FBUyxFQUFFLFFBQVEsRUFFbkIsd0JBQXdCLEVBQUUsY0FBYyxFQUMxQixNQUFNLGVBQWUsQ0FBQztBQUV4QyxPQUFPO0FBQ1AsT0FBTyxFQUFFLFVBQVUsRUFBdUIsTUFBTSxzQkFBc0IsQ0FBQztBQUN2RSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBVSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RFLE9BQU8sRUFBZ0IsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFHckUsVUFBVTtBQUNWLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUUzQyxXQUFXO0FBQ1gsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFeEQsb0JBQW9CO0FBQ3BCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ25GLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRXRFLGtCQUFrQjtBQUNsQixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUU5RDs7R0FFRztBQUlILElBQWEsWUFBWSxHQUF6QixNQUFhLFlBQVk7SUFnb0NyQixZQUNZLFNBQW9CLEVBQ3BC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