add cells selection
This commit is contained in:
parent
b282490279
commit
2f78b7ec22
@ -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,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user