添加表格处理功能

This commit is contained in:
wux_labs
2025-02-18 22:50:27 +08:00
parent 95a374fb03
commit 944052753f
12 changed files with 985 additions and 0 deletions
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-add-column-after.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:后面添加列
*/
export class AddColumnAfter extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.addColumnAfter'),
tooltip: t('table.addColumnAfter'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,在后面插入列
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().addColumnAfter().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().addColumnAfter();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-add-column-after.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:前面添加列
*/
export class AddColumnBefore extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.addColumnBefore'),
tooltip: t('table.addColumnBefore'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,在前面插入列
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().addColumnBefore().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().addColumnBefore();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-add-row-after.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:后面添加行
*/
export class AddRowAfter extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.addRowAfter'),
tooltip: t('table.addRowAfter'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,在后面插入行
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().addRowAfter().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().addRowAfter();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-add-row-before.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:前面添加行
*/
export class AddRowBefore extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.addRowBefore'),
tooltip: t('table.addRowBefore'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,在前面插入行
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().addRowBefore().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().addRowBefore();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-delete-column.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:删除列
*/
export class DeleteColumn extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.deleteColumn.text'),
tooltip: t('table.deleteColumn.text'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,删除列
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().deleteColumn().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().deleteColumn();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-delete-row.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:删除行
*/
export class DeleteRow extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.deleteRow.text'),
tooltip: t('table.deleteRow.text'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,删除行
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().deleteRow().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().deleteRow();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table-delete.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions, InnerEditor } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
/**
* 表格菜单:删除表格
*/
export class DeleteTable extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "button",
enable: true,
icon: icon,
hideText: true,
text: t('table.delete.text'),
tooltip: t('table.delete.text'),
}
// 功能按钮
menuButton: MenuButton;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
this.onEditableChange(false);
// 添加鼠标点击事件,删除表格
this.addEventListener("click", () => {
if (this.menuButtonOptions.enable) {
event.editor.chain().focus().deleteTable().run();
}
})
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
if (this.menuButton.menuButton) {
var disable = event.editor.can().deleteTable();
this.onEditableChange(disable);
}
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
}
@@ -0,0 +1,264 @@
// Copyright (c) 2024-present AI-Labs
// @ ts-nocheck
import { MenuButton, MenuButtonOptions } from "../../MenuButton.ts";
import icon from "../../../../assets/icons/table.svg";
import { t } from "i18next";
import { UAIEditorEventListener, UAIEditorOptions } from "../../../../core/UAIEditor.ts";
import { EditorEvents } from "@tiptap/core";
import tippy, { Instance, Props } from "tippy.js";
/**
* 表格菜单:插入表格
*/
export class InsertTable extends HTMLElement implements UAIEditorEventListener {
// 按钮选项
menuButtonOptions: MenuButtonOptions = {
menuType: "popup",
enable: true,
icon: icon,
hideText: true,
text: t('table.insert.text'),
tooltip: t('table.insert.tip'),
}
// 功能按钮
menuButton: MenuButton;
tippyInstance!: Instance<Props>;
// 表格大小设置
selected = { rows: 0, cols: 0 }
// 表格行数
gridRows = 10;
// 表格列数
gridCols = 10;
// 手工输入行数
rowsInput!: HTMLInputElement;
// 手工输入列数
colsInput!: HTMLInputElement;
// 是否包含标题行
withHeaderRow!: HTMLInputElement;
constructor(options: MenuButtonOptions) {
super();
// 初始化功能按钮选项
this.menuButtonOptions = { ...this.menuButtonOptions, ...options };
// 创建功能按钮
this.menuButton = new MenuButton(this.menuButtonOptions);
}
/**
* 定义创建方法
* @param event
* @param options
*/
onCreate(event: EditorEvents["create"], options: UAIEditorOptions) {
this.menuButton.onCreate(event, options);
this.appendChild(this.menuButton);
// 创建表格设置提示框
if (this.menuButtonOptions.enable && this.menuButton.menuButtonArrow) {
this.tippyInstance = tippy(this.menuButton.menuButton, {
content: this.createContainer(event, options),
appendTo: 'parent',
placement: 'bottom',
trigger: 'click',
interactive: true,
arrow: false,
onShow: () => {
this.menuButton.tippyInstance?.disable();
},
onHidden: () => {
this.menuButton.tippyInstance?.enable();
},
});
}
}
/**
* 定义Transaction监听方法
* @param event
* @param options
*/
onTransaction(event: EditorEvents["transaction"], options: UAIEditorOptions) {
this.menuButton.onTransaction(event, options);
}
onEditableChange(editable: boolean) {
this.menuButtonOptions.enable = editable;
this.menuButton.onEditableChange(editable);
}
/**
* 渲染选择的行、列
*/
renderSelected() {
this.rowsInput.value = `${this.selected.rows}`;
this.colsInput.value = `${this.selected.cols}`;
// 为所有选中的行、列设置样式
for (var i = 0; i < this.gridRows; i++) {
for (var j = 0; j < this.gridCols; j++) {
const cell = document.querySelector(`#uai-table-rows-${i}-cells-${j}`)
cell?.classList.remove("selected");
if (this.isSelected(i, j)) {
cell?.classList.add("selected");
}
}
}
}
/**
* 判断指定的行、列是否选中
* @param rows
* @param cols
* @returns
*/
isSelected(rows: number, cols: number) {
return (
this.selected.rows &&
this.selected.rows > rows &&
this.selected.cols &&
this.selected.cols > cols
)
}
/**
* 插入表格
* @param event
* @param options
* @returns
*/
insertTable(event: EditorEvents["create"], options: UAIEditorOptions) {
const { rows, cols } = this.selected;
if (rows === 0 || rows > 1000 || cols === 0 || cols > 30) {
return
}
event.editor.chain().focus().insertTable({ rows, cols, withHeaderRow: this.withHeaderRow.checked }).scrollIntoView().run();
this.tippyInstance.hide();
}
/**
* 创建表格设置容器
* @param event
* @param options
* @returns
*/
createContainer(event: EditorEvents["create"], options: UAIEditorOptions) {
const container = document.createElement("div");
container.classList.add("uai-table-container");
const grid = document.createElement("div");
grid.classList.add("uai-table-grid");
// 设置指定的行、列
for (var i = 0; i < this.gridRows; i++) {
const row = document.createElement("div");
row.classList.add("row");
for (var j = 0; j < this.gridCols; j++) {
// 绘制单元格块
const cell = document.createElement("div");
cell.id = `uai-table-rows-${i}-cells-${j}`;
cell.setAttribute("rows", `${i}`);
cell.setAttribute("cols", `${j}`);
cell.classList.add("cell");
// 设置鼠标事件,设置所选行、列数
cell.addEventListener("mouseover", () => {
this.selected.rows = +cell.getAttribute("rows")! + 1;
this.selected.cols = +cell.getAttribute("cols")! + 1;
})
// 设置鼠标点击事件,插入表格
cell.addEventListener("click", () => {
this.insertTable(event, options);
});
row.appendChild(cell);
}
grid.appendChild(row);
}
// 设置鼠标事件,渲染单元格块
grid.addEventListener("mousemove", () => {
this.renderSelected();
});
// 设置鼠标事件,渲染单元格块
grid.addEventListener("mouseleave", () => {
this.selected.rows = 0;
this.selected.cols = 0;
this.renderSelected();
});
container.appendChild(grid);
// 创建自定义表格行列数设置区
const custom = document.createElement("div");
custom.classList.add("uai-table-custom");
const title = document.createElement("div");
title.classList.add("uai-table-custom-title");
title.innerHTML = t('table.insert.property');
custom.appendChild(title);
// 表格行数输入区
const rowsDiv = document.createElement("div");
rowsDiv.classList.add("uai-table-custom-input");
rowsDiv.innerHTML = t('table.insert.rows');
this.rowsInput = document.createElement("input");
this.rowsInput.type = "number";
this.rowsInput.min = "0";
this.rowsInput.max = "100";
this.rowsInput.placeholder = "请输入";
this.rowsInput.addEventListener("input", () => {
this.selected.rows = +this.rowsInput.value;
this.renderSelected();
});
rowsDiv.appendChild(this.rowsInput);
custom.appendChild(rowsDiv);
// 表格列数输入区
const colsDiv = document.createElement("div");
colsDiv.classList.add("uai-table-custom-input");
colsDiv.innerHTML = t('table.insert.cols');
this.colsInput = document.createElement("input");
this.colsInput.type = "number";
this.colsInput.min = "0";
this.colsInput.max = "100";
this.colsInput.placeholder = "请输入";
this.colsInput.addEventListener("input", () => {
this.selected.cols = +this.colsInput.value;
this.renderSelected();
});
colsDiv.appendChild(this.colsInput);
custom.appendChild(colsDiv);
this.rowsInput.value = `${this.selected.rows}`;
this.colsInput.value = `${this.selected.cols}`;
// 设置插入的表格是否带有标题行
const withHeaderDiv = document.createElement("div");
withHeaderDiv.classList.add("uai-table-custom-header");
this.withHeaderRow = document.createElement("input");
this.withHeaderRow.type = "checkbox";
this.withHeaderRow.id = "withHeaderRow";
this.withHeaderRow.checked = true;
const withHeaderRowLabel = document.createElement('label');
withHeaderRowLabel.htmlFor = 'withHeaderRow';
withHeaderRowLabel.textContent = t('table.insert.withHeader');
withHeaderDiv.appendChild(this.withHeaderRow);
withHeaderDiv.appendChild(withHeaderRowLabel);
custom.appendChild(withHeaderDiv);
// 插入表格按钮
const insertButton = document.createElement("div");
insertButton.classList.add("uai-table-insert-button");
insertButton.innerHTML = t('table.insert.create');
// 添加鼠标点击事件,插入表格
insertButton.addEventListener("click", () => {
this.insertTable(event, options);
});
custom.appendChild(insertButton);
container.appendChild(custom);
return container;
}
}