add cells selection

This commit is contained in:
Sergey Krylov 2022-07-13 21:40:09 +05:00
parent b282490279
commit 2f78b7ec22
4 changed files with 100 additions and 36 deletions

View File

@ -62,7 +62,7 @@ export class Table extends ExcelComponent {
this.initTable(); this.initTable();
this.$onEventFromObserver('formula:input', this.updateCurrentText); this.$onEventFromObserver('formula:input', this.updateCurrentText);
this.$onEventFromObserver('formula:enter-press', () => this.selection.current.focus()); this.$onEventFromObserver('formula:enter-press', () => this.selection.$currentCell.focus());
this.$onEventFromObserver('toolbar:applyStyle', this.updateCurrentStyles); this.$onEventFromObserver('toolbar:applyStyle', this.updateCurrentStyles);
this.$onEventFromObserver('toolbar:add-row', this.addNewRowHandler); this.$onEventFromObserver('toolbar:add-row', this.addNewRowHandler);
} }
@ -126,12 +126,12 @@ export class Table extends ExcelComponent {
} }
emitSelectCallback() { emitSelectCallback() {
this.$emitEventToObserver('table:select-cell', this.selection.current); this.$emitEventToObserver('table:select-cell', this.selection.$currentCell);
const styles = this.selection.current?.getStyles(Object.keys(initialStyleState)); const styles = this.selection.$currentCell?.getStyles(Object.keys(initialStyleState));
this.dispatchToStore(changeCurrentStyles(styles)); this.dispatchToStore(changeCurrentStyles(styles));
this.dispatchToStore(changeCurrentText(this.selection.current.text)); this.dispatchToStore(changeCurrentText(this.selection.$currentCell.text));
} }
async resizeTable(event: MouseEvent) { async resizeTable(event: MouseEvent) {
@ -147,12 +147,12 @@ export class Table extends ExcelComponent {
} }
updateCurrentText = (text: string) => { updateCurrentText = (text: string) => {
this.selection.current.attr('data-value', text); this.selection.$currentCell.attr('data-value', text);
this.selection.current.text = parse(text); this.selection.$currentCell.text = parse(text);
this.dispatchToStore(actions.changeText({ this.dispatchToStore(actions.changeText({
text, text,
id: this.selection.current.data.id || startCellId, id: this.selection.$currentCell.data.id || startCellId,
})); }));
}; };

View File

@ -4,17 +4,21 @@ import { getParamsFromCellId, startCellId } from 'components/table/table.functio
export class TableSelection { export class TableSelection {
static selectedClassName = 'selected'; static selectedClassName = 'selected';
private group: Dom[]; private selectedCellsGroup: Dom[];
public current: Dom; // TODO remove focus, when selection
// $focusedCell and $currentCell can be different, f.e. if select cells with Shift key, currentCell
// will be last cell, focusedCell will start cell, and can be different from selectedCellsGroup first item
public $currentCell: Dom;
public $focusedCell: Dom;
public rootTable: Table; public rootTable: Table;
constructor(rootTable: Table) { constructor(rootTable: Table) {
this.group = []; this.selectedCellsGroup = [];
this.rootTable = rootTable; this.rootTable = rootTable;
} }
get selectedIds() { get selectedIds() {
return this.group.map(el => el.data.id); return this.selectedCellsGroup.map(el => el.data.id);
} }
// TODO make a focus manager // TODO make a focus manager
@ -32,12 +36,14 @@ export class TableSelection {
} }
} }
select($el: Dom) { select($cell: Dom) {
this.clearSelection(); this.clearSelection();
this.group = [$el]; this.selectedCellsGroup = [$cell];
this.current = $el; this.$currentCell = $cell;
$el.addClass(TableSelection.selectedClassName); $cell.addClass(TableSelection.selectedClassName);
this.focusToCell($el); this.focusToCell($cell);
this.selectHeader($cell);
this.$focusedCell = $cell;
} }
selectByCellId(cellID: { col: number, row: number }) { selectByCellId(cellID: { col: number, row: number }) {
@ -46,21 +52,19 @@ export class TableSelection {
if (col <= 0) col = 0; if (col <= 0) col = 0;
if (row <= 0) row = 0; if (row <= 0) row = 0;
this.clearSelection(); this.select($(`[data-id="${row}:${col}"]`));
this.current = $(`[data-id="${row}:${col}"]`);
this.focusToCell(this.current);
this.current.addClass(TableSelection.selectedClassName);
} }
clearSelection() { clearSelection() {
this.group.forEach(el => el?.removeClass(TableSelection.selectedClassName)); this.selectedCellsGroup.forEach(el => el?.removeClass(TableSelection.selectedClassName));
this.current?.removeClass(TableSelection.selectedClassName); this.$currentCell?.removeClass(TableSelection.selectedClassName);
this.group = []; this.clearHeaderSelection();
this.selectedCellsGroup = [];
} }
selectTo($el: Dom) { selectFromTo($from: Dom, $cell: Dom) {
const startCellParams = getParamsFromCellId(this.current.data.id || startCellId); const startCellParams = getParamsFromCellId($from.data.id || startCellId);
const selectedCellParams = getParamsFromCellId($el.data.id || startCellId); const selectedCellParams = getParamsFromCellId($cell.data.id || startCellId);
const startCol = Math.min(startCellParams.col, selectedCellParams.col); const startCol = Math.min(startCellParams.col, selectedCellParams.col);
const endCol = Math.max(startCellParams.col, selectedCellParams.col); const endCol = Math.max(startCellParams.col, selectedCellParams.col);
@ -71,8 +75,8 @@ export class TableSelection {
for (let row = startRow; row <= endRow; row++) { for (let row = startRow; row <= endRow; row++) {
for (let col = startCol; col <= endCol; col++) { for (let col = startCol; col <= endCol; col++) {
const $cell = $(`[data-id="${row}:${col}"]`); const $target = $(`[data-id="${row}:${col}"]`);
this.addCellToSelection($cell); this.addCellToSelection($target);
} }
} }
} }
@ -83,11 +87,56 @@ export class TableSelection {
} }
addCellToSelection($cell: Dom) { addCellToSelection($cell: Dom) {
this.group.push($cell); this.selectedCellsGroup.push($cell);
$cell.addClass(TableSelection.selectedClassName); $cell.addClass(TableSelection.selectedClassName);
this.selectHeader($cell);
}
addGroupToSelectionById(cellID: { col: number, row: number }) {
if (this.selectedCellsGroup.length === 1) {
this.$focusedCell = this.selectedCellsGroup[0];
}
const { col, row } = cellID;
const $cell = $(`[data-id="${row}:${col}"]`);
const $lastCell = this.selectedCellsGroup[this.selectedCellsGroup.length - 1];
if (!$lastCell.isExist) {
this.select($lastCell);
return;
}
this.selectFromTo(this.$focusedCell, $cell);
this.$currentCell = $cell;
} }
applyStyle(style: CSSStyleDeclaration) { applyStyle(style: CSSStyleDeclaration) {
this.group.forEach(el => el.css(style)); this.selectedCellsGroup.forEach(el => el.css(style));
}
selectHeader($cell: Dom) {
if (!$cell) return;
const { headerCol, headerRow } = this.findHeadOfCell($cell);
headerRow.addClass(TableSelection.selectedClassName);
headerCol.addClass(TableSelection.selectedClassName);
}
clearHeaderSelection() {
this.rootTable.$root.findAll('[data-header]').forEach(header => {
header.classList.remove(TableSelection.selectedClassName);
});
}
findHeadOfCell($cell: Dom): { headerRow: Dom, headerCol: Dom } {
const headerRow = $cell.closest('[data-row]').find("[data-header='row']");
const headerCol = this.rootTable.$root.find(`[data-col="${$cell.data.id?.split(':')[1]}"]`);
return { headerRow, headerCol };
}
isCellInSelection($cell: Dom) {
return this.selectedCellsGroup.includes($cell);
} }
} }

View File

@ -29,7 +29,7 @@ export function selectHandler(event: MouseEvent | KeyboardEvent, selection: Tabl
const target = $(event.target); const target = $(event.target);
if (isCell(event)) { if (isCell(event)) {
if (event.shiftKey) selection.selectTo(target); if (event.shiftKey) selection.selectFromTo(selection.$currentCell, target);
else if (event.ctrlKey) selection.addCellToSelection(target); else if (event.ctrlKey) selection.addCellToSelection(target);
else selection.select(target); else selection.select(target);
} else { } else {
@ -63,10 +63,10 @@ export function selectHandler(event: MouseEvent | KeyboardEvent, selection: Tabl
'Tab', 'Tab',
]; ];
if (!selection?.current || !handleKeys.includes(key)) return; if (!selection?.$currentCell || !handleKeys.includes(key)) return;
// If something goes wrong, go to start line // If something goes wrong, go to start line
const currentCellId = selection.current.data.id || startCellId; const currentCellId = selection.$currentCell.data.id || startCellId;
let { row, col } = getParamsFromCellId(currentCellId); let { row, col } = getParamsFromCellId(currentCellId);
switch (key) { switch (key) {
@ -104,13 +104,14 @@ export function selectHandler(event: MouseEvent | KeyboardEvent, selection: Tabl
default: break; default: break;
} }
selection.selectByCellId({ row, col }); if (event.shiftKey) selection.addGroupToSelectionById({ row, col });
else selection.selectByCellId({ row, col });
} }
function onMouseOverHandler() { function onMouseOverHandler() {
if (selection.current.$el) { if (selection.$currentCell.$el) {
// TODO find event type // TODO find event type
selection.selectTo($((event as any).toElement)); selection.selectFromTo(selection.$currentCell, $((event as any).toElement));
} }
} }
} }

View File

@ -93,8 +93,22 @@
} }
[data-header="row"] { [data-header="row"] {
cursor: e-resize; cursor: e-resize;
&.selected {
border-right: 2px solid #3c74ff;
} }
}
[data-header="col"] { [data-header="col"] {
cursor: n-resize; cursor: n-resize;
&.selected {
border-bottom: 2px solid #3c74ff;
}
}
[data-header="col"].selected, [data-header="row"].selected {
font-weight: bold;
background: rgba(60, 116, 255, 0.4);
} }
} }