refactor(views/table): move row editing to own component

This commit is contained in:
Elian Doran 2025-07-15 15:04:41 +03:00
parent 5a7a0d32d1
commit b91a3e13b0
No known key found for this signature in database
2 changed files with 102 additions and 86 deletions

View File

@ -1,10 +1,7 @@
import froca from "../../../services/froca.js";
import ViewMode, { type ViewModeArgs } from "../view_mode.js"; import ViewMode, { type ViewModeArgs } from "../view_mode.js";
import attributes, { setAttribute, setLabel } from "../../../services/attributes.js"; import attributes from "../../../services/attributes.js";
import server from "../../../services/server.js";
import SpacedUpdate from "../../../services/spaced_update.js"; import SpacedUpdate from "../../../services/spaced_update.js";
import type { CommandListenerData, EventData } from "../../../components/app_context.js"; import type { EventData } from "../../../components/app_context.js";
import note_create, { CreateNoteOpts } from "../../../services/note_create.js";
import {Tabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent, ColumnComponent} from 'tabulator-tables'; import {Tabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent, ColumnComponent} from 'tabulator-tables';
import "tabulator-tables/dist/css/tabulator.css"; import "tabulator-tables/dist/css/tabulator.css";
import "../../../../src/stylesheets/table.css"; import "../../../../src/stylesheets/table.css";
@ -14,6 +11,7 @@ import getAttributeDefinitionInformation, { buildRowDefinitions } from "./rows.j
import { AttributeDefinitionInformation, buildColumnDefinitions } from "./columns.js"; import { AttributeDefinitionInformation, buildColumnDefinitions } from "./columns.js";
import { setupContextMenu } from "./context_menu.js"; import { setupContextMenu } from "./context_menu.js";
import TableColumnEditing from "./col_editing.js"; import TableColumnEditing from "./col_editing.js";
import TableRowEditing from "./row_editing.js";
const TPL = /*html*/` const TPL = /*html*/`
<div class="table-view"> <div class="table-view">
@ -171,11 +169,12 @@ export default class TableView extends ViewMode<StateInfo> {
this.colEditing = new TableColumnEditing(this.args.$parent, this.args.parentNote, this.api); this.colEditing = new TableColumnEditing(this.args.$parent, this.args.parentNote, this.api);
this.child(this.colEditing); this.child(this.colEditing);
this.child(new TableRowEditing(this.api, this.args.parentNotePath!));
if (movableRows) { if (movableRows) {
configureReorderingRows(this.api); configureReorderingRows(this.api);
} }
setupContextMenu(this.api, this.parentNote); setupContextMenu(this.api, this.parentNote);
this.setupEditing();
} }
private onSave() { private onSave() {
@ -184,51 +183,6 @@ export default class TableView extends ViewMode<StateInfo> {
}); });
} }
private setupEditing() {
this.api!.on("cellEdited", async (cell) => {
const noteId = cell.getRow().getData().noteId;
const field = cell.getField();
let newValue = cell.getValue();
if (field === "title") {
server.put(`notes/${noteId}/title`, { title: newValue });
return;
}
if (field.includes(".")) {
const [ type, name ] = field.split(".", 2);
if (type === "labels") {
if (typeof newValue === "boolean") {
newValue = newValue ? "true" : "false";
}
setLabel(noteId, name, newValue);
} else if (type === "relations") {
const note = await froca.getNote(noteId);
if (note) {
setAttribute(note, "relation", name, newValue);
}
}
}
});
}
addNewRowCommand({ customOpts, parentNotePath: customNotePath }: CommandListenerData<"addNewRow">) {
const parentNotePath = customNotePath ?? this.args.parentNotePath;
if (parentNotePath) {
const opts: CreateNoteOpts = {
activate: false,
...customOpts
}
note_create.createNote(parentNotePath, opts).then(({ branch }) => {
if (branch) {
setTimeout(() => {
this.focusOnBranch(branch?.branchId);
});
}
})
}
}
async onEntitiesReloaded({ loadResults }: EventData<"entitiesReloaded">) { async onEntitiesReloaded({ loadResults }: EventData<"entitiesReloaded">) {
if (!this.api) { if (!this.api) {
return; return;
@ -285,40 +239,5 @@ export default class TableView extends ViewMode<StateInfo> {
return false; return false;
} }
focusOnBranch(branchId: string) {
if (!this.api) {
return;
}
const row = findRowDataById(this.api.getRows(), branchId);
if (!row) {
return;
}
// Expand the parent tree if any.
if (this.api.options.dataTree) {
const parent = row.getTreeParent();
if (parent) {
parent.treeExpand();
}
}
row.getCell("title").edit();
}
} }
function findRowDataById(rows: RowComponent[], branchId: string): RowComponent | null {
for (let row of rows) {
const item = row.getIndex() as string;
if (item === branchId) {
return row;
}
let found = findRowDataById(row.getTreeChildren(), branchId);
if (found) return found;
}
return null;
}

View File

@ -0,0 +1,97 @@
import { RowComponent, Tabulator } from "tabulator-tables";
import Component from "../../../components/component.js";
import { setAttribute, setLabel } from "../../../services/attributes.js";
import server from "../../../services/server.js";
import froca from "../../../services/froca.js";
import note_create, { CreateNoteOpts } from "../../../services/note_create.js";
import { CommandListenerData } from "../../../components/app_context.js";
export default class TableRowEditing extends Component {
private parentNotePath: string;
private api: Tabulator;
constructor(api: Tabulator, parentNotePath: string) {
super();
this.api = api;
this.parentNotePath = parentNotePath;
api.on("cellEdited", async (cell) => {
const noteId = cell.getRow().getData().noteId;
const field = cell.getField();
let newValue = cell.getValue();
if (field === "title") {
server.put(`notes/${noteId}/title`, { title: newValue });
return;
}
if (field.includes(".")) {
const [ type, name ] = field.split(".", 2);
if (type === "labels") {
if (typeof newValue === "boolean") {
newValue = newValue ? "true" : "false";
}
setLabel(noteId, name, newValue);
} else if (type === "relations") {
const note = await froca.getNote(noteId);
if (note) {
setAttribute(note, "relation", name, newValue);
}
}
}
});
}
addNewRowEvent({ customOpts, parentNotePath: customNotePath }: CommandListenerData<"addNewRow">) {
const parentNotePath = customNotePath ?? this.parentNotePath;
if (parentNotePath) {
const opts: CreateNoteOpts = {
activate: false,
...customOpts
}
note_create.createNote(parentNotePath, opts).then(({ branch }) => {
if (branch) {
setTimeout(() => {
this.focusOnBranch(branch?.branchId);
});
}
})
}
}
focusOnBranch(branchId: string) {
if (!this.api) {
return;
}
const row = findRowDataById(this.api.getRows(), branchId);
if (!row) {
return;
}
// Expand the parent tree if any.
if (this.api.options.dataTree) {
const parent = row.getTreeParent();
if (parent) {
parent.treeExpand();
}
}
row.getCell("title").edit();
}
}
function findRowDataById(rows: RowComponent[], branchId: string): RowComponent | null {
for (let row of rows) {
const item = row.getIndex() as string;
if (item === branchId) {
return row;
}
let found = findRowDataById(row.getTreeChildren(), branchId);
if (found) return found;
}
return null;
}