quill-table-up 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +16 -3
  3. package/dist/index.d.ts +45 -37
  4. package/dist/index.js +11 -11
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.umd.js +9 -9
  7. package/dist/index.umd.js.map +1 -1
  8. package/package.json +19 -18
  9. package/src/__tests__/e2e/table-blots.test.ts +5 -2
  10. package/src/__tests__/e2e/table-keyboard-handler.test.ts +32 -24
  11. package/src/__tests__/e2e/table-menu.test.ts +38 -0
  12. package/src/__tests__/e2e/table-resize.test.ts +111 -60
  13. package/src/__tests__/e2e/table-scrollbar.test.ts +2 -2
  14. package/src/__tests__/e2e/table-selection.test.ts +48 -0
  15. package/src/__tests__/unit/table-contenteditable.test.ts +222 -0
  16. package/src/__tests__/unit/utils.ts +1 -2
  17. package/src/formats/container-format.ts +2 -2
  18. package/src/formats/table-body-format.ts +1 -1
  19. package/src/formats/table-caption-format.ts +1 -1
  20. package/src/formats/table-cell-format.ts +2 -2
  21. package/src/formats/table-cell-inner-format.ts +1 -1
  22. package/src/formats/table-row-format.ts +1 -1
  23. package/src/modules/table-align.ts +1 -0
  24. package/src/modules/table-clipboard/paste-cell-into-cell.ts +2 -2
  25. package/src/modules/table-dom-selector.ts +18 -3
  26. package/src/modules/table-menu/table-menu-common.ts +1 -0
  27. package/src/modules/table-menu/table-menu-contextmenu.ts +2 -3
  28. package/src/modules/table-menu/table-menu-select.ts +4 -2
  29. package/src/modules/table-resize/table-resize-box.ts +1 -0
  30. package/src/modules/table-resize/table-resize-line.ts +14 -1
  31. package/src/modules/table-resize/table-resize-scale.ts +34 -53
  32. package/src/modules/table-scrollbar.ts +26 -31
  33. package/src/modules/table-selection.ts +5 -3
  34. package/src/style/table-selection.less +0 -5
  35. package/src/table-up.ts +44 -2
  36. package/src/utils/types.ts +1 -0
  37. package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -0,0 +1,222 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { TableDomSelector, TableSelection } from '../../modules';
3
+ import { TableUp } from '../../table-up';
4
+ import { createQuillWithTableModule } from './utils';
5
+
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
9
+ afterEach(() => {
10
+ vi.useRealTimers();
11
+ });
12
+
13
+ describe('TableUp - contenteditable change', () => {
14
+ describe('when contenteditable becomes false', () => {
15
+ it('should destroy all table modules', async () => {
16
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
17
+ modules: [{ module: TableSelection }],
18
+ });
19
+
20
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
21
+ const module = tableUp.getModule<TableSelection>(TableSelection.moduleName);
22
+
23
+ expect(module).toBeDefined();
24
+
25
+ // Disable editor
26
+ quill.enable(false);
27
+
28
+ // Wait for MutationObserver callback
29
+ await vi.runAllTimersAsync();
30
+
31
+ // Verify modules are cleared
32
+ expect(tableUp.modules).not.toBeNullable();
33
+ expect(Object.keys(tableUp.modules).length).toEqual(0);
34
+ });
35
+
36
+ it('should handle modules without destroy method gracefully', async () => {
37
+ // Create a module without destroy method
38
+ class MockModuleWithoutDestroy extends TableDomSelector {
39
+ static moduleName = 'mock-module-without-destroy';
40
+ }
41
+
42
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
43
+ modules: [{ module: MockModuleWithoutDestroy }],
44
+ });
45
+
46
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
47
+
48
+ // Should not throw error
49
+ await expect(() => quill.enable(false)).not.toThrow();
50
+
51
+ // Modules should be cleared
52
+ expect(tableUp.modules).not.toBeNullable();
53
+ expect(Object.keys(tableUp.modules).length).toEqual(0);
54
+ });
55
+ });
56
+
57
+ describe('when contenteditable becomes true', () => {
58
+ it('should create new module instances', async () => {
59
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
60
+ modules: [{ module: TableSelection }],
61
+ });
62
+
63
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
64
+ const oldModule = tableUp.getModule<TableSelection>(TableSelection.moduleName);
65
+
66
+ expect(oldModule).toBeDefined();
67
+
68
+ // Disable editor
69
+ quill.enable(false);
70
+ await vi.runAllTimersAsync();
71
+
72
+ // Re-enable editor
73
+ quill.enable(true);
74
+ await vi.runAllTimersAsync();
75
+
76
+ // Get new module instance
77
+ const newModule = tableUp.getModule<TableSelection>(TableSelection.moduleName);
78
+
79
+ // Verify new instance is created
80
+ expect(newModule).toBeDefined();
81
+ expect(newModule).not.toBe(oldModule);
82
+ });
83
+
84
+ it('should work with multiple enable/disable cycles', async () => {
85
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
86
+ modules: [{ module: TableSelection }],
87
+ });
88
+
89
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
90
+
91
+ // Multiple toggle cycles
92
+ quill.enable(false);
93
+ await vi.runAllTimersAsync();
94
+
95
+ quill.enable(true);
96
+ await vi.runAllTimersAsync();
97
+
98
+ quill.enable(false);
99
+ await vi.runAllTimersAsync();
100
+
101
+ quill.enable(true);
102
+ await vi.runAllTimersAsync();
103
+
104
+ // Verify modules still work
105
+ const module = tableUp.getModule<TableSelection>(TableSelection.moduleName);
106
+ expect(module).toBeDefined();
107
+ expect(module).toBeInstanceOf(TableSelection);
108
+ });
109
+ });
110
+
111
+ describe('error handling', () => {
112
+ it('should continue working if module destroy throws error', async () => {
113
+ // Create a module that throws error on destroy
114
+ class BadModule extends TableDomSelector {
115
+ static moduleName = 'bad-module';
116
+
117
+ destroy() {
118
+ throw new Error('Destroy failed');
119
+ }
120
+ }
121
+
122
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
123
+
124
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
125
+ modules: [{ module: BadModule }],
126
+ });
127
+
128
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
129
+
130
+ // Should not throw error
131
+ await expect(() => quill.enable(false)).not.toThrow();
132
+
133
+ // Should output warning
134
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
135
+ expect.stringContaining('Failed to destroy module'),
136
+ expect.any(Error),
137
+ );
138
+
139
+ consoleWarnSpy.mockRestore();
140
+
141
+ // Modules should be cleared
142
+ expect(tableUp.modules).toEqual({});
143
+ });
144
+
145
+ it('should handle partial destroy failures', async () => {
146
+ class BadModule extends TableDomSelector {
147
+ static moduleName = 'bad-module';
148
+
149
+ destroy() {
150
+ throw new Error('Bad module destroy failed');
151
+ }
152
+ }
153
+
154
+ class GoodModule extends TableDomSelector {
155
+ static moduleName = 'good-module';
156
+
157
+ destroy() {
158
+ // Normal destroy
159
+ }
160
+ }
161
+
162
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
163
+
164
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
165
+ modules: [
166
+ { module: BadModule },
167
+ { module: GoodModule },
168
+ ],
169
+ });
170
+
171
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
172
+
173
+ quill.enable(false);
174
+ await vi.runAllTimersAsync();
175
+
176
+ // Should have warning
177
+ expect(consoleWarnSpy).toHaveBeenCalled();
178
+
179
+ consoleWarnSpy.mockRestore();
180
+
181
+ // All modules should be cleared
182
+ expect(tableUp.modules).toEqual({});
183
+ });
184
+ });
185
+
186
+ describe('MutationObserver behavior', () => {
187
+ it('should only respond to contenteditable attribute changes', async () => {
188
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
189
+ modules: [{ module: TableSelection }],
190
+ });
191
+
192
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
193
+ const initialModuleCount = Object.keys(tableUp.modules).length;
194
+
195
+ // Change other attributes, should not trigger destroy
196
+ quill.root.setAttribute('data-test', 'value');
197
+ await vi.runAllTimersAsync();
198
+
199
+ expect(Object.keys(tableUp.modules).length).toBe(initialModuleCount);
200
+
201
+ // Change contenteditable should trigger
202
+ quill.enable(false);
203
+ await vi.runAllTimersAsync();
204
+
205
+ expect(tableUp.modules).toEqual({});
206
+ });
207
+
208
+ it('should handle direct contenteditable attribute changes', async () => {
209
+ const quill = createQuillWithTableModule(`<p><br></p>`, {
210
+ modules: [{ module: TableSelection }],
211
+ });
212
+
213
+ const tableUp = quill.getModule(TableUp.moduleName) as TableUp;
214
+
215
+ // Directly set contenteditable attribute (instead of using enable method)
216
+ quill.root.setAttribute('contenteditable', 'false');
217
+ await vi.runAllTimersAsync();
218
+
219
+ expect(Object.keys(tableUp.modules).length).toEqual(0);
220
+ });
221
+ });
222
+ });
@@ -187,8 +187,7 @@ export function createTableDeltaOps(row: number, col: number, colOptions?: ColOp
187
187
  );
188
188
  }
189
189
  for (const [i, _] of new Array(col).fill(0).entries()) {
190
- const value: TableColDeltaValue = { tableId, colId: `${i + 1}`, width: 1 / col * 100 };
191
- value.full = full;
190
+ const value: TableColDeltaValue = { tableId, colId: `${i + 1}`, width: 1 / col * 100, full };
192
191
  if (!full) {
193
192
  value.width = width;
194
193
  }
@@ -15,8 +15,8 @@ export class ContainerFormat extends Container {
15
15
  static requiredContainer: TypeParchment.BlotConstructor;
16
16
  static defaultChild?: TypeParchment.BlotConstructor;
17
17
 
18
- static allowAttrs = new Set<string>([]);
19
- static allowDataAttrs = new Set<string>([]);
18
+ static allowAttrs = new Set<string>();
19
+ static allowDataAttrs = new Set<string>();
20
20
  // handle the attribute change when use `setFormatValue`
21
21
  static allowDataAttrsChangeHandler: Record<string, string> = {};
22
22
 
@@ -40,7 +40,7 @@ export class TableBodyFormat extends ContainerFormat {
40
40
  convertBody(tag: TableBodyTag) {
41
41
  const blots = this.descendants(TableCellInnerFormat);
42
42
  for (const blot of blots) {
43
- (blot as any).wrapTag = tag;
43
+ blot.wrapTag = tag;
44
44
  }
45
45
  }
46
46
 
@@ -31,7 +31,7 @@ export class TableCaptionFormat extends BlockOverride {
31
31
  static formats(domNode: HTMLElement) {
32
32
  const { tableId } = domNode.dataset;
33
33
  const value: TableCaptionValue = {
34
- tableId: String(tableId),
34
+ tableId: tableId!,
35
35
  side: domNode.style.captionSide === 'bottom' ? 'bottom' : 'top',
36
36
  };
37
37
  return value;
@@ -87,7 +87,7 @@ export class TableCellFormat extends ContainerFormat {
87
87
 
88
88
  isChildHeadTableCellInner() {
89
89
  const headChild = this.children.head;
90
- return headChild && headChild.statics.blotName === blotName.tableCellInner;
90
+ return headChild?.statics.blotName === blotName.tableCellInner;
91
91
  }
92
92
 
93
93
  setFormatValue(name: string, value?: any) {
@@ -122,7 +122,7 @@ export class TableCellFormat extends ContainerFormat {
122
122
  (headChild.domNode as HTMLElement).dataset.style = this.domNode.style.cssText;
123
123
  }
124
124
 
125
- if (this.parent && this.parent.statics.blotName === blotName.tableRow) {
125
+ if (this.parent?.statics.blotName === blotName.tableRow) {
126
126
  (this.parent as TableRowFormat).setFormatValue(name, value);
127
127
  }
128
128
  }
@@ -105,7 +105,7 @@ export class TableCellInnerFormat extends ContainerFormat {
105
105
  else {
106
106
  super.setFormatValue(name, value);
107
107
  }
108
- if (this.parent && this.parent.statics.blotName === blotName.tableCell) {
108
+ if (this.parent?.statics.blotName === blotName.tableCell) {
109
109
  this.parent.setFormatValue(name, value);
110
110
  }
111
111
 
@@ -64,7 +64,7 @@ export class TableRowFormat extends ContainerFormat {
64
64
  }
65
65
  }
66
66
  // Not found in current row. Means cell is rowspan. Find in prev or next row.
67
- if (this[direction] && this[direction]!.statics.blotName === blotName.tableRow) {
67
+ if (this[direction]?.statics.blotName === blotName.tableRow) {
68
68
  return (this[direction] as TableRowFormat).getCellByColId(colId, direction);
69
69
  }
70
70
  return null;
@@ -117,6 +117,7 @@ export class TableAlign extends TableDomSelector {
117
117
  }
118
118
 
119
119
  destroy() {
120
+ super.destroy();
120
121
  this.hide();
121
122
  if (this.resizeObserver) {
122
123
  this.resizeObserver.disconnect();
@@ -17,8 +17,8 @@ interface CellUpdate {
17
17
  length: number;
18
18
  insertDelta: TypeDelta;
19
19
  cell: TableCellInnerFormat;
20
- rowspan?: number;
21
- colspan?: number;
20
+ rowspan: number;
21
+ colspan: number;
22
22
  emptyRow?: string[];
23
23
  }
24
24
  interface TableCellValueLike {
@@ -1,17 +1,26 @@
1
1
  import type Quill from 'quill';
2
2
  import type { TableUp } from '../table-up';
3
3
 
4
- export class TableDomSelector {
4
+ export interface TableModuleLifecycle {
5
+ hide: () => void;
6
+ show: () => void;
7
+ update: () => void;
8
+ destroy: () => void;
9
+ }
10
+
11
+ export class TableDomSelector implements TableModuleLifecycle {
5
12
  table?: HTMLTableElement;
13
+ tableSelectMouseDownHandler: (event: MouseEvent) => void;
6
14
 
7
15
  constructor(public tableModule: TableUp, public quill: Quill) {
8
- this.quill.root.addEventListener('mousedown', this.tableSelectHandler.bind(this));
16
+ this.tableSelectMouseDownHandler = this.tableSelectHandler.bind(this);
17
+ this.quill.root.addEventListener('mousedown', this.tableSelectMouseDownHandler);
9
18
  }
10
19
 
11
20
  tableSelectHandler(event: MouseEvent) {
12
21
  const path = event.composedPath() as HTMLElement[];
13
22
  if (event.button !== 0 || !path || path.length <= 0) return;
14
- const tableNode = path.find(node => node.tagName && node.tagName.toUpperCase() === 'TABLE');
23
+ const tableNode = path.find(node => node.tagName?.toUpperCase() === 'TABLE');
15
24
  this.setSelectionTable(tableNode as HTMLTableElement);
16
25
  }
17
26
 
@@ -30,4 +39,10 @@ export class TableDomSelector {
30
39
  show() {}
31
40
 
32
41
  update() {}
42
+
43
+ destroy() {
44
+ this.quill.root.removeEventListener('mousedown', this.tableSelectMouseDownHandler);
45
+ this.hide();
46
+ this.table = undefined;
47
+ }
33
48
  }
@@ -318,6 +318,7 @@ export class TableMenuCommon extends TableDomSelector {
318
318
  }
319
319
 
320
320
  destroy() {
321
+ super.destroy();
321
322
  this.quill.off(Quill.events.TEXT_CHANGE, this.updateWhenTextChange);
322
323
  this.quill.off(tableUpEvent.TABLE_SELECTION_DRAG_START, this.hideWhenSelectionDragStart);
323
324
  this.activeTooltip = null;
@@ -27,15 +27,14 @@ export class TableMenuContextmenu extends TableMenuCommon {
27
27
  };
28
28
 
29
29
  listenContextmenu = (e: MouseEvent) => {
30
- e.preventDefault();
31
-
32
30
  const path = e.composedPath() as HTMLElement[];
33
31
  if (!path || path.length <= 0) return;
34
32
 
35
- const tableNode = path.find(node => node.tagName && node.tagName.toUpperCase() === 'TABLE' && node.classList.contains('ql-table'));
33
+ const tableNode = path.find(node => node.tagName?.toUpperCase() === 'TABLE' && node.classList.contains('ql-table'));
36
34
 
37
35
  const tableSelection = this.tableModule.getModule<TableSelection>(tableUpInternal.tableSelectionName);
38
36
  if (tableNode && tableSelection?.selectedTds?.length) {
37
+ e.preventDefault();
39
38
  if (!this.menu) {
40
39
  this.menu = this.buildTools();
41
40
  }
@@ -44,7 +44,7 @@ export class TableMenuSelect extends TableMenuCommon {
44
44
 
45
45
  buildTools(): HTMLElement {
46
46
  const menu = super.buildTools();
47
- this.tableModule.addContainer(menu);
47
+ this.quill.container.appendChild(menu);
48
48
  return menu;
49
49
  }
50
50
 
@@ -87,10 +87,12 @@ export class TableMenuSelect extends TableMenuCommon {
87
87
  }
88
88
  }
89
89
 
90
- destroy(): void {
90
+ destroy() {
91
91
  super.destroy();
92
92
 
93
93
  this.quill.off(tableUpEvent.TABLE_SELECTION_DRAG_START, this.tableSelectionDragStart);
94
94
  this.quill.off(tableUpEvent.TABLE_SELECTION_DRAG_END, this.tableSelectionDragEnd);
95
+ this.quill.off(tableUpEvent.TABLE_SELECTION_CHANGE, this.tableSelectioChange);
96
+ this.quill.off(tableUpEvent.TABLE_SELECTION_DISPLAY_CHANGE, this.tableSelectionDisplayChange);
95
97
  }
96
98
  }
@@ -703,6 +703,7 @@ export class TableResizeBox extends TableResizeCommon {
703
703
  }
704
704
 
705
705
  destroy() {
706
+ super.destroy();
706
707
  this.hide();
707
708
  clearScrollEvent.call(this);
708
709
  this.quill.off(Quill.events.EDITOR_CHANGE, this.updateWhenTextChange);
@@ -137,6 +137,12 @@ export class TableResizeLine extends TableResizeCommon {
137
137
  },
138
138
  onEnd: ({ position }) => {
139
139
  this.dragging = false;
140
+ // update the resizer position to the final position
141
+ if (this.colResizer) {
142
+ const resultX = this.dragXCommon.limitRange(this.tableBlot, position.x, true);
143
+ const rootRect = this.quill.root.getBoundingClientRect();
144
+ this.colResizer.style.left = `${resultX - rootRect.x}px`;
145
+ }
140
146
 
141
147
  this.updateTableCol(position.x);
142
148
  this.removeBreak();
@@ -198,6 +204,12 @@ export class TableResizeLine extends TableResizeCommon {
198
204
  },
199
205
  onEnd: ({ position }) => {
200
206
  this.dragging = false;
207
+ // update the resizer position to the final position
208
+ if (this.rowResizer) {
209
+ const resultY = this.dragYCommon.limitRange(this.tableBlot, position.y, true);
210
+ const rootRect = this.quill.root.getBoundingClientRect();
211
+ this.rowResizer.style.left = `${resultY - rootRect.y}px`;
212
+ }
201
213
 
202
214
  this.updateTableRow(position.y);
203
215
  this.removeBreak();
@@ -230,7 +242,8 @@ export class TableResizeLine extends TableResizeCommon {
230
242
  this.table.removeEventListener('pointermove', this.pointermoveHandler);
231
243
  }
232
244
 
233
- destroy(): void {
245
+ destroy() {
246
+ super.destroy();
234
247
  if (this.colResizer) {
235
248
  this.colResizer.remove();
236
249
  this.colResizer = undefined;
@@ -3,7 +3,7 @@ import type { TableUp } from '../../table-up';
3
3
  import type { TableResizeScaleOptions } from '../../utils';
4
4
  import Quill from 'quill';
5
5
  import { getTableMainRect } from '../../formats';
6
- import { addScrollEvent, clearScrollEvent, createBEM, tableUpSize } from '../../utils';
6
+ import { addScrollEvent, clearScrollEvent, createBEM, dragElement, tableUpSize } from '../../utils';
7
7
  import { TableDomSelector } from '../table-dom-selector';
8
8
  import { isTableAlignRight } from './utils';
9
9
 
@@ -14,9 +14,6 @@ export class TableResizeScale extends TableDomSelector {
14
14
  tableMainBlot?: TableMainFormat;
15
15
  tableWrapperBlot?: TableWrapperFormat;
16
16
  bem = createBEM('scale');
17
- startX: number = 0;
18
- startY: number = 0;
19
- offset: number = 6;
20
17
  options: TableResizeScaleOptions;
21
18
  root?: HTMLElement;
22
19
  block?: HTMLElement;
@@ -42,6 +39,7 @@ export class TableResizeScale extends TableDomSelector {
42
39
  resolveOptions(options: Partial<TableResizeScaleOptions>) {
43
40
  return Object.assign({
44
41
  blockSize: 12,
42
+ offset: 6,
45
43
  }, options);
46
44
  }
47
45
 
@@ -58,57 +56,38 @@ export class TableResizeScale extends TableDomSelector {
58
56
 
59
57
  let originColWidth: { blot: TableColFormat; width: number }[] = [];
60
58
  let originRowHeight: { blot: TableRowFormat; height: number }[] = [];
61
- const handleMouseMove = (e: MouseEvent) => {
62
- if (!this.tableMainBlot) return;
63
- // divide equally by col count/row count
64
- const isRight = isTableAlignRight(this.tableMainBlot) ? -1 : 1;
65
- const diffX = (e.clientX - this.startX) * isRight;
66
- const diffY = e.clientY - this.startY;
67
- const itemWidth = Math.floor(diffX / originColWidth.length);
68
- const itemHeight = Math.floor(diffY / originRowHeight.length);
69
59
 
70
- for (const { blot, width } of originColWidth) {
71
- blot.width = Math.max(width + itemWidth, tableUpSize.colMinWidthPx);
72
- }
73
- for (const { blot, height } of originRowHeight) {
74
- blot.setHeight(`${Math.max(height + itemHeight, tableUpSize.rowMinHeightPx)}px`);
75
- }
76
- };
77
- const handleMouseUp = () => {
78
- originColWidth = [];
79
- originRowHeight = [];
80
- document.removeEventListener('mousemove', handleMouseMove);
81
- document.removeEventListener('mouseup', handleMouseUp);
82
- };
83
- this.block.addEventListener('mousedown', (e) => {
84
- if (!this.tableMainBlot || this.isTableOutofEditor()) return;
85
- this.startX = e.clientX;
86
- this.startY = e.clientY;
87
- // save the origin width and height to calculate result width and height
88
- originColWidth = this.tableMainBlot.getCols().map(col => ({ blot: col, width: Math.floor(col.width) }));
89
- originRowHeight = this.tableMainBlot.getRows().map(row => ({ blot: row, height: Math.floor(row.domNode.getBoundingClientRect().height) }));
90
- document.addEventListener('mousemove', handleMouseMove);
91
- document.addEventListener('mouseup', handleMouseUp);
60
+ dragElement(this.block, {
61
+ onStart: () => {
62
+ if (!this.tableMainBlot) return;
63
+ // save the origin width and height to calculate result width and height
64
+ originColWidth = this.tableMainBlot.getCols().map(col => ({ blot: col, width: Math.floor(col.width) }));
65
+ originRowHeight = this.tableMainBlot.getRows().map(row => ({ blot: row, height: Math.floor(row.domNode.getBoundingClientRect().height) }));
66
+ },
67
+ onMove: ({ movePosition }) => {
68
+ if (!this.tableMainBlot) return;
69
+ // divide equally by col count/row count
70
+ const isRight = isTableAlignRight(this.tableMainBlot) ? -1 : 1;
71
+ const diffX = movePosition.x * isRight;
72
+ const diffY = movePosition.y;
73
+ const itemWidth = Math.floor(diffX / originColWidth.length);
74
+ const itemHeight = Math.floor(diffY / originRowHeight.length);
75
+
76
+ for (const { blot, width } of originColWidth) {
77
+ blot.width = Math.max(width + itemWidth, tableUpSize.colMinWidthPx);
78
+ }
79
+ for (const { blot, height } of originRowHeight) {
80
+ blot.setHeight(`${Math.max(height + itemHeight, tableUpSize.rowMinHeightPx)}px`);
81
+ }
82
+ },
83
+ onEnd: () => {
84
+ originColWidth = [];
85
+ originRowHeight = [];
86
+ },
92
87
  });
93
88
  this.block.addEventListener('dragstart', e => e.preventDefault());
94
89
  }
95
90
 
96
- isTableOutofEditor(): boolean {
97
- if (!this.tableMainBlot || !this.tableWrapperBlot || this.tableMainBlot.full) return false;
98
- // if tableMain width larger than tableWrapper. reset tableMain width equal editor width
99
- const tableRect = this.tableMainBlot.domNode.getBoundingClientRect();
100
- const tableWrapperRect = this.tableWrapperBlot.domNode.getBoundingClientRect();
101
- // equal scale
102
- if (tableRect.width > tableWrapperRect.width) {
103
- for (const col of this.tableMainBlot.getCols()) {
104
- col.width = Math.floor((col.width / tableRect.width) * tableWrapperRect.width);
105
- }
106
- this.tableMainBlot.colWidthFillTable();
107
- return true;
108
- }
109
- return false;
110
- }
111
-
112
91
  update() {
113
92
  if (!this.block || !this.root || !this.tableMainBlot || !this.tableWrapperBlot) return;
114
93
  if (this.tableMainBlot.full) {
@@ -120,7 +99,7 @@ export class TableResizeScale extends TableDomSelector {
120
99
  const tableWrapperRect = this.tableWrapperBlot.domNode.getBoundingClientRect();
121
100
  const editorRect = this.quill.root.getBoundingClientRect();
122
101
  const { scrollTop, scrollLeft } = this.tableWrapperBlot.domNode;
123
- const blockSize = this.options.blockSize * 2 + this.offset;
102
+ const blockSize = this.options.blockSize * 2 + this.options.offset;
124
103
  const rootWidth = Math.min(tableRect.width, tableWrapperRect.width) + blockSize;
125
104
  const rootHeight = Math.min(tableRect.height, tableWrapperRect.height) + blockSize;
126
105
  Object.assign(this.root.style, {
@@ -151,6 +130,7 @@ export class TableResizeScale extends TableDomSelector {
151
130
 
152
131
  this.resizeobserver.observe(this.tableMainBlot.domNode);
153
132
  addScrollEvent.call(this, this.quill.root, () => this.update());
133
+ addScrollEvent.call(this, this.tableWrapperBlot.domNode, () => this.update());
154
134
  }
155
135
  this.buildResizer();
156
136
  }
@@ -163,12 +143,13 @@ export class TableResizeScale extends TableDomSelector {
163
143
  this.root = undefined;
164
144
  this.block = undefined;
165
145
  }
146
+ clearScrollEvent.call(this);
166
147
  }
167
148
 
168
149
  destroy() {
150
+ super.destroy();
169
151
  this.hide();
170
- this.quill.off(Quill.events.TEXT_CHANGE, this.updateWhenTextChange);
152
+ this.quill.off(Quill.events.EDITOR_CHANGE, this.updateWhenTextChange);
171
153
  this.resizeobserver.disconnect();
172
- clearScrollEvent.call(this);
173
154
  }
174
155
  }