@worktile/theia 15.2.1 → 15.3.1

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 (41) hide show
  1. package/constants/default.d.ts +1 -1
  2. package/esm2020/components/column-resize/column-resize.directive.mjs +5 -1
  3. package/esm2020/constants/default.mjs +2 -2
  4. package/esm2020/interfaces/image.mjs +1 -1
  5. package/esm2020/plugins/image/image.editor.mjs +6 -2
  6. package/esm2020/plugins/link/edit/link-edit.component.mjs +3 -5
  7. package/esm2020/plugins/table/components/table.component.mjs +33 -22
  8. package/esm2020/plugins/table/components/td/td.component.mjs +48 -40
  9. package/esm2020/plugins/table/components/toolbar/table-options.component.mjs +5 -6
  10. package/esm2020/plugins/table/components/toolbar/table-toolbar.component.mjs +3 -3
  11. package/esm2020/plugins/table/table.service.mjs +55 -8
  12. package/esm2020/plugins/table/table.store.mjs +164 -131
  13. package/esm2020/plugins/table/utils/cell-position.mjs +31 -10
  14. package/esm2020/plugins/table/utils/get-min-max-cell-index.mjs +16 -11
  15. package/esm2020/plugins/table/utils/get-select-cell-node.mjs +8 -1
  16. package/esm2020/plugins/table/utils/index.mjs +17 -9
  17. package/esm2020/plugins/table/utils/remove-row-column.mjs +47 -0
  18. package/esm2020/plugins/table/utils/set-node-options.mjs +11 -0
  19. package/esm2020/services/table-contextmenu.service.mjs +10 -3
  20. package/esm2020/utils/dom.mjs +2 -2
  21. package/esm2020/utils/index.mjs +2 -1
  22. package/fesm2015/worktile-theia.mjs +1043 -851
  23. package/fesm2015/worktile-theia.mjs.map +1 -1
  24. package/fesm2020/worktile-theia.mjs +1047 -857
  25. package/fesm2020/worktile-theia.mjs.map +1 -1
  26. package/interfaces/image.d.ts +1 -0
  27. package/package.json +1 -1
  28. package/plugins/link/edit/link-edit.component.d.ts +0 -1
  29. package/plugins/table/components/table.component.d.ts +4 -2
  30. package/plugins/table/components/td/td.component.d.ts +5 -5
  31. package/plugins/table/components/toolbar/table-options.component.d.ts +1 -3
  32. package/plugins/table/table.editor.d.ts +1 -4
  33. package/plugins/table/table.service.d.ts +22 -4
  34. package/plugins/table/table.store.d.ts +35 -16
  35. package/plugins/table/utils/cell-position.d.ts +24 -2
  36. package/plugins/table/utils/get-min-max-cell-index.d.ts +6 -1
  37. package/plugins/table/utils/get-select-cell-node.d.ts +1 -0
  38. package/plugins/table/utils/index.d.ts +16 -8
  39. package/plugins/table/utils/remove-row-column.d.ts +6 -0
  40. package/plugins/table/utils/set-node-options.d.ts +3 -0
  41. package/utils/index.d.ts +1 -0
@@ -8,7 +8,7 @@ import * as i1 from 'slate-angular';
8
8
  import { BaseElementComponent, BaseTextComponent, NODE_TO_PARENT, NODE_TO_INDEX, AngularEditor, hotkeys, IS_SAFARI, ELEMENT_TO_COMPONENT, hasBlockCard, isCardLeft, FAKE_RIGHT_BLOCK_CARD_OFFSET, getPlainText as getPlainText$1, EDITOR_TO_ELEMENT, defaultScrollSelectionIntoView, withAngular, SlateModule } from 'slate-angular';
9
9
  import { Range, Element as Element$1, Editor, Node, Span, Path, Text, Point, Transforms, Operation, createEditor } from 'slate';
10
10
  import { map, cloneDeep, assign, defaults, groupBy, uniq, isEqual } from 'lodash';
11
- import { isObject, isArray, isString } from 'ngx-tethys/util';
11
+ import { isObject, isArray, isString, isUndefined } from 'ngx-tethys/util';
12
12
  import { TheiaConverter } from '@atinc/selene';
13
13
  import { HistoryEditor, withHistory } from 'slate-history';
14
14
  import * as i1$1 from 'ngx-tethys/popover';
@@ -61,8 +61,8 @@ import * as i6$2 from 'ngx-tethys/button';
61
61
  import { ThyButtonModule } from 'ngx-tethys/button';
62
62
  import * as i7$1 from 'ngx-tethys/input-number';
63
63
  import { ThyInputNumberModule } from 'ngx-tethys/input-number';
64
- import { coerceCssPixelValue } from '@angular/cdk/coercion';
65
64
  import { PortalInjector, ComponentPortal } from '@angular/cdk/portal';
65
+ import { coerceCssPixelValue } from '@angular/cdk/coercion';
66
66
  import { ScrollingModule } from '@angular/cdk/scrolling';
67
67
  import { ThyAutocompleteModule } from 'ngx-tethys/autocomplete';
68
68
  import { ThyAvatarModule } from 'ngx-tethys/avatar';
@@ -130,7 +130,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
130
130
  }] } });
131
131
 
132
132
  const PICTURE_ACCEPTED_UPLOAD_MIME = ['image/png', 'image/jpeg', 'image/gif', 'image/bmp'];
133
- const PICTURE_ACCEPTED_UPLOAD_SIZE = 20;
133
+ const PICTURE_ACCEPTED_UPLOAD_SIZE = 30;
134
134
  const A_TAG_REL_ATTR = 'noopener noreferrer nofollow external ugc';
135
135
  const LINK_DEFAULT_TEXT = '链接';
136
136
  const TAB_SPACE = ' ';
@@ -2191,7 +2191,7 @@ function getElementWidth(element) {
2191
2191
  return coercePixelsFromCssValue(element.style.width) || element.getBoundingClientRect().width;
2192
2192
  }
2193
2193
  function getElementHeight(element) {
2194
- return element.getBoundingClientRect().height;
2194
+ return coercePixelsFromCssValue(element.style.height) || element.getBoundingClientRect().height;
2195
2195
  }
2196
2196
  function getColsTotalWidth(cols) {
2197
2197
  return cols.reduce((total, col) => {
@@ -2436,6 +2436,21 @@ function insertDataByInvalidType(editor, fragment) {
2436
2436
  return true;
2437
2437
  }
2438
2438
 
2439
+ const isColorPanel = (element) => {
2440
+ const pickerPanel = element.closest('.thy-color-picker-panel');
2441
+ const customPickerPanel = element.closest('.thy-color-picker-custom-panel');
2442
+ if (pickerPanel || customPickerPanel) {
2443
+ return true;
2444
+ }
2445
+ return false;
2446
+ };
2447
+ const isColorIndicator = (element) => {
2448
+ return element.closest('.indicator-hue-alp');
2449
+ };
2450
+ const isColorInput = (element) => {
2451
+ return element.closest('.thy-color-inputs');
2452
+ };
2453
+
2439
2454
  const toolbarInitialize = (toolbarItems, global = DefaultGlobalToolbarDefinition, inline = DefaultInlineToolbarDefinition) => {
2440
2455
  const toolbarDefinition = {
2441
2456
  global,
@@ -3770,264 +3785,594 @@ function isInside(cellRect, rowIndex, columnIndex) {
3770
3785
  return false;
3771
3786
  }
3772
3787
 
3773
- const setMarks = (editor, marks, at) => {
3774
- Transforms.setNodes(editor, marks, {
3775
- at,
3776
- match: Text.isText,
3777
- split: true
3788
+ function isVirtualKey(e) {
3789
+ const isMod = e.ctrlKey || e.metaKey;
3790
+ const isAlt = isKeyHotkey('alt', e);
3791
+ const isShift = isKeyHotkey('shift', e);
3792
+ const isCapsLock = e.key.includes('CapsLock');
3793
+ const isTab = e.key.includes('Tab');
3794
+ const isEsc = e.key.includes('Escape');
3795
+ const isF = e.key.startsWith('F');
3796
+ const isArrow = e.key.includes('Arrow') ? true : false;
3797
+ return isCapsLock || isMod || isAlt || isArrow || isShift || isTab || isEsc || isF;
3798
+ }
3799
+
3800
+ /**
3801
+ * 获取标题行网格列宽值
3802
+ * @param editor
3803
+ * @param headerRow 标题行
3804
+ * @param cellsWidth
3805
+ * @returns string
3806
+ */
3807
+ const getGridColumns = (headerRow, cellsWidth) => {
3808
+ let result = '';
3809
+ Array.from(headerRow.childNodes)
3810
+ .filter((n) => n.nodeType === 1)
3811
+ .forEach((node, i) => {
3812
+ const col = node.getAttribute('colspan');
3813
+ const display = node.style.display;
3814
+ if (display === 'none') {
3815
+ return;
3816
+ }
3817
+ if (col) {
3818
+ const colSpan = Number(col) ?? 1;
3819
+ let width = 0;
3820
+ Array.from({ length: colSpan }, (_, j) => {
3821
+ width += cellsWidth[i + j];
3822
+ });
3823
+ result += width + 'px ';
3824
+ }
3825
+ else {
3826
+ result += cellsWidth[i] + 'px ';
3827
+ }
3778
3828
  });
3829
+ return result;
3779
3830
  };
3780
-
3781
- const clearMarks = (editor) => {
3782
- const { selection } = editor;
3783
- if (!selection) {
3784
- return;
3785
- }
3786
- if (Range.isCollapsed(selection)) {
3787
- const marks = Editor.marks(editor);
3788
- for (const key in marks) {
3789
- Editor.removeMark(editor, key);
3831
+ const getColumnsWidth = (cellRow, isColgroup = false) => {
3832
+ const result = [];
3833
+ Array.from(cellRow.childNodes)
3834
+ .filter((n) => n.nodeType === 1)
3835
+ .forEach((item) => {
3836
+ if (isColgroup && IS_SAFARI) {
3837
+ result.push(item.offsetWidth);
3838
+ return;
3790
3839
  }
3791
- }
3792
- else {
3793
- const unsetMarks = {};
3794
- MarkProps.forEach(key => {
3795
- unsetMarks[key] = null;
3796
- });
3797
- setMarks(editor, unsetMarks);
3798
- }
3840
+ if (item.getBoundingClientRect) {
3841
+ result.push(item.getBoundingClientRect().width);
3842
+ }
3843
+ });
3844
+ return result;
3799
3845
  };
3800
-
3801
- const insertElements = (editor, elements) => {
3802
- if (!editor.selection) {
3803
- refocus(editor);
3804
- }
3805
- if (Range.isExpanded(editor.selection)) {
3806
- Editor.deleteFragment(editor);
3807
- }
3808
- const type = !isArray(elements) ? elements.type : elements[0].type; // 后期处理复制粘贴需要修改
3809
- const allowParentTypes = getPluginOptions(editor, type)?.allowParentTypes || [];
3810
- const insertNodePath = getInsertElementsPath(editor, allowParentTypes);
3811
- const [anchorBlock, anchorBlockPath] = anchorBlockEntry(editor);
3812
- let isEmpty = Editor.isEmpty(editor, anchorBlock);
3813
- if (insertNodePath) {
3814
- Editor.withoutNormalizing(editor, () => {
3815
- Transforms.insertNodes(editor, elements, { at: insertNodePath });
3816
- Transforms.select(editor, Editor.start(editor, insertNodePath));
3817
- if (isEmpty) {
3818
- Transforms.removeNodes(editor, { at: anchorBlockPath });
3819
- }
3820
- });
3821
- return;
3822
- }
3823
- const nextPath = Path.next([anchorBlockPath[0]]);
3824
- Transforms.insertNodes(editor, elements, { at: nextPath });
3825
- if (isEmpty && anchorBlockPath.length === 1) {
3826
- Transforms.delete(editor, { at: anchorBlockPath });
3827
- Transforms.select(editor, Editor.start(editor, anchorBlockPath));
3846
+ /**
3847
+ * 计算表格列宽
3848
+ * @param isReadonly
3849
+ * @param element
3850
+ * @param tableWidth
3851
+ * @param mode
3852
+ * @returns number[]
3853
+ */
3854
+ const calcColumnGroups = (isReadonly, element, tableWidth, mode) => {
3855
+ const columns = element?.columns;
3856
+ if (isReadonly) {
3857
+ if (columns) {
3858
+ const opts = new TableOptions();
3859
+ const isPrint = mode === TheMode.print;
3860
+ const newColumns = isPrint
3861
+ ? calcPrintColumnWidth(element, opts.minWidthPx)
3862
+ : calcColumnWidth(element, tableWidth, opts.minWidthPx);
3863
+ return newColumns;
3864
+ }
3865
+ return [];
3828
3866
  }
3829
3867
  else {
3830
- Transforms.select(editor, Editor.start(editor, nextPath));
3868
+ return columns;
3831
3869
  }
3832
3870
  };
3833
-
3834
- const setNode = (editor, props, origin) => {
3835
- Transforms.setNodes(editor, props, { at: findPath(editor, origin) });
3871
+ /**
3872
+ * 计算表格列宽
3873
+ * @param element
3874
+ * @param tableWidth
3875
+ * @param minWidthPx
3876
+ * @returns number[]
3877
+ */
3878
+ const calcColumnWidth = (element, tableWidth, minWidthPx) => {
3879
+ const columns = element?.columns;
3880
+ const numberedColumnWidth = element?.options?.numberedColumn ? TABLE_NUMBER_COLUMN : 0;
3881
+ const columnsWidth = columns.reduce((a, b) => a + b.width, 0);
3882
+ // 总列宽大于当前表格宽度时,按照设置时的总列宽计算
3883
+ const columnTotalWidth = Math.max(columnsWidth, tableWidth - numberedColumnWidth);
3884
+ return columns.map(column => {
3885
+ const cellWidth = (column.width / columnsWidth) * columnTotalWidth;
3886
+ return { width: Math.max(cellWidth, minWidthPx) };
3887
+ });
3836
3888
  };
3837
-
3838
3889
  /**
3839
- * Unwrap nodes by type
3890
+ * 打印模式下,按照原宽度比例基于当前表格宽度计算列宽
3891
+ * 1. 所有列的最小列宽总和大于表格宽度时,所有列返回最小宽度
3892
+ * @param element
3893
+ * @param minWidthPx
3894
+ * @returns number[]
3840
3895
  */
3841
- const unwrapNodesByType = (editor, types, options = {}) => {
3842
- if (!Array.isArray(types)) {
3843
- types = [types];
3896
+ const calcPrintColumnWidth = (element, minWidthPx) => {
3897
+ const columns = element?.columns;
3898
+ const numberedColumnWidth = element?.options?.numberedColumn ? TABLE_NUMBER_COLUMN : 0;
3899
+ // 按照 DPI 96 的 A4 纸宽度是 794, 打印时左右 80px 的边距,所以这里取 794 - 80 * 2 = 634
3900
+ // 如果存在序号列,还需要在 634 基础上减去序号列的宽度,剩下的才是内容区域的宽度
3901
+ let columnTotalWidth = 634 - numberedColumnWidth;
3902
+ const columnsWidth = columns.reduce((a, b) => a + b.width, 0);
3903
+ // 计算所有列的 minWidth 总和
3904
+ const totalMinWidth = minWidthPx * columns.length;
3905
+ if (totalMinWidth > columnTotalWidth) {
3906
+ // 如果所有列的 minWidth 总和大于 columnTotalWidth,所有列返回最小宽度
3907
+ return columns.map(() => ({ width: minWidthPx }));
3844
3908
  }
3845
- Transforms.unwrapNodes(editor, {
3846
- match: n => Element$1.isElement(n) && types.includes(n.type),
3847
- ...options
3848
- });
3909
+ // 在剩余的宽度中按比例分配
3910
+ const remainingWidth = columnTotalWidth - totalMinWidth;
3911
+ const remainingWidthRatio = columns.map(column => column.width / columnsWidth);
3912
+ // 为什么减 1, 因为这个宽度是内容区域宽度,但 td 右侧还有一个边框,所以减去 1
3913
+ let newColumnsWidth = remainingWidthRatio.map(ratio => minWidthPx + Math.floor(ratio * remainingWidth) - 1);
3914
+ return columns.map((_, index) => ({
3915
+ width: newColumnsWidth[index]
3916
+ }));
3849
3917
  };
3850
3918
 
3851
- const onKeyDownResetBlockType = ({ rules }) => (event, editor) => {
3852
- let reset;
3853
- if (editor.selection && isCollapsed(editor.selection)) {
3854
- rules.forEach(({ types, defaultType, hotkey, predicate, onReset }) => {
3855
- if (!event || (hotkey && isKeyHotkey(hotkey, event))) {
3856
- if (predicate(editor) && isNodeTypeIn(editor, types)) {
3857
- if (event !== null) {
3858
- event.preventDefault();
3859
- }
3860
- Transforms.setNodes(editor, { type: defaultType });
3861
- onReset(editor);
3862
- reset = true;
3863
- }
3864
- }
3865
- });
3919
+ /* cell-position 有关的函数 */
3920
+ /**
3921
+ * 判断是否选中了所有的单元格
3922
+ * @param editor 编辑器对象
3923
+ * @param selectedCellPositions 选中的单元格位置数组
3924
+ * @returns 是否选中了所有的单元格
3925
+ */
3926
+ const isSelectedAllCell = (editor, selectedCellPositions) => {
3927
+ if (!AngularEditor.isFocused(editor)) {
3928
+ return false;
3866
3929
  }
3867
- return reset;
3930
+ const pos = createTablePosition(editor);
3931
+ return !!selectedCellPositions.length && pos.getHeight() * pos.getWidth() === selectedCellPositions.length;
3868
3932
  };
3869
-
3870
3933
  /**
3871
- * 将节点的子级移动到路径。 返回移动的子级数。
3934
+ * 获取选中的单元格位置数组
3935
+ * @param editor 编辑器对象
3936
+ * @param selectedCells 选中的单元格
3937
+ * @returns 选中的单元格位置
3872
3938
  */
3873
- const moveChildren = (editor, { at, to, match, start = 0 }) => {
3874
- let moved = 0;
3875
- const parentPath = Path.isPath(at) ? at : at[1];
3876
- const parentNode = Path.isPath(at) ? Node.get(editor, parentPath) : at[0];
3877
- if (!Editor.isBlock(editor, parentNode))
3878
- return moved;
3879
- for (let i = parentNode.children.length - 1; i >= start; i--) {
3880
- const childPath = [...parentPath, i];
3881
- const childNode = getNode(editor, childPath);
3882
- if (!match || (childNode && match([childNode, childPath]))) {
3883
- Transforms.moveNodes(editor, { at: childPath, to });
3884
- moved++;
3939
+ const getSelectedCellPositions = (editor, selectedCells) => {
3940
+ return selectedCells?.map((cell) => {
3941
+ const path = AngularEditor.findPath(editor, cell);
3942
+ const [row, col] = path.slice(-2);
3943
+ return { row, col };
3944
+ });
3945
+ };
3946
+ /**
3947
+ * 获取一定范围内所有的单元格位置
3948
+ * @param startRow 起始行
3949
+ * @param startCol 起始列
3950
+ * @param endRow 结束行
3951
+ * @param endCol 结束列
3952
+ * @returns 单元格位置
3953
+ */
3954
+ const getCellPositionsFromRange = (startRow, startCol, endRow, endCol) => {
3955
+ const positions = [];
3956
+ for (let row = startRow; row < endRow; row++) {
3957
+ for (let col = startCol; col < endCol; col++) {
3958
+ positions.push({ row, col });
3885
3959
  }
3886
3960
  }
3887
- return moved;
3888
- };
3889
-
3890
- const insertParagraph = (editor, at) => {
3891
- Transforms.insertNodes(editor, createEmptyParagraph(), { at });
3961
+ return positions;
3892
3962
  };
3893
-
3894
3963
  /**
3895
- * Recursively apply an operation to children nodes with a query.
3964
+ * 过滤重复的单元格位置
3965
+ * @param cells 单元格数组
3966
+ * @param selectedCellPositions 选中的单元格位置数组
3967
+ * @returns 过滤后的单元格位置数组
3896
3968
  */
3897
- const applyDeepToNodes = ({ node, source, apply, query }) => {
3898
- const entry = [node, []];
3899
- if (isNodeType(entry, query)) {
3900
- if (source instanceof Function) {
3901
- apply(node, source());
3969
+ const uniqueCellPosition = (cells, selectedCellPositions) => {
3970
+ const positions = [];
3971
+ const modCells = new Set();
3972
+ cells.concat(selectedCellPositions).forEach(cell => modCells.add(JSON.stringify(cell)));
3973
+ modCells.forEach((cell) => positions.push(JSON.parse(cell)));
3974
+ return positions;
3975
+ };
3976
+
3977
+ /**
3978
+ * 计算最小行跨距单元格
3979
+ * @param element TableElement
3980
+ * @returns
3981
+ */
3982
+ const calculateMinRowSpanCellForRows = (element) => {
3983
+ const cells = element.children.map((row, index) => {
3984
+ const noHiddenCells = row.children.filter(cell => !cell.hidden);
3985
+ if (noHiddenCells.length > 0) {
3986
+ const minRowspan = Math.min.apply(Math, noHiddenCells.map(cell => {
3987
+ return cell.rowspan || 1;
3988
+ }));
3989
+ const cell = row.children.find(item => !item.hidden && (item.rowspan || 1) === minRowspan);
3990
+ return {
3991
+ cell,
3992
+ rowIndex: index
3993
+ };
3902
3994
  }
3903
3995
  else {
3904
- apply(node, source);
3996
+ return {
3997
+ rowIndex: index
3998
+ };
3905
3999
  }
3906
- }
3907
- if (!isAncestor(node)) {
3908
- return;
3909
- }
3910
- node.children.forEach((child) => {
3911
- applyDeepToNodes({ node: child, source, apply, query });
3912
4000
  });
4001
+ return cells;
3913
4002
  };
3914
-
3915
4003
  /**
3916
- * Recursively merge a source object to children nodes with a query.
4004
+ * 计算行控件的平均高度
4005
+ * @param previousCombineRowIndex
4006
+ * @param previousRowIndex
4007
+ * @param rowControls
3917
4008
  */
3918
- const mergeDeepToNodes = (options) => {
3919
- applyDeepToNodes({ ...options, apply: defaults });
3920
- };
3921
-
3922
- const unWrap = (editor, kind) => {
3923
- Editor.withoutNormalizing(editor, () => {
3924
- Transforms.setNodes(editor, { type: ElementKinds.paragraph });
3925
- Transforms.unwrapNodes(editor, {
3926
- match: n => Element$1.isElement(n) && n.type === kind,
3927
- split: true
3928
- });
4009
+ const calculateRowControlsAvgHeight = (previousCombineRowIndex, previousRowIndex, rowControls) => {
4010
+ const rowControl = rowControls[previousRowIndex];
4011
+ const count = previousCombineRowIndex - previousRowIndex;
4012
+ const avgHeight = Math.floor(rowControl.height / (count + 1));
4013
+ const firstHeight = rowControl.height - avgHeight * count;
4014
+ rowControl.height = firstHeight;
4015
+ rowControls
4016
+ .filter((_, index) => index > previousRowIndex && index <= previousCombineRowIndex)
4017
+ .forEach(rowControl => {
4018
+ rowControl.height = avgHeight;
3929
4019
  });
3930
4020
  };
3931
-
3932
- const deleteElement = (editor, element) => {
3933
- const at = findPath(editor, element);
3934
- Transforms.insertNodes(editor, createEmptyParagraph(), { at });
3935
- AngularEditor.focus(editor);
3936
- Transforms.select(editor, at);
3937
- Transforms.removeNodes(editor, { at: Path.next(at) });
4021
+ const getBelowRowHeight = (editor, cells, index, rowIndex, rowspan) => {
4022
+ let belowRowlHeight = 0;
4023
+ cells.slice(index + 1, cells.length).map(item => {
4024
+ if (!item.cell) {
4025
+ return;
4026
+ }
4027
+ if (rowIndex + rowspan > item.rowIndex) {
4028
+ const cellDom = AngularEditor.toDOMNode(editor, item.cell);
4029
+ if (item.cell.rowspan > 1) {
4030
+ // 如果下方单元格的rowspan > 1,递归计算
4031
+ const height = getBelowRowHeight(editor, cells, cells.findIndex(cell => cell.rowIndex === item.rowIndex), item.rowIndex, item.cell.rowspan);
4032
+ belowRowlHeight += getElementHeight(cellDom) - height;
4033
+ }
4034
+ else {
4035
+ belowRowlHeight += getElementHeight(cellDom);
4036
+ }
4037
+ }
4038
+ });
4039
+ return belowRowlHeight;
3938
4040
  };
3939
-
3940
- const setEndSelection = (editor) => {
3941
- const lastNode = getLastNode(editor, 1);
3942
- const end = Editor.end(editor, lastNode[1]);
3943
- Transforms.select(editor, end);
3944
- AngularEditor.focus(editor);
4041
+ const calculateRowControls = (editor, element) => {
4042
+ const minRowSpanCellForRows = calculateMinRowSpanCellForRows(element);
4043
+ const rowControls = [];
4044
+ let previousRowIndex = 0;
4045
+ let previousCombineRowIndex = 0;
4046
+ minRowSpanCellForRows.forEach((cellInfo, index) => {
4047
+ if (!cellInfo.cell) {
4048
+ rowControls.push({
4049
+ height: 0,
4050
+ rowIndex: index
4051
+ });
4052
+ previousCombineRowIndex = index;
4053
+ if (index === minRowSpanCellForRows.length - 1) {
4054
+ calculateRowControlsAvgHeight(previousCombineRowIndex, previousRowIndex, rowControls);
4055
+ }
4056
+ return;
4057
+ }
4058
+ // calculate combine row height
4059
+ if (previousCombineRowIndex > previousRowIndex) {
4060
+ calculateRowControlsAvgHeight(previousCombineRowIndex, previousRowIndex, rowControls);
4061
+ previousCombineRowIndex = 0;
4062
+ }
4063
+ const cellDom = AngularEditor.toDOMNode(editor, cellInfo.cell);
4064
+ let height = getElementHeight(cellDom);
4065
+ // 当cell为合并的单元格(rowspan > 1),计算其实际高度(当前单元格的高度 - 下方合并单元格的高度)
4066
+ if (cellInfo.cell.rowspan > 1) {
4067
+ const calcHeight = height - getBelowRowHeight(editor, minRowSpanCellForRows, index, cellInfo.rowIndex, cellInfo.cell.rowspan);
4068
+ rowControls.push({
4069
+ height: calcHeight,
4070
+ rowIndex: cellInfo.rowIndex
4071
+ });
4072
+ }
4073
+ else {
4074
+ rowControls.push({
4075
+ height,
4076
+ rowIndex: cellInfo.rowIndex
4077
+ });
4078
+ }
4079
+ previousRowIndex = index;
4080
+ });
4081
+ return rowControls;
3945
4082
  };
3946
4083
 
3947
- const closeConversionHint = (editor) => {
3948
- const hintRef = THE_EDITOR_CONVERSION_HINT_REF.get(editor);
3949
- if (hintRef) {
3950
- hintRef.close();
4084
+ /**
4085
+ * compatible with old data
4086
+ * @returns
4087
+ */
4088
+ function isHeaderRow(element) {
4089
+ if (element?.options?.headerRow) {
4090
+ return true;
3951
4091
  }
3952
- };
3953
-
3954
- function handleContinualDeleteBackward(editor, aboveResult, type) {
3955
- const highestBlock = aboveResult[0];
3956
- const lowestBlock = anchorBlock(editor);
3957
- const wrapBlockType = highestBlock.type;
3958
- if (lowestBlock && Editor.isStart(editor, editor.selection.anchor, aboveResult[1])) {
3959
- if (wrapBlockType === type) {
3960
- if (highestBlock.children[0] === lowestBlock) {
3961
- unWrap(editor, wrapBlockType);
3962
- return true;
3963
- }
3964
- }
4092
+ // compat old data
4093
+ if (element?.children[0].header) {
4094
+ return true;
3965
4095
  }
3966
- return false;
3967
4096
  }
3968
4097
 
3969
- function handleContinualInsertBreak(editor, lowestBlock, type) {
3970
- const isEmpty = Editor.isEmpty(editor, lowestBlock);
3971
- const isEnd = Editor.isEnd(editor, editor.selection.anchor, editor.selection.focus.path);
3972
- const aboveResult = Editor.above(editor, {
3973
- match: n => Editor.isBlock(editor, n) && n.type === type
3974
- });
3975
- if (aboveResult && aboveResult[0] && isEnd && isEmpty) {
3976
- const wrapBlock = aboveResult[0];
3977
- if (wrapBlock.type === type) {
3978
- if (wrapBlock.children[wrapBlock.children.length - 1] === lowestBlock) {
3979
- unWrap(editor, wrapBlock.type);
3980
- return true;
3981
- }
4098
+ function getSelectCellNode(editor, selectedCells) {
4099
+ const pos = createTablePosition(editor);
4100
+ return selectedCells
4101
+ .map(item => {
4102
+ const node = pos.findCellByPath(item);
4103
+ if (node) {
4104
+ return {
4105
+ ...item,
4106
+ node: node
4107
+ };
3982
4108
  }
3983
- }
3984
- return false;
4109
+ })
4110
+ .filter(item => item);
4111
+ }
4112
+ function focusCell(editor, path) {
4113
+ const at = Editor.start(editor, path);
4114
+ TheEditor.focus(editor);
4115
+ Transforms.select(editor, at);
3985
4116
  }
3986
4117
 
3987
- var index = /*#__PURE__*/Object.freeze({
3988
- __proto__: null,
3989
- applyDeepToNodes: applyDeepToNodes,
3990
- clearMarks: clearMarks,
3991
- closeConversionHint: closeConversionHint,
3992
- deleteElement: deleteElement,
3993
- handleContinualDeleteBackward: handleContinualDeleteBackward,
3994
- handleContinualInsertBreak: handleContinualInsertBreak,
3995
- insertElements: insertElements,
3996
- insertParagraph: insertParagraph,
3997
- mergeDeepToNodes: mergeDeepToNodes,
3998
- moveChildren: moveChildren,
3999
- onKeyDownResetBlockType: onKeyDownResetBlockType,
4000
- setEndSelection: setEndSelection,
4001
- setMarks: setMarks,
4002
- setNode: setNode,
4003
- unWrap: unWrap,
4004
- unwrapNodesByType: unwrapNodesByType
4005
- });
4118
+ const setMarks = (editor, marks, at) => {
4119
+ Transforms.setNodes(editor, marks, {
4120
+ at,
4121
+ match: Text.isText,
4122
+ split: true
4123
+ });
4124
+ };
4006
4125
 
4007
- /**
4008
- * Insert a new table
4009
- */
4010
- function insertTable(opts, editor, rows = 3, columns = 3, getCellContent) {
4126
+ const clearMarks = (editor) => {
4011
4127
  const { selection } = editor;
4012
- if (!selection?.anchor) {
4128
+ if (!selection) {
4013
4129
  return;
4014
4130
  }
4015
- // Create the table node
4016
- const table = createTable(opts, columns, rows, getCellContent);
4017
- insertElements(editor, table);
4018
- }
4131
+ if (Range.isCollapsed(selection)) {
4132
+ const marks = Editor.marks(editor);
4133
+ for (const key in marks) {
4134
+ Editor.removeMark(editor, key);
4135
+ }
4136
+ }
4137
+ else {
4138
+ const unsetMarks = {};
4139
+ MarkProps.forEach(key => {
4140
+ unsetMarks[key] = null;
4141
+ });
4142
+ setMarks(editor, unsetMarks);
4143
+ }
4144
+ };
4019
4145
 
4020
- function getInsertRowState(opts, editor, count = 1, at) {
4021
- const tablePosition = createTablePosition(editor);
4022
- let table = tablePosition.table;
4023
- let tableEntry = tablePosition.tableEntry;
4024
- // Create a new row with the right count of cells
4025
- const columns = table.children[0].children.length;
4026
- const rowIndex = tablePosition.getRowIndex();
4027
- const insertRowIndex = typeof at === 'undefined' ? rowIndex + 1 : at;
4028
- return { table, tableEntry, columns, rowIndex, insertRowIndex };
4029
- }
4030
- function packNewRow(opts, editor, count = 1, at) {
4146
+ const insertElements = (editor, elements) => {
4147
+ if (!editor.selection) {
4148
+ refocus(editor);
4149
+ }
4150
+ if (Range.isExpanded(editor.selection)) {
4151
+ Editor.deleteFragment(editor);
4152
+ }
4153
+ const type = !isArray(elements) ? elements.type : elements[0].type; // 后期处理复制粘贴需要修改
4154
+ const allowParentTypes = getPluginOptions(editor, type)?.allowParentTypes || [];
4155
+ const insertNodePath = getInsertElementsPath(editor, allowParentTypes);
4156
+ const [anchorBlock, anchorBlockPath] = anchorBlockEntry(editor);
4157
+ let isEmpty = Editor.isEmpty(editor, anchorBlock);
4158
+ if (insertNodePath) {
4159
+ Editor.withoutNormalizing(editor, () => {
4160
+ Transforms.insertNodes(editor, elements, { at: insertNodePath });
4161
+ Transforms.select(editor, Editor.start(editor, insertNodePath));
4162
+ if (isEmpty) {
4163
+ Transforms.removeNodes(editor, { at: anchorBlockPath });
4164
+ }
4165
+ });
4166
+ return;
4167
+ }
4168
+ const nextPath = Path.next([anchorBlockPath[0]]);
4169
+ Transforms.insertNodes(editor, elements, { at: nextPath });
4170
+ if (isEmpty && anchorBlockPath.length === 1) {
4171
+ Transforms.delete(editor, { at: anchorBlockPath });
4172
+ Transforms.select(editor, Editor.start(editor, anchorBlockPath));
4173
+ }
4174
+ else {
4175
+ Transforms.select(editor, Editor.start(editor, nextPath));
4176
+ }
4177
+ };
4178
+
4179
+ const setNode = (editor, props, origin) => {
4180
+ Transforms.setNodes(editor, props, { at: findPath(editor, origin) });
4181
+ };
4182
+
4183
+ /**
4184
+ * Unwrap nodes by type
4185
+ */
4186
+ const unwrapNodesByType = (editor, types, options = {}) => {
4187
+ if (!Array.isArray(types)) {
4188
+ types = [types];
4189
+ }
4190
+ Transforms.unwrapNodes(editor, {
4191
+ match: n => Element$1.isElement(n) && types.includes(n.type),
4192
+ ...options
4193
+ });
4194
+ };
4195
+
4196
+ const onKeyDownResetBlockType = ({ rules }) => (event, editor) => {
4197
+ let reset;
4198
+ if (editor.selection && isCollapsed(editor.selection)) {
4199
+ rules.forEach(({ types, defaultType, hotkey, predicate, onReset }) => {
4200
+ if (!event || (hotkey && isKeyHotkey(hotkey, event))) {
4201
+ if (predicate(editor) && isNodeTypeIn(editor, types)) {
4202
+ if (event !== null) {
4203
+ event.preventDefault();
4204
+ }
4205
+ Transforms.setNodes(editor, { type: defaultType });
4206
+ onReset(editor);
4207
+ reset = true;
4208
+ }
4209
+ }
4210
+ });
4211
+ }
4212
+ return reset;
4213
+ };
4214
+
4215
+ /**
4216
+ * 将节点的子级移动到路径。 返回移动的子级数。
4217
+ */
4218
+ const moveChildren = (editor, { at, to, match, start = 0 }) => {
4219
+ let moved = 0;
4220
+ const parentPath = Path.isPath(at) ? at : at[1];
4221
+ const parentNode = Path.isPath(at) ? Node.get(editor, parentPath) : at[0];
4222
+ if (!Editor.isBlock(editor, parentNode))
4223
+ return moved;
4224
+ for (let i = parentNode.children.length - 1; i >= start; i--) {
4225
+ const childPath = [...parentPath, i];
4226
+ const childNode = getNode(editor, childPath);
4227
+ if (!match || (childNode && match([childNode, childPath]))) {
4228
+ Transforms.moveNodes(editor, { at: childPath, to });
4229
+ moved++;
4230
+ }
4231
+ }
4232
+ return moved;
4233
+ };
4234
+
4235
+ const insertParagraph = (editor, at) => {
4236
+ Transforms.insertNodes(editor, createEmptyParagraph(), { at });
4237
+ };
4238
+
4239
+ /**
4240
+ * Recursively apply an operation to children nodes with a query.
4241
+ */
4242
+ const applyDeepToNodes = ({ node, source, apply, query }) => {
4243
+ const entry = [node, []];
4244
+ if (isNodeType(entry, query)) {
4245
+ if (source instanceof Function) {
4246
+ apply(node, source());
4247
+ }
4248
+ else {
4249
+ apply(node, source);
4250
+ }
4251
+ }
4252
+ if (!isAncestor(node)) {
4253
+ return;
4254
+ }
4255
+ node.children.forEach((child) => {
4256
+ applyDeepToNodes({ node: child, source, apply, query });
4257
+ });
4258
+ };
4259
+
4260
+ /**
4261
+ * Recursively merge a source object to children nodes with a query.
4262
+ */
4263
+ const mergeDeepToNodes = (options) => {
4264
+ applyDeepToNodes({ ...options, apply: defaults });
4265
+ };
4266
+
4267
+ const unWrap = (editor, kind) => {
4268
+ Editor.withoutNormalizing(editor, () => {
4269
+ Transforms.setNodes(editor, { type: ElementKinds.paragraph });
4270
+ Transforms.unwrapNodes(editor, {
4271
+ match: n => Element$1.isElement(n) && n.type === kind,
4272
+ split: true
4273
+ });
4274
+ });
4275
+ };
4276
+
4277
+ const deleteElement = (editor, element) => {
4278
+ const at = findPath(editor, element);
4279
+ Transforms.insertNodes(editor, createEmptyParagraph(), { at });
4280
+ AngularEditor.focus(editor);
4281
+ Transforms.select(editor, at);
4282
+ Transforms.removeNodes(editor, { at: Path.next(at) });
4283
+ };
4284
+
4285
+ const setEndSelection = (editor) => {
4286
+ const lastNode = getLastNode(editor, 1);
4287
+ const end = Editor.end(editor, lastNode[1]);
4288
+ Transforms.select(editor, end);
4289
+ AngularEditor.focus(editor);
4290
+ };
4291
+
4292
+ const closeConversionHint = (editor) => {
4293
+ const hintRef = THE_EDITOR_CONVERSION_HINT_REF.get(editor);
4294
+ if (hintRef) {
4295
+ hintRef.close();
4296
+ }
4297
+ };
4298
+
4299
+ function handleContinualDeleteBackward(editor, aboveResult, type) {
4300
+ const highestBlock = aboveResult[0];
4301
+ const lowestBlock = anchorBlock(editor);
4302
+ const wrapBlockType = highestBlock.type;
4303
+ if (lowestBlock && Editor.isStart(editor, editor.selection.anchor, aboveResult[1])) {
4304
+ if (wrapBlockType === type) {
4305
+ if (highestBlock.children[0] === lowestBlock) {
4306
+ unWrap(editor, wrapBlockType);
4307
+ return true;
4308
+ }
4309
+ }
4310
+ }
4311
+ return false;
4312
+ }
4313
+
4314
+ function handleContinualInsertBreak(editor, lowestBlock, type) {
4315
+ const isEmpty = Editor.isEmpty(editor, lowestBlock);
4316
+ const isEnd = Editor.isEnd(editor, editor.selection.anchor, editor.selection.focus.path);
4317
+ const aboveResult = Editor.above(editor, {
4318
+ match: n => Editor.isBlock(editor, n) && n.type === type
4319
+ });
4320
+ if (aboveResult && aboveResult[0] && isEnd && isEmpty) {
4321
+ const wrapBlock = aboveResult[0];
4322
+ if (wrapBlock.type === type) {
4323
+ if (wrapBlock.children[wrapBlock.children.length - 1] === lowestBlock) {
4324
+ unWrap(editor, wrapBlock.type);
4325
+ return true;
4326
+ }
4327
+ }
4328
+ }
4329
+ return false;
4330
+ }
4331
+
4332
+ var index = /*#__PURE__*/Object.freeze({
4333
+ __proto__: null,
4334
+ applyDeepToNodes: applyDeepToNodes,
4335
+ clearMarks: clearMarks,
4336
+ closeConversionHint: closeConversionHint,
4337
+ deleteElement: deleteElement,
4338
+ handleContinualDeleteBackward: handleContinualDeleteBackward,
4339
+ handleContinualInsertBreak: handleContinualInsertBreak,
4340
+ insertElements: insertElements,
4341
+ insertParagraph: insertParagraph,
4342
+ mergeDeepToNodes: mergeDeepToNodes,
4343
+ moveChildren: moveChildren,
4344
+ onKeyDownResetBlockType: onKeyDownResetBlockType,
4345
+ setEndSelection: setEndSelection,
4346
+ setMarks: setMarks,
4347
+ setNode: setNode,
4348
+ unWrap: unWrap,
4349
+ unwrapNodesByType: unwrapNodesByType
4350
+ });
4351
+
4352
+ /**
4353
+ * Insert a new table
4354
+ */
4355
+ function insertTable(opts, editor, rows = 3, columns = 3, getCellContent) {
4356
+ const { selection } = editor;
4357
+ if (!selection?.anchor) {
4358
+ return;
4359
+ }
4360
+ // Create the table node
4361
+ const table = createTable(opts, columns, rows, getCellContent);
4362
+ insertElements(editor, table);
4363
+ }
4364
+
4365
+ function getInsertRowState(opts, editor, count = 1, at) {
4366
+ const tablePosition = createTablePosition(editor);
4367
+ let table = tablePosition.table;
4368
+ let tableEntry = tablePosition.tableEntry;
4369
+ // Create a new row with the right count of cells
4370
+ const columns = table.children[0].children.length;
4371
+ const rowIndex = tablePosition.getRowIndex();
4372
+ const insertRowIndex = typeof at === 'undefined' ? rowIndex + 1 : at;
4373
+ return { table, tableEntry, columns, rowIndex, insertRowIndex };
4374
+ }
4375
+ function packNewRow(opts, editor, count = 1, at) {
4031
4376
  const { table, tableEntry, columns, insertRowIndex } = getInsertRowState(opts, editor, count, at);
4032
4377
  const rowspan = calcSpanForRow(table, insertRowIndex);
4033
4378
  const newRow = createRow(opts, columns);
@@ -4538,7 +4883,9 @@ const ImageEditor = {
4538
4883
  });
4539
4884
  return false;
4540
4885
  }
4541
- if (image.size / 1000000 >= PICTURE_ACCEPTED_UPLOAD_SIZE) {
4886
+ const acceptedUploadSize = getPluginOptions(editor, PluginKeys.image)?.acceptedUploadSize ?? PICTURE_ACCEPTED_UPLOAD_SIZE;
4887
+ console.log(acceptedUploadSize);
4888
+ if (image.size / 1000000 >= acceptedUploadSize) {
4542
4889
  editor.onError({
4543
4890
  code: ErrorCodes.IMAGE_ERR_SIZE_LIMIT
4544
4891
  });
@@ -7403,21 +7750,6 @@ const createBlockCardPlugin = createPluginFactory({
7403
7750
  withOverrides: withBlockCard
7404
7751
  });
7405
7752
 
7406
- const isColorPanel = (element) => {
7407
- const pickerPanel = element.closest('.thy-color-picker-panel');
7408
- const customPickerPanel = element.closest('.thy-color-picker-custom-panel');
7409
- if (pickerPanel || customPickerPanel) {
7410
- return true;
7411
- }
7412
- return false;
7413
- };
7414
- const isColorIndicator = (element) => {
7415
- return element.closest('.indicator-hue-alp');
7416
- };
7417
- const isColorInput = (element) => {
7418
- return element.closest('.thy-color-inputs');
7419
- };
7420
-
7421
7753
  const withInternalCommon = (editor) => {
7422
7754
  const { globalMousedown, onKeydown } = editor;
7423
7755
  editor.globalMousedown = (event) => {
@@ -9011,15 +9343,12 @@ class TheLinkEditComponent {
9011
9343
  }
9012
9344
  });
9013
9345
  }
9014
- linkRegExp(val) {
9015
- return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(val);
9016
- }
9017
9346
  closePopover(type) {
9018
9347
  this.thyPopoverRef.close(type);
9019
9348
  }
9020
9349
  applyLink(form) {
9021
9350
  const link = this.link.trim();
9022
- if (this.linkRegExp(link)) {
9351
+ if (isUrl(link)) {
9023
9352
  const linkPath = findPath(this.editor, this.node);
9024
9353
  if (this.originLink !== link) {
9025
9354
  Transforms.setNodes(this.editor, { url: link }, { at: linkPath });
@@ -10970,58 +11299,6 @@ function resetTableCell(editor, table, cell, cellRow, cellCol) {
10970
11299
  });
10971
11300
  }
10972
11301
 
10973
- function getSelectCellNode(editor, selectedCells) {
10974
- const pos = createTablePosition(editor);
10975
- return selectedCells
10976
- .map(item => {
10977
- const node = pos.findCellByPath(item);
10978
- if (node) {
10979
- return {
10980
- ...item,
10981
- node: node
10982
- };
10983
- }
10984
- })
10985
- .filter(item => item);
10986
- }
10987
-
10988
- /* cell-position 有关的函数 */
10989
- const isSelectedAllCell = (editor, selectedCellPositions) => {
10990
- if (!AngularEditor.isFocused(editor)) {
10991
- return false;
10992
- }
10993
- const pos = createTablePosition(editor);
10994
- return !!selectedCellPositions.length && pos.getHeight() * pos.getWidth() === selectedCellPositions.length;
10995
- };
10996
- const getSelectedCellPositions = (editor, selectedCells) => {
10997
- return selectedCells?.map((cell) => {
10998
- const path = AngularEditor.findPath(editor, cell);
10999
- const [row, col] = path.slice(-2);
11000
- return { row, col };
11001
- });
11002
- };
11003
- /* 获取一定范围内所有的单元格 */
11004
- const getCellPositionsFromRange = (startRow, startCol, endRow, endCol) => {
11005
- const result = [];
11006
- for (let row = startRow; row < endRow; row++) {
11007
- for (let col = startCol; col < endCol; col++) {
11008
- result.push({ row, col });
11009
- }
11010
- }
11011
- return result;
11012
- };
11013
- /**
11014
- * 去重重复的单元格位置
11015
- * @returns
11016
- */
11017
- const uniqueCellPosition = (cells, selectedCellPositions) => {
11018
- const result = [];
11019
- const modCells = new Set();
11020
- cells.concat(selectedCellPositions).forEach(cell => modCells.add(JSON.stringify(cell)));
11021
- modCells.forEach((cell) => result.push(JSON.parse(cell)));
11022
- return result;
11023
- };
11024
-
11025
11302
  function isSelectedCellMerged(editor) {
11026
11303
  if (editor && editor.selection) {
11027
11304
  const opts = new TableOptions();
@@ -11271,13 +11548,61 @@ const setSelectedCellsBackgroundColor = (editor, color, tableStore) => {
11271
11548
  }
11272
11549
  };
11273
11550
 
11551
+ function setTableOptions(editor, newOptions) {
11552
+ const tablePosition = createTablePosition(editor);
11553
+ const tablePath = getTablePath(editor);
11554
+ const table = tablePosition.table;
11555
+ const options = { ...table.options, ...newOptions };
11556
+ Transforms.setNodes(editor, { options }, { at: tablePath });
11557
+ }
11558
+
11559
+ function removeColumnOrRows(editor, tableStore, options) {
11560
+ const { isSelectedTable } = tableStore;
11561
+ const selectedRowsIndex = options?.selectedRowsIndex || tableStore.selectedRowsIndex;
11562
+ const selectedColumnsIndex = options?.selectedColumnsIndex || tableStore.selectedColumnsIndex;
11563
+ const tablePosition = createTablePosition(editor);
11564
+ if (isSelectedTable) {
11565
+ TableEditor.removeTable(editor);
11566
+ return;
11567
+ }
11568
+ const tableComponent = ELEMENT_TO_COMPONENT.get(tablePosition.table);
11569
+ if (selectedRowsIndex.length > 0 && selectedColumnsIndex.length === 0) {
11570
+ // 删除行时取消标题行
11571
+ if (tablePosition.table && tableComponent.headerRow && selectedRowsIndex.includes(0)) {
11572
+ setTableOptions(editor, { headerRow: false });
11573
+ // headerRow 兼容代码, 取消标题行的时候同时设置 row 中的 header 属性
11574
+ if (tablePosition.table.children[0].header) {
11575
+ const rowPath = TheEditor.findPath(editor, tablePosition.table.children[0]);
11576
+ Transforms.setNodes(editor, { header: null }, { at: rowPath });
11577
+ }
11578
+ }
11579
+ selectedRowsIndex
11580
+ .sort((a, b) => b - a)
11581
+ .forEach(index => {
11582
+ TableEditor.removeRow(editor, index);
11583
+ });
11584
+ tableStore.changeCells();
11585
+ }
11586
+ if (selectedColumnsIndex.length > 0 && selectedRowsIndex.length === 0) {
11587
+ // 删除列时取消标题列
11588
+ if (tablePosition.table && tablePosition.table.options?.headerColumn && selectedColumnsIndex.includes(0)) {
11589
+ setTableOptions(editor, { headerColumn: false });
11590
+ }
11591
+ selectedColumnsIndex
11592
+ .sort((a, b) => b - a)
11593
+ .forEach(index => {
11594
+ TableEditor.removeColumn(editor, index);
11595
+ });
11596
+ tableStore.changeCells();
11597
+ }
11598
+ }
11599
+
11274
11600
  const getMinAndMaxCellIndex = (editor, selectedCellPositions, maxRow, maxCol, minRow, minCol, table) => {
11275
11601
  const beforeCols = [];
11276
11602
  const beforeRows = [];
11277
11603
  let spanSelectedCells = [];
11278
11604
  if (selectedCellPositions.length) {
11279
- spanSelectedCells = selectedCellPositions
11280
- .map(item => {
11605
+ spanSelectedCells = selectedCellPositions.map(item => {
11281
11606
  const { row, col } = item;
11282
11607
  const node = table.children[row].children[col];
11283
11608
  if (!node.hidden) {
@@ -11287,20 +11612,26 @@ const getMinAndMaxCellIndex = (editor, selectedCellPositions, maxRow, maxCol, mi
11287
11612
  rowspan: node.rowspan || 1
11288
11613
  };
11289
11614
  }
11290
- })
11291
- .filter(item => item);
11615
+ else {
11616
+ return {
11617
+ ...item,
11618
+ colspan: 1,
11619
+ rowspan: 1
11620
+ };
11621
+ }
11622
+ });
11292
11623
  }
11293
- table.children.map((row, rowIndex) => {
11624
+ table.children.forEach((row, rowIndex) => {
11294
11625
  if (rowIndex <= maxRow) {
11295
- row.children.map((cell, colIndex) => {
11626
+ row.children.forEach((cell, colIndex) => {
11296
11627
  if (colIndex <= maxCol) {
11297
11628
  const cellRowIndex = rowIndex + (cell.rowspan || 1) - 1;
11298
11629
  const cellColIndex = colIndex + (cell.colspan || 1) - 1;
11299
11630
  if (spanSelectedCells.length) {
11300
- const { row: selectRow, col: selectCol, rowspan: selectRowspan, colspan: selectColspan } = spanSelectedCells[0];
11301
- if (selectRow + selectRowspan - 1 >= minRow && selectCol + selectColspan - 1 >= minCol) {
11302
- minRow = Math.min(spanSelectedCells[0].row, minRow);
11303
- minCol = Math.min(spanSelectedCells[0].col, minCol);
11631
+ const { row: selectRow, col: selectCol, rowspan: selectRowSpan, colspan: selectColSpan } = spanSelectedCells[0];
11632
+ if (selectRow + selectRowSpan - 1 >= minRow && selectCol + selectColSpan - 1 >= minCol) {
11633
+ minRow = Math.min(selectRow, minRow);
11634
+ minCol = Math.min(selectCol, minCol);
11304
11635
  }
11305
11636
  }
11306
11637
  if (cell.colspan && cell.colspan > 1) {
@@ -11353,17 +11684,17 @@ class TableStore {
11353
11684
  this.isRightClicking = false;
11354
11685
  this.isFocusedInput = false;
11355
11686
  this.pointerSelection = false;
11356
- this.isSelectedAllCell = () => {
11357
- if (!this.editor.selection)
11358
- return false;
11359
- const pos = createTablePosition(this.editor);
11360
- const selectedCellPositions = this.getSelectedCellPositions();
11361
- return !!selectedCellPositions.length && pos.getHeight() * pos.getWidth() === selectedCellPositions.length;
11362
- };
11687
+ this.areaSelection = false;
11688
+ }
11689
+ initEditor(editor) {
11690
+ this.editor = editor;
11363
11691
  }
11364
11692
  getSelectedCellPositions() {
11365
11693
  return getSelectedCellPositions(this.editor, this.selectedCells$.getValue());
11366
11694
  }
11695
+ publishDangerousCells(value) {
11696
+ return this.dangerousCells$.next(value);
11697
+ }
11367
11698
  setSelectedColumnsAndRowIndex() {
11368
11699
  if (!this.editor?.selection) {
11369
11700
  return;
@@ -11410,29 +11741,52 @@ class TableStore {
11410
11741
  this.selectedCells$.next(cellElements);
11411
11742
  this.setSelectedColumnsAndRowIndex();
11412
11743
  }
11413
- initEditor(editor) {
11414
- this.editor = editor;
11415
- }
11416
11744
  selectRow(editor, index) {
11417
- this.clearLastFocusPath();
11418
11745
  const pos = createTablePosition(editor);
11419
- const cells = getCellPositionsFromRange(index, 0, index + 1, pos.getWidth());
11420
- this.setSelectedCells(cells, pos);
11421
- this.focusCell(editor, pos.tableEntry[1].concat([index, 0]));
11746
+ const rangeCells = getCellPositionsFromRange(index, 0, index + 1, pos.getWidth());
11747
+ this.clearLastFocusPath();
11748
+ if (this.areaSelection) {
11749
+ this.areaSelectRowAndColumn(rangeCells);
11750
+ }
11751
+ else {
11752
+ this.setSelectedCells(rangeCells, pos);
11753
+ this.focusCell(pos.tableEntry[1].concat([index, 0]));
11754
+ }
11422
11755
  }
11423
11756
  selectColumn(editor, index) {
11424
- this.clearLastFocusPath();
11425
11757
  const pos = createTablePosition(editor);
11426
- const cells = getCellPositionsFromRange(0, index, pos.getHeight(), index + 1);
11427
- this.setSelectedCells(cells, pos);
11428
- this.focusCell(editor, pos.tableEntry[1].concat([0, index]));
11758
+ const rangeCells = getCellPositionsFromRange(0, index, pos.getHeight(), index + 1);
11759
+ this.clearLastFocusPath();
11760
+ if (this.areaSelection) {
11761
+ this.areaSelectRowAndColumn(rangeCells);
11762
+ }
11763
+ else {
11764
+ this.setSelectedCells(rangeCells, pos);
11765
+ this.focusCell(pos.tableEntry[1].concat([0, index]));
11766
+ }
11429
11767
  }
11430
11768
  selectTable(editor) {
11431
- this.isSelectedTable = true;
11432
11769
  const pos = createTablePosition(editor);
11433
11770
  const cells = getCellPositionsFromRange(0, 0, pos.getHeight(), pos.getWidth());
11771
+ const lastCell = cells[cells.length - 1];
11772
+ const anchorCellPath = pos.tableEntry[1].concat([lastCell.row, lastCell.col]);
11773
+ this.isSelectedTable = true;
11434
11774
  this.setSelectedCells(cells, pos);
11435
- this.focusCell(editor, pos.tableEntry[1].concat([0, 0]));
11775
+ this.setAreaAnchorCellPath(anchorCellPath);
11776
+ this.focusCell(pos.tableEntry[1].concat([0, 0]));
11777
+ }
11778
+ // 拖选开始 || 记录聚焦点
11779
+ selectCellStart(cell, editor) {
11780
+ const node = AngularEditor.toSlateNode(editor, cell);
11781
+ const path = AngularEditor.findPath(editor, node);
11782
+ this.isPrepareSelecting = true;
11783
+ this.anchorCellPath = path;
11784
+ this.focusCellPath = path;
11785
+ this.focusCellElement = cell;
11786
+ this.lastFocusCellPath = path;
11787
+ if (!this.preFocusCellPath) {
11788
+ this.preFocusCellPath = this.anchorCellPath;
11789
+ }
11436
11790
  }
11437
11791
  // 拖选
11438
11792
  selectCells(editor) {
@@ -11453,6 +11807,13 @@ class TableStore {
11453
11807
  const cells = getCellPositionsFromRange(minRow, minCol, maxRow + 1, maxCol + 1);
11454
11808
  this.setSelectedCells(cells, pos);
11455
11809
  }
11810
+ selectFirstCell() {
11811
+ const selectedCellPositions = this.getSelectedCellPositions();
11812
+ const { row, col } = selectedCellPositions[0];
11813
+ const tablePath = getTablePath(this.editor);
11814
+ const path = Editor.start(this.editor, [...tablePath, row, col]);
11815
+ Transforms.select(this.editor, path);
11816
+ }
11456
11817
  // 选择单元格
11457
11818
  selectCell(cell, editor) {
11458
11819
  const node = AngularEditor.toSlateNode(editor, cell);
@@ -11462,80 +11823,38 @@ class TableStore {
11462
11823
  this.focusCellElement = cell;
11463
11824
  const [row, col] = path.slice(-2);
11464
11825
  const pos = createTablePosition(editor);
11465
- const result = [{ row, col }];
11826
+ const cells = [{ row, col }];
11466
11827
  const selectedCellPositions = this.getSelectedCellPositions();
11467
11828
  if (this.pointerSelection) {
11468
- result.push(...selectedCellPositions);
11829
+ cells.push(...selectedCellPositions);
11469
11830
  // 处理单元格选中时,处理为选中多单元格
11470
11831
  const selectedCells = getCellPositionsBeforeMerge(this.editor, { row, col });
11471
- result.push(...selectedCells);
11832
+ cells.push(...selectedCells);
11472
11833
  // 已聚焦的单元格在多选模式下选中(暂存上次聚焦的单元格数据)
11473
11834
  const focusCell = this.lastFocusCellPath?.slice(-2);
11474
11835
  if (focusCell) {
11475
11836
  const focusCells = getCellPositionsBeforeMerge(this.editor, { row: focusCell[0], col: focusCell[1] });
11476
- result.push(...focusCells);
11837
+ cells.push(...focusCells);
11477
11838
  }
11478
11839
  }
11479
- this.setSelectedCells(result, pos);
11480
- }
11481
- selectedCellsChange() {
11482
- return this.selectedCells$.asObservable().pipe(skip(1));
11483
- }
11484
- cellsPositionChange() {
11485
- return this.cellsChangeObject$.asObservable();
11486
- }
11487
- changeCells() {
11488
- this.cellsChangeObject$.next();
11489
- }
11490
- emitTableChange() {
11491
- this.tableChange$.next();
11492
- }
11493
- tableChange() {
11494
- return this.tableChange$.asObservable();
11495
- }
11496
- clearSelectedCells() {
11497
- this.selectedColumnsIndex = [];
11498
- this.selectedRowsIndex = [];
11499
- this.isSelectedTable = false;
11500
- this.isCellSelecting = false;
11501
- this.isRightClicking = false;
11502
- this.isFocusedInput = false;
11503
- this.selectedCells$.next([]);
11504
- }
11505
- clearLastFocusPath() {
11506
- this.lastFocusCellPath = null;
11507
- }
11508
- // 拖选开始 || 记录聚焦点
11509
- selectCellStart(cell, editor) {
11510
- this.isPrepareSelecting = true;
11511
- const node = AngularEditor.toSlateNode(editor, cell);
11512
- const path = AngularEditor.findPath(editor, node);
11513
- this.anchorCellPath = path;
11514
- this.lastFocusCellPath = path;
11515
- if (!this.preFocusCellPath) {
11516
- this.preFocusCellPath = this.anchorCellPath;
11517
- }
11840
+ this.setSelectedCells(cells, pos);
11518
11841
  }
11519
11842
  selectCellOngoing(cell, editor) {
11520
- if (AngularEditor.isReadonly(editor)) {
11521
- return;
11522
- }
11523
- if (!editor.selection) {
11843
+ const pos = createTablePosition(editor);
11844
+ if (AngularEditor.isReadonly(editor) || !editor.selection || !pos?.table) {
11524
11845
  return;
11525
11846
  }
11526
11847
  let isChanged;
11527
11848
  if (cell) {
11528
11849
  const node = AngularEditor.toSlateNode(editor, cell);
11529
11850
  const path = AngularEditor.findPath(editor, node);
11530
- isChanged = !this.focusCellPath || this.focusCellPath.toString() !== path.toString();
11851
+ isChanged = !this.focusCellPath || !Path.equals(this.focusCellPath, path);
11531
11852
  this.focusCellPath = path;
11532
11853
  this.focusCellElement = cell;
11533
11854
  }
11534
11855
  else {
11535
11856
  const selectedCellPositions = this.getSelectedCellPositions();
11536
- isChanged =
11537
- !this.focusCellPath ||
11538
- (this.focusCellPath.toString() === this.anchorCellPath.toString() && selectedCellPositions.length === 0);
11857
+ isChanged = !this.focusCellPath || (Path.equals(this.focusCellPath, this.anchorCellPath) && selectedCellPositions.length === 0);
11539
11858
  }
11540
11859
  if (this.isPrepareSelecting && isChanged) {
11541
11860
  if (JSON.stringify(this.preFocusCellPath) !== JSON.stringify(this.focusCellPath)) {
@@ -11545,18 +11864,40 @@ class TableStore {
11545
11864
  }
11546
11865
  }
11547
11866
  }
11867
+ clearSelectedCells() {
11868
+ this.selectedColumnsIndex = [];
11869
+ this.selectedRowsIndex = [];
11870
+ this.isSelectedTable = false;
11871
+ this.isCellSelecting = false;
11872
+ this.isRightClicking = false;
11873
+ this.isFocusedInput = false;
11874
+ this.selectedCells$.next([]);
11875
+ }
11876
+ clearLastFocusPath() {
11877
+ this.lastFocusCellPath = null;
11878
+ }
11879
+ selectedCellsChange() {
11880
+ return this.selectedCells$.asObservable().pipe(skip(1));
11881
+ }
11882
+ cellsPositionChange() {
11883
+ return this.cellsChangeObject$.asObservable();
11884
+ }
11885
+ changeCells() {
11886
+ this.cellsChangeObject$.next();
11887
+ }
11888
+ emitTableChange() {
11889
+ this.tableChange$.next();
11890
+ }
11891
+ tableChange() {
11892
+ return this.tableChange$.asObservable();
11893
+ }
11548
11894
  selectCellEnd(editor) {
11549
11895
  if (this.isCellSelecting) {
11550
- this.focusCell(editor, this.focusCellPath);
11896
+ this.focusCell(this.focusCellPath);
11551
11897
  }
11552
11898
  this.isPrepareSelecting = false;
11553
11899
  this.preFocusCellPath = null;
11554
11900
  }
11555
- focusCell(editor, path) {
11556
- const at = Editor.start(editor, path);
11557
- TheEditor.focus(this.editor);
11558
- Transforms.select(editor, at);
11559
- }
11560
11901
  dangerousCellsChange() {
11561
11902
  return this.dangerousCells$.asObservable().pipe(skip(1));
11562
11903
  }
@@ -11628,13 +11969,6 @@ class TableStore {
11628
11969
  this.dangerousColumnsIndex = [...Array(pos.getWidth())].map((_, i) => i);
11629
11970
  this.dangerousCells$.next(cells);
11630
11971
  }
11631
- selectFirstCell() {
11632
- const selectedCellPositions = this.getSelectedCellPositions();
11633
- const { row, col } = selectedCellPositions[0];
11634
- const tablePath = getTablePath(this.editor);
11635
- const path = Editor.start(this.editor, [...tablePath, row, col]);
11636
- Transforms.select(this.editor, path);
11637
- }
11638
11972
  setSelectedCellsBackgroundColor(backgroundColor) {
11639
11973
  const cells = this.selectedCells$.getValue();
11640
11974
  Editor.withoutNormalizing(this.editor, () => {
@@ -11658,53 +11992,83 @@ class TableStore {
11658
11992
  Transforms.select(this.editor, Editor.start(this.editor, tablePosition.cellEntry[1]));
11659
11993
  }
11660
11994
  }
11661
- setTableOptions(editor, newOptions) {
11662
- const tablePosition = createTablePosition(editor);
11663
- const tablePath = getTablePath(this.editor);
11664
- const table = tablePosition.table;
11665
- const options = { ...table.options, ...newOptions };
11666
- Transforms.setNodes(editor, { options }, { at: tablePath });
11995
+ /**
11996
+ * 聚焦单元格并设置聚焦相关路径及元素
11997
+ */
11998
+ focusCell(path) {
11999
+ const node = Node.get(this.editor, path);
12000
+ const cellHTMLElement = AngularEditor.toDOMNode(this.editor, node);
12001
+ this.preFocusCellPath = this.focusCellPath;
12002
+ this.focusCellPath = path;
12003
+ this.focusCellElement = cellHTMLElement;
12004
+ focusCell(this.editor, path);
11667
12005
  }
11668
- removeDangerousColumnsOrRows() {
11669
- const { dangerousRowsIndex, dangerousColumnsIndex } = this;
11670
- this.removeColumnOrRows(dangerousRowsIndex, dangerousColumnsIndex);
12006
+ /**
12007
+ * 区域选择开始
12008
+ * @param editor 编辑器对象
12009
+ * @param cell 单元格元素
12010
+ */
12011
+ areaSelectionStart(cell, editor) {
12012
+ const node = AngularEditor.toSlateNode(editor, cell);
12013
+ const path = AngularEditor.findPath(editor, node);
12014
+ this.isPrepareSelecting = true;
12015
+ this.lastFocusCellPath = path;
12016
+ if (!this?.anchorCellPath) {
12017
+ this.anchorCellPath = path;
12018
+ }
12019
+ if (!this?.focusCellPath) {
12020
+ this.focusCellPath = path;
12021
+ }
12022
+ if (!this.preFocusCellPath) {
12023
+ this.preFocusCellPath = this.anchorCellPath;
12024
+ }
11671
12025
  }
11672
- removeColumnOrRows(selectedRowIndexs = this.selectedRowsIndex, selectedColumnIndexs = this.selectedColumnsIndex) {
11673
- const { isSelectedTable } = this;
11674
- const tablePosition = createTablePosition(this.editor);
11675
- if (isSelectedTable) {
11676
- TableEditor.removeTable(this.editor);
12026
+ /**
12027
+ * 设置区域选择的单元格
12028
+ * @param cellElement 单元格元素
12029
+ */
12030
+ setAreaSelectionCells(cellElement) {
12031
+ if (AngularEditor.isReadonly(this.editor) || !this.editor.selection || !this.isPrepareSelecting) {
11677
12032
  return;
11678
12033
  }
11679
- const tableComponent = ELEMENT_TO_COMPONENT.get(tablePosition.table);
11680
- if (selectedRowIndexs.length > 0 && selectedColumnIndexs.length === 0) {
11681
- // 删除行时取消标题行
11682
- if (tablePosition.table && tableComponent.headerRow && selectedRowIndexs.includes(0)) {
11683
- this.setTableOptions(this.editor, { headerRow: false });
11684
- // headerRow 兼容代码, 取消标题行的时候同时设置 row 中的 header 属性
11685
- if (tablePosition.table.children[0].header) {
11686
- const rowPath = TheEditor.findPath(this.editor, tablePosition.table.children[0]);
11687
- Transforms.setNodes(this.editor, { header: null }, { at: rowPath });
11688
- }
11689
- }
11690
- selectedRowIndexs
11691
- .sort((a, b) => b - a)
11692
- .forEach(index => {
11693
- TableEditor.removeRow(this.editor, index);
11694
- });
11695
- this.changeCells();
12034
+ const currentCellPath = AngularEditor.findPath(this.editor, cellElement);
12035
+ const selectedCellPositions = this.getSelectedCellPositions();
12036
+ const selectEqual = Path.equals(currentCellPath, this.anchorCellPath);
12037
+ // 不可以区域选择单一单元格
12038
+ if (selectedCellPositions.length <= 1 && selectEqual) {
12039
+ return;
11696
12040
  }
11697
- if (selectedColumnIndexs.length > 0 && selectedRowIndexs.length === 0) {
11698
- // 删除列时取消标题列
11699
- if (tablePosition.table && tablePosition.table.options?.headerColumn && selectedColumnIndexs.includes(0)) {
11700
- this.setTableOptions(this.editor, { headerColumn: false });
11701
- }
11702
- selectedColumnIndexs
11703
- .sort((a, b) => b - a)
11704
- .forEach(index => {
11705
- TableEditor.removeColumn(this.editor, index);
11706
- });
11707
- this.changeCells();
12041
+ this.isCellSelecting = true;
12042
+ this.focusCell(currentCellPath);
12043
+ this.selectCells(this.editor);
12044
+ }
12045
+ /**
12046
+ * 处理区域选择启用时选择整行/整列
12047
+ * @param cells 选择的单元格
12048
+ */
12049
+ areaSelectRowAndColumn(cells) {
12050
+ const pos = createTablePosition(this.editor);
12051
+ const [row, col] = this.focusCellPath.slice(-2);
12052
+ const selectCells = [{ row, col }, ...cells];
12053
+ const sortRows = selectCells.map(item => item.row).sort((m, n) => m - n);
12054
+ const sortCols = selectCells.map(item => item.col).sort((m, n) => m - n);
12055
+ const startRow = sortRows[0];
12056
+ const startCol = sortCols[0];
12057
+ const endRow = sortCols[sortCols.length - 1];
12058
+ const endCol = sortRows[sortRows.length - 1];
12059
+ const anchorCellPath = pos.tableEntry[1].concat([endCol, endRow]);
12060
+ const focusCellPath = pos.tableEntry[1].concat([startRow, startCol]);
12061
+ this.setAreaAnchorCellPath(anchorCellPath);
12062
+ this.focusCell(focusCellPath);
12063
+ this.selectCells(this.editor);
12064
+ }
12065
+ /**
12066
+ * 设置区域选择触发时的指定 anchorCellPath
12067
+ * @param path 路径
12068
+ */
12069
+ setAreaAnchorCellPath(path) {
12070
+ if (this.areaSelection && path) {
12071
+ this.anchorCellPath = path;
11708
12072
  }
11709
12073
  }
11710
12074
  }
@@ -11839,7 +12203,10 @@ class TheTableContextMenuService {
11839
12203
  name: '删除所在行',
11840
12204
  visibility: true,
11841
12205
  actionHandle: () => {
11842
- this.tableStore.removeDangerousColumnsOrRows();
12206
+ removeColumnOrRows(this.editor, this.tableStore, {
12207
+ selectedColumnsIndex: this.tableStore.dangerousColumnsIndex,
12208
+ selectedRowsIndex: this.tableStore.dangerousRowsIndex
12209
+ });
11843
12210
  this.tableStore.clearDangerousCells();
11844
12211
  this.tableStore.clearSelectedCells();
11845
12212
  },
@@ -11854,7 +12221,10 @@ class TheTableContextMenuService {
11854
12221
  name: '删除所在列',
11855
12222
  visibility: true,
11856
12223
  actionHandle: () => {
11857
- this.tableStore.removeDangerousColumnsOrRows();
12224
+ removeColumnOrRows(this.editor, this.tableStore, {
12225
+ selectedColumnsIndex: this.tableStore.dangerousColumnsIndex,
12226
+ selectedRowsIndex: this.tableStore.dangerousRowsIndex
12227
+ });
11858
12228
  this.tableStore.clearDangerousCells();
11859
12229
  this.tableStore.clearSelectedCells();
11860
12230
  },
@@ -12013,7 +12383,7 @@ class TheTableOptionsComponent {
12013
12383
  currentOption.isActive = !option.isActive;
12014
12384
  const tableOption = {};
12015
12385
  tableOption[option.key] = currentOption.isActive || false;
12016
- this.tableStore.setTableOptions(this.editor, { ...tableOption });
12386
+ setTableOptions(this.editor, { ...tableOption });
12017
12387
  // headerRow 兼容代码, 取消标题行的时候同时设置 row 中的 header 属性
12018
12388
  if (option.key === TableOperations.headerRow && !tableOption[option.key] && this.table.children[0].header) {
12019
12389
  const rowPath = TheEditor.findPath(this.editor, this.table.children[0]);
@@ -12022,7 +12392,7 @@ class TheTableOptionsComponent {
12022
12392
  }
12023
12393
  }
12024
12394
  TheTableOptionsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TheTableOptionsComponent, deps: [{ token: i1$1.ThyPopoverRef }], target: i0.ɵɵFactoryTarget.Component });
12025
- TheTableOptionsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: TheTableOptionsComponent, selector: "the-table-options", inputs: { tableStore: "tableStore", editor: "editor" }, ngImport: i0, template: `
12395
+ TheTableOptionsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: TheTableOptionsComponent, selector: "the-table-options", inputs: { editor: "editor" }, ngImport: i0, template: `
12026
12396
  <div class="thy-dropdown-menu table-drop-menu">
12027
12397
  <ng-container *ngFor="let option of tableDropdownList">
12028
12398
  <a thyDropdownMenuItem href="javascript:;" (mousedown)="setTableOptions($event, option)">
@@ -12051,9 +12421,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
12051
12421
  </div>
12052
12422
  `
12053
12423
  }]
12054
- }], ctorParameters: function () { return [{ type: i1$1.ThyPopoverRef }]; }, propDecorators: { tableStore: [{
12055
- type: Input
12056
- }], editor: [{
12424
+ }], ctorParameters: function () { return [{ type: i1$1.ThyPopoverRef }]; }, propDecorators: { editor: [{
12057
12425
  type: Input
12058
12426
  }] } });
12059
12427
 
@@ -12144,7 +12512,7 @@ class TheTableToolbarComponent {
12144
12512
  }
12145
12513
  onDelete(event) {
12146
12514
  event.preventDefault();
12147
- this.tableStore.removeColumnOrRows();
12515
+ removeColumnOrRows(this.editor, this.tableStore);
12148
12516
  this.tableStore.clearDangerousCells();
12149
12517
  this.tableStore.clearSelectedCells();
12150
12518
  this.popoverRef.close();
@@ -12192,7 +12560,6 @@ class TheTableToolbarComponent {
12192
12560
  this.thyPopover.open(TheTableOptionsComponent, {
12193
12561
  origin: event.currentTarget,
12194
12562
  initialState: {
12195
- tableStore: this.tableStore,
12196
12563
  editor: this.editor
12197
12564
  },
12198
12565
  minWidth: 0,
@@ -12209,404 +12576,198 @@ TheTableToolbarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0",
12209
12576
  TheTableToolbarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: TheTableToolbarComponent, selector: "the-table-toolbar", inputs: { tableStore: "tableStore", tableElement: "tableElement" }, ngImport: i0, template: "<thy-actions thySize=\"xxs\">\n <ng-container *ngFor=\"let item of cellMenuList\">\n <a\n *ngIf=\"item.visibility\"\n href=\"javascript:;\"\n thyAction\n [thyActionIcon]=\"item.icon\"\n [thyTooltip]=\"item.name\"\n (mousedown)=\"item.actionHandle()\"\n ></a>\n </ng-container>\n <thy-divider *ngIf=\"hasDivider\" class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"> </thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyTooltip=\"\u5355\u5143\u683C\u80CC\u666F\"\n thyColorPicker\n [(ngModel)]=\"selectedColor\"\n (ngModelChange)=\"changeColor($event)\"\n (mousedown)=\"openColorPanel($event)\"\n thyPlacement=\"bottomLeft\"\n [thyHasBackdrop]=\"false\"\n >\n <thy-icon thyIconName=\"background-tt\" thyIconType=\"twotone\" [thyTwotoneColor]=\"selectedColor\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && !isColumnEqual\"\n thyAction\n thyTooltip=\"\u5217\u7B49\u5BBD\"\n (mousedown)=\"setEquallyColumnHandle($event)\"\n >\n <thy-icon thyIconName=\"table-column-equal-width\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && tableOptions?.showFullscreen\"\n thyAction\n thyTooltip=\"\u5168\u5C4F\"\n (mousedown)=\"setFullscreen($event)\"\n >\n <thy-icon thyIconName=\"arrows-alt\"></thy-icon>\n </a>\n <a\n *ngIf=\"tableStore.isSelectedTable && !tableStore?.isFullscreen\"\n class=\"fullscreen-hidden\"\n href=\"javascript:;\"\n thyAction\n thyActionIcon=\"copy\"\n thyTooltip=\"\u590D\u5236\"\n (mousedown)=\"onCopy($event)\"\n ></a>\n <ng-container *ngIf=\"tableStore.isSelectedTable\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a href=\"javascript:;\" class=\"link-with-down\" thyAction (mousedown)=\"mousedown($event)\" (click)=\"openTableOptionMenu($event)\">\n <span>\u8868\u683C\u9009\u9879</span>\n <thy-icon class=\"font-size-sm text-desc ml-1\" thyIconName=\"caret-down\"></thy-icon>\n </a>\n </ng-container>\n <ng-container *ngIf=\"tableStore?.isFullscreen ? deleteIcon && !tableStore.isSelectedTable : deleteIcon\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyType=\"danger\"\n [thyActionIcon]=\"deleteIcon\"\n [thyTooltip]=\"iconName\"\n (mousedown)=\"onDelete($event)\"\n (mouseenter)=\"onEnterDelete($event)\"\n (mouseleave)=\"onLeaveDelete($event)\"\n ></a>\n </ng-container>\n</thy-actions>\n", dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.ThyIconComponent, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "directive", type: i8.ThyTooltipDirective, selector: "[thyTooltip],[thy-tooltip]", inputs: ["thyTooltip", "thyTooltipPlacement", "thyTooltipClass", "thyTooltipShowDelay", "thyTooltipHideDelay", "thyTooltipTrigger", "thyTooltipDisabled", "thyTooltipTemplateContext", "thyTooltipOffset", "thyTooltipPin"], exportAs: ["thyTooltip"] }, { kind: "component", type: i7.ThyActionComponent, selector: "thy-action, [thyAction]", inputs: ["thyType", "thyIcon", "thyActionIcon", "thyActive", "thyActionActive", "thyTheme", "thyHoverIcon", "thyDisabled"] }, { kind: "component", type: i7.ThyActionsComponent, selector: "thy-actions", inputs: ["thySize"] }, { kind: "component", type: i8$1.ThyDividerComponent, selector: "thy-divider", inputs: ["thyVertical", "thyStyle", "thyColor", "thyText", "thyTextDirection", "thyDeeper"] }, { kind: "directive", type: i5.ThyColorPickerDirective, selector: "[thyColorPicker]", inputs: ["thyOffset", "thyHasBackdrop", "thyDefaultColor", "thyTransparentColorSelectable", "thyPresetColors", "thyPlacement", "thyTrigger", "thyShowDelay", "thyHideDelay"], outputs: ["thyPanelOpen", "thyPanelClose"] }] });
12210
12577
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TheTableToolbarComponent, decorators: [{
12211
12578
  type: Component,
12212
- args: [{ selector: 'the-table-toolbar', template: "<thy-actions thySize=\"xxs\">\n <ng-container *ngFor=\"let item of cellMenuList\">\n <a\n *ngIf=\"item.visibility\"\n href=\"javascript:;\"\n thyAction\n [thyActionIcon]=\"item.icon\"\n [thyTooltip]=\"item.name\"\n (mousedown)=\"item.actionHandle()\"\n ></a>\n </ng-container>\n <thy-divider *ngIf=\"hasDivider\" class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"> </thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyTooltip=\"\u5355\u5143\u683C\u80CC\u666F\"\n thyColorPicker\n [(ngModel)]=\"selectedColor\"\n (ngModelChange)=\"changeColor($event)\"\n (mousedown)=\"openColorPanel($event)\"\n thyPlacement=\"bottomLeft\"\n [thyHasBackdrop]=\"false\"\n >\n <thy-icon thyIconName=\"background-tt\" thyIconType=\"twotone\" [thyTwotoneColor]=\"selectedColor\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && !isColumnEqual\"\n thyAction\n thyTooltip=\"\u5217\u7B49\u5BBD\"\n (mousedown)=\"setEquallyColumnHandle($event)\"\n >\n <thy-icon thyIconName=\"table-column-equal-width\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && tableOptions?.showFullscreen\"\n thyAction\n thyTooltip=\"\u5168\u5C4F\"\n (mousedown)=\"setFullscreen($event)\"\n >\n <thy-icon thyIconName=\"arrows-alt\"></thy-icon>\n </a>\n <a\n *ngIf=\"tableStore.isSelectedTable && !tableStore?.isFullscreen\"\n class=\"fullscreen-hidden\"\n href=\"javascript:;\"\n thyAction\n thyActionIcon=\"copy\"\n thyTooltip=\"\u590D\u5236\"\n (mousedown)=\"onCopy($event)\"\n ></a>\n <ng-container *ngIf=\"tableStore.isSelectedTable\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a href=\"javascript:;\" class=\"link-with-down\" thyAction (mousedown)=\"mousedown($event)\" (click)=\"openTableOptionMenu($event)\">\n <span>\u8868\u683C\u9009\u9879</span>\n <thy-icon class=\"font-size-sm text-desc ml-1\" thyIconName=\"caret-down\"></thy-icon>\n </a>\n </ng-container>\n <ng-container *ngIf=\"tableStore?.isFullscreen ? deleteIcon && !tableStore.isSelectedTable : deleteIcon\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyType=\"danger\"\n [thyActionIcon]=\"deleteIcon\"\n [thyTooltip]=\"iconName\"\n (mousedown)=\"onDelete($event)\"\n (mouseenter)=\"onEnterDelete($event)\"\n (mouseleave)=\"onLeaveDelete($event)\"\n ></a>\n </ng-container>\n</thy-actions>\n" }]
12213
- }], ctorParameters: function () { return [{ type: i1$1.ThyPopover }, { type: i1$1.ThyPopoverRef }, { type: i1$2.ThyNotifyService }]; }, propDecorators: { tableStore: [{
12214
- type: Input
12215
- }], tableElement: [{
12216
- type: Input
12217
- }] } });
12218
- var DeleteIcon;
12219
- (function (DeleteIcon) {
12220
- DeleteIcon["table-delete-rows"] = "table-delete-rows";
12221
- DeleteIcon["table-delete-columns"] = "table-delete-columns";
12222
- DeleteIcon["trash"] = "trash";
12223
- })(DeleteIcon || (DeleteIcon = {}));
12224
-
12225
- class TableService {
12226
- get isOpened() {
12227
- return this.toolbarRef && this.toolbarRef.componentInstance;
12228
- }
12229
- constructor(thyPopover, overlay, tableStore, theTableContextMenuService, ngZone, theContextService) {
12230
- this.thyPopover = thyPopover;
12231
- this.overlay = overlay;
12232
- this.tableStore = tableStore;
12233
- this.theTableContextMenuService = theTableContextMenuService;
12234
- this.ngZone = ngZone;
12235
- this.theContextService = theContextService;
12236
- this.backdropClosable = false;
12237
- this.hasBackdrop = false;
12238
- this.insideClosable = false;
12239
- this.placement = 'topLeft';
12240
- this.offset = 8;
12241
- }
12242
- openToolbar(origin, tableElement) {
12243
- if (this.isOpened) {
12244
- if (this.toolbarRef.containerInstance.config.origin === origin) {
12245
- return;
12246
- }
12247
- this.toolbarRef.close();
12248
- }
12249
- this.toolbarRef = this.thyPopover.open(TheTableToolbarComponent, {
12250
- initialState: {
12251
- tableStore: this.tableStore,
12252
- tableElement
12253
- },
12254
- viewContainerRef: this.theContextService.getOptions().viewContainerRef,
12255
- origin: this.getOrigin(origin),
12256
- backdropClosable: this.backdropClosable,
12257
- panelClass: 'the-plugin-toolbar-popover',
12258
- placement: this.placement,
12259
- offset: this.offset,
12260
- hasBackdrop: this.hasBackdrop,
12261
- insideClosable: this.insideClosable,
12262
- minWidth: 0,
12263
- scrollStrategy: this.overlay.scrollStrategies.reposition(),
12264
- manualClosure: true
12265
- });
12266
- if (this.toolbarRef) {
12267
- this.toolbarRef
12268
- .getOverlayRef()
12269
- .outsidePointerEvents()
12270
- .pipe(skip(1))
12271
- .subscribe(event => {
12272
- if (isColorPanel(event.target)) {
12273
- return;
12274
- }
12275
- if (!this.toolbarRef.getOverlayRef().hostElement.contains(event.target)) {
12276
- this.closeToolbar();
12277
- }
12278
- });
12279
- }
12280
- }
12281
- afterSelectedCells(origin, element) {
12282
- this.theTableContextMenuService.closeContextMenu();
12283
- this.openToolbar(origin, element);
12284
- }
12285
- getOrigin(origin) {
12286
- if (origin instanceof HTMLTableCellElement && origin.tagName !== 'TH') {
12287
- const { selectedRowsIndex, selectedColumnsIndex, focusCellPath, isSelectedTable, focusCellElement } = this.tableStore;
12288
- const [row, col] = focusCellPath.slice(-2);
12289
- const tableElement = focusCellElement.closest('.the-table-container');
12290
- if (isSelectedTable && col === 0 && row === 0) {
12291
- return tableElement.querySelector('.the-table-corner-controls');
12292
- }
12293
- if (selectedColumnsIndex.length > 0 && row === 0) {
12294
- return tableElement.querySelectorAll('.the-table-col-controls')[col];
12295
- }
12296
- if (selectedRowsIndex.length > 0 && col === 0) {
12297
- return tableElement.querySelectorAll('.the-table-row-controls-button-wrap')[row];
12298
- }
12299
- }
12300
- return origin;
12301
- }
12302
- closeToolbar() {
12303
- if (this.isOpened) {
12304
- this.ngZone.run(() => {
12305
- this.toolbarRef.close();
12306
- });
12307
- return this.toolbarRef.afterClosed();
12308
- }
12309
- }
12310
- }
12311
- TableService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService, deps: [{ token: i1$1.ThyPopover }, { token: i2$1.Overlay }, { token: TableStore }, { token: TheTableContextMenuService }, { token: i0.NgZone }, { token: TheContextService }], target: i0.ɵɵFactoryTarget.Injectable });
12312
- TableService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService });
12313
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService, decorators: [{
12314
- type: Injectable
12315
- }], ctorParameters: function () { return [{ type: i1$1.ThyPopover }, { type: i2$1.Overlay }, { type: TableStore }, { type: TheTableContextMenuService }, { type: i0.NgZone }, { type: TheContextService }]; } });
12316
-
12317
- function isVirtualKey(e) {
12318
- const isMod = e.ctrlKey || e.metaKey;
12319
- const isAlt = isKeyHotkey('alt', e);
12320
- const isShift = isKeyHotkey('shift', e);
12321
- const isCapsLock = e.key.includes('CapsLock');
12322
- const isTab = e.key.includes('Tab');
12323
- const isEsc = e.key.includes('Escape');
12324
- const isF = e.key.startsWith('F');
12325
- const isArrow = e.key.includes('Arrow') ? true : false;
12326
- return isCapsLock || isMod || isAlt || isArrow || isShift || isTab || isEsc || isF;
12327
- }
12328
-
12329
- class TableFreezeColumnPipe {
12330
- transform(table, tablePluginOptions) {
12331
- const rows = table.children?.map(item => item.children);
12332
- const headerColumnWidth = table.columns && table.columns[0].width;
12333
- const tableComponent = ELEMENT_TO_COMPONENT.get(table);
12334
- let stickyColumn = true;
12335
- let buffer = TABLE_CONTROL;
12336
- if (table.options?.numberedColumn) {
12337
- buffer = TABLE_NUMBER_COLUMN + TABLE_CONTROL;
12338
- }
12339
- if (tableComponent) {
12340
- const tableWidth = getElementWidth(tableComponent.elementRef.nativeElement);
12341
- stickyColumn = headerColumnWidth + buffer < tableWidth;
12342
- }
12343
- // 标题列存在合并的列时,取消冻结
12344
- const mergeColumnCells = rows && rows.map(cells => cells[0]).filter(item => item.colspan && item.colspan !== 1);
12345
- return !!(tablePluginOptions?.freezeColumnHeader && table.options?.headerColumn && !mergeColumnCells.length && stickyColumn);
12346
- }
12347
- }
12348
- TableFreezeColumnPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
12349
- TableFreezeColumnPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, name: "freezeColumn" });
12350
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, decorators: [{
12351
- type: Pipe,
12352
- args: [{ name: 'freezeColumn' }]
12353
- }] });
12354
- class TableFreezeRowPipe {
12355
- transform(table, headerRow, tablePluginOptions) {
12356
- // 标题行存在合并的行时,取消冻结
12357
- if (table.children) {
12358
- const mergeRows = table.children[0]?.children.filter(item => item.rowspan && item.rowspan !== 1);
12359
- return !!(headerRow && !mergeRows.length && tablePluginOptions?.freezeRowHeader);
12360
- }
12361
- return false;
12362
- }
12363
- }
12364
- TableFreezeRowPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
12365
- TableFreezeRowPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, name: "freezeRow" });
12366
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, decorators: [{
12367
- type: Pipe,
12368
- args: [{ name: 'freezeRow' }]
12369
- }] });
12370
-
12371
- /**
12372
- * 获取标题行网格列宽值
12373
- * @param editor
12374
- * @param headerRow 标题行
12375
- * @param cellsWidth
12376
- * @returns string
12377
- */
12378
- const getGridColumns = (headerRow, cellsWidth) => {
12379
- let result = '';
12380
- Array.from(headerRow.childNodes)
12381
- .filter((n) => n.nodeType === 1)
12382
- .forEach((node, i) => {
12383
- const col = node.getAttribute('colspan');
12384
- const display = node.style.display;
12385
- if (display === 'none') {
12386
- return;
12387
- }
12388
- if (col) {
12389
- const colSpan = Number(col) ?? 1;
12390
- let width = 0;
12391
- Array.from({ length: colSpan }, (_, j) => {
12392
- width += cellsWidth[i + j];
12393
- });
12394
- result += width + 'px ';
12395
- }
12396
- else {
12397
- result += cellsWidth[i] + 'px ';
12398
- }
12399
- });
12400
- return result;
12401
- };
12402
- const getColumnsWidth = (cellRow, isColgroup = false) => {
12403
- const result = [];
12404
- Array.from(cellRow.childNodes)
12405
- .filter((n) => n.nodeType === 1)
12406
- .forEach((item) => {
12407
- if (isColgroup && IS_SAFARI) {
12408
- result.push(item.offsetWidth);
12409
- return;
12410
- }
12411
- if (item.getBoundingClientRect) {
12412
- result.push(item.getBoundingClientRect().width);
12413
- }
12414
- });
12415
- return result;
12416
- };
12417
- /**
12418
- * 计算表格列宽
12419
- * @param isReadonly
12420
- * @param element
12421
- * @param tableWidth
12422
- * @param mode
12423
- * @returns number[]
12424
- */
12425
- const calcColumnGroups = (isReadonly, element, tableWidth, mode) => {
12426
- const columns = element?.columns;
12427
- if (isReadonly) {
12428
- if (columns) {
12429
- const opts = new TableOptions();
12430
- const isPrint = mode === TheMode.print;
12431
- const newColumns = isPrint
12432
- ? calcPrintColumnWidth(element, opts.minWidthPx)
12433
- : calcColumnWidth(element, tableWidth, opts.minWidthPx);
12434
- return newColumns;
12435
- }
12436
- return [];
12437
- }
12438
- else {
12439
- return columns;
12440
- }
12441
- };
12442
- /**
12443
- * 计算表格列宽
12444
- * @param element
12445
- * @param tableWidth
12446
- * @param minWidthPx
12447
- * @returns number[]
12448
- */
12449
- const calcColumnWidth = (element, tableWidth, minWidthPx) => {
12450
- const columns = element?.columns;
12451
- const numberedColumnWidth = element?.options?.numberedColumn ? TABLE_NUMBER_COLUMN : 0;
12452
- const columnsWidth = columns.reduce((a, b) => a + b.width, 0);
12453
- // 总列宽大于当前表格宽度时,按照设置时的总列宽计算
12454
- const columnTotalWidth = Math.max(columnsWidth, tableWidth - numberedColumnWidth);
12455
- return columns.map(column => {
12456
- const cellWidth = (column.width / columnsWidth) * columnTotalWidth;
12457
- return { width: Math.max(cellWidth, minWidthPx) };
12458
- });
12459
- };
12460
- /**
12461
- * 打印模式下,按照原宽度比例基于当前表格宽度计算列宽
12462
- * 1. 所有列的最小列宽总和大于表格宽度时,所有列返回最小宽度
12463
- * @param element
12464
- * @param minWidthPx
12465
- * @returns number[]
12466
- */
12467
- const calcPrintColumnWidth = (element, minWidthPx) => {
12468
- const columns = element?.columns;
12469
- const numberedColumnWidth = element?.options?.numberedColumn ? TABLE_NUMBER_COLUMN : 0;
12470
- // 按照 DPI 96 的 A4 纸宽度是 794, 打印时左右 80px 的边距,所以这里取 794 - 80 * 2 = 634
12471
- // 如果存在序号列,还需要在 634 基础上减去序号列的宽度,剩下的才是内容区域的宽度
12472
- let columnTotalWidth = 634 - numberedColumnWidth;
12473
- const columnsWidth = columns.reduce((a, b) => a + b.width, 0);
12474
- // 计算所有列的 minWidth 总和
12475
- const totalMinWidth = minWidthPx * columns.length;
12476
- if (totalMinWidth > columnTotalWidth) {
12477
- // 如果所有列的 minWidth 总和大于 columnTotalWidth,所有列返回最小宽度
12478
- return columns.map(() => ({ width: minWidthPx }));
12479
- }
12480
- // 在剩余的宽度中按比例分配
12481
- const remainingWidth = columnTotalWidth - totalMinWidth;
12482
- const remainingWidthRatio = columns.map(column => column.width / columnsWidth);
12483
- // 为什么减 1, 因为这个宽度是内容区域宽度,但 td 右侧还有一个边框,所以减去 1
12484
- let newColumnsWidth = remainingWidthRatio.map(ratio => minWidthPx + Math.floor(ratio * remainingWidth) - 1);
12485
- return columns.map((_, index) => ({
12486
- width: newColumnsWidth[index]
12487
- }));
12488
- };
12489
-
12490
- /**
12491
- * 计算最小行跨距单元格
12492
- * @param element TableElement
12493
- * @returns
12494
- */
12495
- const calculateMinRowSpanCellForRows = (element) => {
12496
- const cells = element.children.map((row, index) => {
12497
- const noHiddenCells = row.children.filter(cell => !cell.hidden);
12498
- if (noHiddenCells.length > 0) {
12499
- const minRowspan = Math.min.apply(Math, noHiddenCells.map(cell => {
12500
- return cell.rowspan || 1;
12501
- }));
12502
- const cell = row.children.find(item => !item.hidden && (item.rowspan || 1) === minRowspan);
12503
- return {
12504
- cell,
12505
- rowIndex: index
12506
- };
12507
- }
12508
- else {
12509
- return {
12510
- rowIndex: index
12511
- };
12579
+ args: [{ selector: 'the-table-toolbar', template: "<thy-actions thySize=\"xxs\">\n <ng-container *ngFor=\"let item of cellMenuList\">\n <a\n *ngIf=\"item.visibility\"\n href=\"javascript:;\"\n thyAction\n [thyActionIcon]=\"item.icon\"\n [thyTooltip]=\"item.name\"\n (mousedown)=\"item.actionHandle()\"\n ></a>\n </ng-container>\n <thy-divider *ngIf=\"hasDivider\" class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"> </thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyTooltip=\"\u5355\u5143\u683C\u80CC\u666F\"\n thyColorPicker\n [(ngModel)]=\"selectedColor\"\n (ngModelChange)=\"changeColor($event)\"\n (mousedown)=\"openColorPanel($event)\"\n thyPlacement=\"bottomLeft\"\n [thyHasBackdrop]=\"false\"\n >\n <thy-icon thyIconName=\"background-tt\" thyIconType=\"twotone\" [thyTwotoneColor]=\"selectedColor\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && !isColumnEqual\"\n thyAction\n thyTooltip=\"\u5217\u7B49\u5BBD\"\n (mousedown)=\"setEquallyColumnHandle($event)\"\n >\n <thy-icon thyIconName=\"table-column-equal-width\"></thy-icon>\n </a>\n <a\n href=\"javascript:;\"\n *ngIf=\"tableStore.isSelectedTable && tableOptions?.showFullscreen\"\n thyAction\n thyTooltip=\"\u5168\u5C4F\"\n (mousedown)=\"setFullscreen($event)\"\n >\n <thy-icon thyIconName=\"arrows-alt\"></thy-icon>\n </a>\n <a\n *ngIf=\"tableStore.isSelectedTable && !tableStore?.isFullscreen\"\n class=\"fullscreen-hidden\"\n href=\"javascript:;\"\n thyAction\n thyActionIcon=\"copy\"\n thyTooltip=\"\u590D\u5236\"\n (mousedown)=\"onCopy($event)\"\n ></a>\n <ng-container *ngIf=\"tableStore.isSelectedTable\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a href=\"javascript:;\" class=\"link-with-down\" thyAction (mousedown)=\"mousedown($event)\" (click)=\"openTableOptionMenu($event)\">\n <span>\u8868\u683C\u9009\u9879</span>\n <thy-icon class=\"font-size-sm text-desc ml-1\" thyIconName=\"caret-down\"></thy-icon>\n </a>\n </ng-container>\n <ng-container *ngIf=\"tableStore?.isFullscreen ? deleteIcon && !tableStore.isSelectedTable : deleteIcon\">\n <thy-divider class=\"mr-2 ml-1 align-self-center\" [thyVertical]=\"true\"></thy-divider>\n <a\n href=\"javascript:;\"\n thyAction\n thyType=\"danger\"\n [thyActionIcon]=\"deleteIcon\"\n [thyTooltip]=\"iconName\"\n (mousedown)=\"onDelete($event)\"\n (mouseenter)=\"onEnterDelete($event)\"\n (mouseleave)=\"onLeaveDelete($event)\"\n ></a>\n </ng-container>\n</thy-actions>\n" }]
12580
+ }], ctorParameters: function () { return [{ type: i1$1.ThyPopover }, { type: i1$1.ThyPopoverRef }, { type: i1$2.ThyNotifyService }]; }, propDecorators: { tableStore: [{
12581
+ type: Input
12582
+ }], tableElement: [{
12583
+ type: Input
12584
+ }] } });
12585
+ var DeleteIcon;
12586
+ (function (DeleteIcon) {
12587
+ DeleteIcon["table-delete-rows"] = "table-delete-rows";
12588
+ DeleteIcon["table-delete-columns"] = "table-delete-columns";
12589
+ DeleteIcon["trash"] = "trash";
12590
+ })(DeleteIcon || (DeleteIcon = {}));
12591
+
12592
+ class TableService {
12593
+ get isOpened() {
12594
+ return this.toolbarRef && this.toolbarRef.componentInstance;
12595
+ }
12596
+ constructor(thyPopover, overlay, tableStore, ngZone, theContextService) {
12597
+ this.thyPopover = thyPopover;
12598
+ this.overlay = overlay;
12599
+ this.tableStore = tableStore;
12600
+ this.ngZone = ngZone;
12601
+ this.theContextService = theContextService;
12602
+ this.backdropClosable = false;
12603
+ this.hasBackdrop = false;
12604
+ this.insideClosable = false;
12605
+ this.placement = 'topLeft';
12606
+ this.offset = 8;
12607
+ }
12608
+ openToolbar(origin, tableElement) {
12609
+ if (this.isOpened) {
12610
+ if (this.toolbarRef.containerInstance.config.origin === origin) {
12611
+ return;
12612
+ }
12613
+ this.toolbarRef.close();
12512
12614
  }
12513
- });
12514
- return cells;
12515
- };
12516
- /**
12517
- * 计算行控件的平均高度
12518
- * @param previousCombineRowIndex
12519
- * @param previousRowIndex
12520
- * @param rowControls
12521
- */
12522
- const calculateRowControlsAvgHeight = (previousCombineRowIndex, previousRowIndex, rowControls) => {
12523
- const rowControl = rowControls[previousRowIndex];
12524
- const count = previousCombineRowIndex - previousRowIndex;
12525
- const avgHeight = Math.floor(rowControl.height / (count + 1));
12526
- const firstHeight = rowControl.height - avgHeight * count;
12527
- rowControl.height = firstHeight;
12528
- rowControls
12529
- .filter((_, index) => index > previousRowIndex && index <= previousCombineRowIndex)
12530
- .forEach(rowControl => {
12531
- rowControl.height = avgHeight;
12532
- });
12533
- };
12534
- const getBelowRowHeight = (editor, cells, index, rowIndex, rowspan) => {
12535
- let belowRowlHeight = 0;
12536
- cells.slice(index + 1, cells.length).map(item => {
12537
- if (!item.cell) {
12538
- return;
12615
+ this.toolbarRef = this.thyPopover.open(TheTableToolbarComponent, {
12616
+ initialState: {
12617
+ tableStore: this.tableStore,
12618
+ tableElement
12619
+ },
12620
+ viewContainerRef: this.theContextService.getOptions().viewContainerRef,
12621
+ origin: this.getOrigin(origin),
12622
+ backdropClosable: this.backdropClosable,
12623
+ panelClass: 'the-plugin-toolbar-popover',
12624
+ placement: this.placement,
12625
+ offset: this.offset,
12626
+ hasBackdrop: this.hasBackdrop,
12627
+ insideClosable: this.insideClosable,
12628
+ minWidth: 0,
12629
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
12630
+ manualClosure: true
12631
+ });
12632
+ if (this.toolbarRef) {
12633
+ this.toolbarRef
12634
+ .getOverlayRef()
12635
+ .outsidePointerEvents()
12636
+ .pipe(skip(1))
12637
+ .subscribe(event => {
12638
+ if (isColorPanel(event.target)) {
12639
+ return;
12640
+ }
12641
+ if (!this.toolbarRef.getOverlayRef().hostElement.contains(event.target)) {
12642
+ this.closeToolbar();
12643
+ }
12644
+ });
12539
12645
  }
12540
- if (rowIndex + rowspan > item.rowIndex) {
12541
- const cellDom = AngularEditor.toDOMNode(editor, item.cell);
12542
- if (item.cell.rowspan > 1) {
12543
- // 如果下方单元格的rowspan > 1,递归计算
12544
- const height = getBelowRowHeight(editor, cells, cells.findIndex(cell => cell.rowIndex === item.rowIndex), item.rowIndex, item.cell.rowspan);
12545
- belowRowlHeight += getElementHeight(cellDom) - height;
12646
+ }
12647
+ afterSelectedCells(origin, element) {
12648
+ this.openToolbar(origin, element);
12649
+ }
12650
+ getOrigin(origin) {
12651
+ if (origin instanceof HTMLTableCellElement && origin.tagName !== 'TH') {
12652
+ const { selectedRowsIndex, selectedColumnsIndex, focusCellPath, isSelectedTable, focusCellElement } = this.tableStore;
12653
+ const [row, col] = focusCellPath.slice(-2);
12654
+ const tableElement = focusCellElement.closest('.the-table-container');
12655
+ if (isSelectedTable && col === 0 && row === 0) {
12656
+ return tableElement.querySelector('.the-table-corner-controls');
12546
12657
  }
12547
- else {
12548
- belowRowlHeight += getElementHeight(cellDom);
12658
+ if (selectedColumnsIndex.length > 0 && row === 0) {
12659
+ return tableElement.querySelectorAll('.the-table-col-controls')[col];
12660
+ }
12661
+ if (selectedRowsIndex.length > 0 && col === 0) {
12662
+ return tableElement.querySelectorAll('.the-table-row-controls-button-wrap')[row];
12549
12663
  }
12550
12664
  }
12551
- });
12552
- return belowRowlHeight;
12553
- };
12554
- const calculateRowControls = (editor, element) => {
12555
- const minRowSpanCellForRows = calculateMinRowSpanCellForRows(element);
12556
- const rowControls = [];
12557
- let previousRowIndex = 0;
12558
- let previousCombineRowIndex = 0;
12559
- minRowSpanCellForRows.forEach((cellInfo, index) => {
12560
- if (!cellInfo.cell) {
12561
- rowControls.push({
12562
- height: 0,
12563
- rowIndex: index
12665
+ return origin;
12666
+ }
12667
+ closeToolbar() {
12668
+ if (this.isOpened) {
12669
+ this.ngZone.run(() => {
12670
+ this.toolbarRef.close();
12564
12671
  });
12565
- previousCombineRowIndex = index;
12566
- if (index === minRowSpanCellForRows.length - 1) {
12567
- calculateRowControlsAvgHeight(previousCombineRowIndex, previousRowIndex, rowControls);
12568
- }
12569
- return;
12672
+ return this.toolbarRef.afterClosed();
12570
12673
  }
12571
- // calculate combine row height
12572
- if (previousCombineRowIndex > previousRowIndex) {
12573
- calculateRowControlsAvgHeight(previousCombineRowIndex, previousRowIndex, rowControls);
12574
- previousCombineRowIndex = 0;
12674
+ }
12675
+ /**
12676
+ * 判断是否触发了点选,并处理点选状态
12677
+ * @param e 事件对象
12678
+ * @param tbody tbody元素
12679
+ */
12680
+ handleKeydownForPointerSelection(e, tbody) {
12681
+ const cell = tbody?.querySelector('.focused-cell') || this.tableStore.focusCellElement;
12682
+ if (cell) {
12683
+ this.tableStore.pointerSelection = true;
12684
+ this.tableStore.selectCellStart(cell, this.tableStore.editor);
12575
12685
  }
12576
- const cellDom = AngularEditor.toDOMNode(editor, cellInfo.cell);
12577
- let height = getElementHeight(cellDom);
12578
- // 当cell为合并的单元格(rowspan > 1),计算其实际高度(当前单元格的高度 - 下方合并单元格的高度)
12579
- if (cellInfo.cell.rowspan > 1) {
12580
- const calcHeight = height - getBelowRowHeight(editor, minRowSpanCellForRows, index, cellInfo.rowIndex, cellInfo.cell.rowspan);
12581
- rowControls.push({
12582
- height: calcHeight,
12583
- rowIndex: cellInfo.rowIndex
12584
- });
12686
+ }
12687
+ /**
12688
+ * 判断是否触发了区域选择,并处理区域选择状态
12689
+ * @param e 事件对象
12690
+ * @param tbody tbody元素
12691
+ */
12692
+ handleKeydownForAreaSelection(e, tbody) {
12693
+ const isTable = TableEditor.isActive(this.tableStore.editor);
12694
+ const cell = tbody?.querySelector('.focused-cell') || this.tableStore.focusCellElement;
12695
+ if (isTable && cell) {
12696
+ this.tableStore.areaSelectionStart(cell, this.tableStore.editor);
12697
+ this.tableStore.areaSelection = true;
12585
12698
  }
12586
- else {
12587
- rowControls.push({
12588
- height,
12589
- rowIndex: cellInfo.rowIndex
12590
- });
12699
+ }
12700
+ cancelPointerSelection() {
12701
+ if (this.tableStore.pointerSelection) {
12702
+ this.tableStore.pointerSelection = false;
12591
12703
  }
12592
- previousRowIndex = index;
12593
- });
12594
- return rowControls;
12595
- };
12704
+ }
12705
+ cancelAreaSelection() {
12706
+ if (this.tableStore.areaSelection) {
12707
+ this.tableStore.areaSelection = false;
12708
+ this.tableStore.selectCellEnd(this.tableStore.editor);
12709
+ }
12710
+ }
12711
+ /**
12712
+ * 进行区域选择时,阻止默认的选区事件
12713
+ * @param e 事件对象
12714
+ * @param editor 编辑器对象
12715
+ */
12716
+ selectStartPreventDefault(e) {
12717
+ const isReadonly = AngularEditor.isReadonly(this.tableStore.editor);
12718
+ const cells = this.tableStore.getSelectedCellPositions();
12719
+ if (!isReadonly && this.tableStore.areaSelection && cells.length > 1) {
12720
+ e.preventDefault();
12721
+ }
12722
+ }
12723
+ }
12724
+ TableService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService, deps: [{ token: i1$1.ThyPopover }, { token: i2$1.Overlay }, { token: TableStore }, { token: i0.NgZone }, { token: TheContextService }], target: i0.ɵɵFactoryTarget.Injectable });
12725
+ TableService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService });
12726
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableService, decorators: [{
12727
+ type: Injectable
12728
+ }], ctorParameters: function () { return [{ type: i1$1.ThyPopover }, { type: i2$1.Overlay }, { type: TableStore }, { type: i0.NgZone }, { type: TheContextService }]; } });
12596
12729
 
12597
- /**
12598
- * compatible with old data
12599
- * @returns
12600
- */
12601
- function isHeaderRow(element) {
12602
- if (element?.options?.headerRow) {
12603
- return true;
12730
+ class TableFreezeColumnPipe {
12731
+ transform(table, tablePluginOptions) {
12732
+ const rows = table.children?.map(item => item.children);
12733
+ const headerColumnWidth = table.columns && table.columns[0].width;
12734
+ const tableComponent = ELEMENT_TO_COMPONENT.get(table);
12735
+ let stickyColumn = true;
12736
+ let buffer = TABLE_CONTROL;
12737
+ if (table.options?.numberedColumn) {
12738
+ buffer = TABLE_NUMBER_COLUMN + TABLE_CONTROL;
12739
+ }
12740
+ if (tableComponent) {
12741
+ const tableWidth = getElementWidth(tableComponent.elementRef.nativeElement);
12742
+ stickyColumn = headerColumnWidth + buffer < tableWidth;
12743
+ }
12744
+ // 标题列存在合并的列时,取消冻结
12745
+ const mergeColumnCells = rows && rows.map(cells => cells[0]).filter(item => item.colspan && item.colspan !== 1);
12746
+ return !!(tablePluginOptions?.freezeColumnHeader && table.options?.headerColumn && !mergeColumnCells.length && stickyColumn);
12604
12747
  }
12605
- // compat old data
12606
- if (element?.children[0].header) {
12607
- return true;
12748
+ }
12749
+ TableFreezeColumnPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
12750
+ TableFreezeColumnPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, name: "freezeColumn" });
12751
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeColumnPipe, decorators: [{
12752
+ type: Pipe,
12753
+ args: [{ name: 'freezeColumn' }]
12754
+ }] });
12755
+ class TableFreezeRowPipe {
12756
+ transform(table, headerRow, tablePluginOptions) {
12757
+ // 标题行存在合并的行时,取消冻结
12758
+ if (table.children) {
12759
+ const mergeRows = table.children[0]?.children.filter(item => item.rowspan && item.rowspan !== 1);
12760
+ return !!(headerRow && !mergeRows.length && tablePluginOptions?.freezeRowHeader);
12761
+ }
12762
+ return false;
12608
12763
  }
12609
12764
  }
12765
+ TableFreezeRowPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
12766
+ TableFreezeRowPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, name: "freezeRow" });
12767
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableFreezeRowPipe, decorators: [{
12768
+ type: Pipe,
12769
+ args: [{ name: 'freezeRow' }]
12770
+ }] });
12610
12771
 
12611
12772
  const TABLE_SELECTOR = '.the-table';
12612
12773
  const TABLE_WRAPPER_SELECTOR = '.the-table-wrapper';
@@ -12676,6 +12837,10 @@ class TheColumnResizeDirective {
12676
12837
  merge(this.resizeNotifier.resizeCanceled, this.resizeNotifier.resizeCompleted)
12677
12838
  .pipe(takeUntil(this.destroyed))
12678
12839
  .subscribe(() => {
12840
+ // 如果没有进行拖拽就不要进行后续表格宽高计算了
12841
+ if (!this.resizeStarted) {
12842
+ return;
12843
+ }
12679
12844
  this.resizeStarted = false;
12680
12845
  if (this.position === Position.left || this.position === Position.right) {
12681
12846
  this.theTableComponent.transformColumnsWidth();
@@ -12907,8 +13072,10 @@ class TheTableComponent extends TheBaseElementComponent {
12907
13072
  this.subscribeCellPositionChange();
12908
13073
  this.listenTableContextMenuEvent();
12909
13074
  this.listenOnSelectedCells();
12910
- this.listenKeydownSelectEvents();
13075
+ this.listenKeydownEvent();
13076
+ this.listenKeyupEvent();
12911
13077
  this.listenTableWrapperScroll();
13078
+ this.listenSelectstartEvent();
12912
13079
  this.getColumnGroups();
12913
13080
  this.bindTableScrollingShadow();
12914
13081
  if (this.element.options?.numberedColumn) {
@@ -13405,7 +13572,7 @@ class TheTableComponent extends TheBaseElementComponent {
13405
13572
  this.tableStore.clearSelectedCellsContent();
13406
13573
  }
13407
13574
  const isCurrentTableElement = this.nativeElement.contains(e.target);
13408
- if (!isCurrentTableElement || !this.tableStore.pointerSelection) {
13575
+ if (!isCurrentTableElement || (!this.tableStore.pointerSelection && !this.tableStore.areaSelection)) {
13409
13576
  this.tableStore.clearSelectedCells();
13410
13577
  }
13411
13578
  if (!isCurrentTableElement) {
@@ -13414,21 +13581,36 @@ class TheTableComponent extends TheBaseElementComponent {
13414
13581
  this.theTableContextMenuService.closeContextMenu();
13415
13582
  });
13416
13583
  }
13417
- listenKeydownSelectEvents() {
13584
+ listenKeydownEvent() {
13418
13585
  this.ngZone.runOutsideAngular(() => {
13419
13586
  fromEvent(document, 'keydown')
13420
13587
  .pipe(takeUntil(this.destroy$), filter((e) => !!e))
13421
13588
  .subscribe((event) => {
13422
- if (isKeyHotkey('mod', event) && !this.readonly) {
13423
- this.tableStore.pointerSelection = true;
13424
- const cell = this.tbodyElement.nativeElement.querySelector('.focused-cell');
13425
- cell && this.tableStore.selectCellStart(cell, this.editor);
13589
+ if (!this.readonly && isKeyHotkey('mod', event)) {
13590
+ this.tableService.handleKeydownForPointerSelection(event, this.tbodyNativeElement);
13591
+ }
13592
+ if (!this.readonly && isKeyHotkey('shift', event)) {
13593
+ this.tableService.handleKeydownForAreaSelection(event, this.tbodyNativeElement);
13426
13594
  }
13427
13595
  });
13596
+ });
13597
+ }
13598
+ listenKeyupEvent() {
13599
+ this.ngZone.runOutsideAngular(() => {
13428
13600
  fromEvent(document, 'keyup')
13429
13601
  .pipe(takeUntil(this.destroy$), filter((e) => !!e))
13430
13602
  .subscribe(() => {
13431
- this.tableStore.pointerSelection = false;
13603
+ this.tableService.cancelPointerSelection();
13604
+ this.tableService.cancelAreaSelection();
13605
+ });
13606
+ });
13607
+ }
13608
+ listenSelectstartEvent() {
13609
+ this.ngZone.runOutsideAngular(() => {
13610
+ fromEvent(document, 'selectstart')
13611
+ .pipe(takeUntil(this.destroy$))
13612
+ .subscribe((event) => {
13613
+ this.tableService.selectStartPreventDefault(event);
13432
13614
  });
13433
13615
  });
13434
13616
  }
@@ -14039,19 +14221,19 @@ const POSITION_MAP = {
14039
14221
  };
14040
14222
  class TheTdComponent extends TheBaseElementComponent {
14041
14223
  get tableStore() {
14042
- return this.tableComponent.tableStore;
14224
+ return this.tableComponent?.tableStore;
14043
14225
  }
14044
14226
  get tableService() {
14045
- return this.tableComponent.tableService;
14227
+ return this.tableComponent?.tableService;
14046
14228
  }
14047
14229
  get eventDispatcher() {
14048
- return this.tableComponent.eventDispatcher;
14230
+ return this.tableComponent?.eventDispatcher;
14049
14231
  }
14050
14232
  get resizeNotifier() {
14051
- return this.tableComponent.resizeNotifier;
14233
+ return this.tableComponent?.resizeNotifier;
14052
14234
  }
14053
14235
  get tableElement() {
14054
- return this.tableComponent.theTableElement.nativeElement;
14236
+ return this.tableComponent?.theTableElement?.nativeElement;
14055
14237
  }
14056
14238
  get scrollableElementTop() {
14057
14239
  const containerElement = this.elementRef.nativeElement.closest(this.editor.options?.scrollContainer || DEFAULT_SCROLL_CONTAINER);
@@ -14071,7 +14253,7 @@ class TheTdComponent extends TheBaseElementComponent {
14071
14253
  return this.tableComponent.tableWrapper.nativeElement.scrollLeft;
14072
14254
  }
14073
14255
  get isXAxisHover() {
14074
- return [Position.left, Position.right].includes(this.hoverdDirection);
14256
+ return [Position.left, Position.right].includes(this.hoveredDirection);
14075
14257
  }
14076
14258
  get rowResizeClass() {
14077
14259
  return [
@@ -14103,11 +14285,7 @@ class TheTdComponent extends TheBaseElementComponent {
14103
14285
  }
14104
14286
  ngOnInit() {
14105
14287
  super.ngOnInit();
14106
- this.useBackground();
14107
- this.useSpan();
14108
- this.useDisplay();
14109
- this.useFocus();
14110
- useElementStyle(this.elementRef.nativeElement, this.element);
14288
+ this.useState();
14111
14289
  }
14112
14290
  ngAfterViewInit() {
14113
14291
  this.ngZone.onStable.pipe(take(1)).subscribe(() => {
@@ -14220,16 +14398,22 @@ class TheTdComponent extends TheBaseElementComponent {
14220
14398
  fromEvent(element, 'mousedown')
14221
14399
  .pipe(takeUntil(this.destroy$), filter((e) => e.button !== 2), map$1(event => event.target.closest(SLA_TABLE_CELL_SELECTOR)), filter(cell => !!cell))
14222
14400
  .subscribe((cell) => {
14223
- // 点选
14224
- if (this.tableStore.pointerSelection) {
14225
- this.tableStore.selectCell(cell, this.editor);
14226
- }
14227
- this.tableStore.selectCellStart(cell, this.editor);
14228
- if (this.overlayRef) {
14229
- this.overlayRef.detach();
14401
+ if (!this.readonly) {
14402
+ if (this.tableStore.pointerSelection) {
14403
+ this.tableStore.selectCell(cell, this.editor);
14404
+ }
14405
+ if (this.tableStore.areaSelection) {
14406
+ this.tableStore.setAreaSelectionCells(this.element);
14407
+ }
14408
+ else {
14409
+ this.tableStore.selectCellStart(cell, this.editor);
14410
+ }
14411
+ if (this.overlayRef) {
14412
+ this.overlayRef.detach();
14413
+ }
14414
+ // 拖选
14415
+ this.listenCellMouseEvents();
14230
14416
  }
14231
- // 拖选
14232
- this.listenCellMouseEvents();
14233
14417
  });
14234
14418
  });
14235
14419
  }
@@ -14245,14 +14429,16 @@ class TheTdComponent extends TheBaseElementComponent {
14245
14429
  this.tableStore.selectCellOngoing(cell, this.editor);
14246
14430
  });
14247
14431
  fromEvent(document, 'mouseup')
14248
- .pipe(take(1))
14432
+ .pipe(take(1), takeUntil(this.destroy$))
14249
14433
  .subscribe(() => {
14250
- this.tableStore.selectCellEnd(this.editor);
14251
14434
  if (this.tableStore.isCellSelecting || this.tableStore.pointerSelection) {
14252
14435
  this.ngZone.run(() => {
14253
14436
  this.tableComponent.tableService.afterSelectedCells(this.tableStore.focusCellElement, this.tableComponent.element);
14254
14437
  });
14255
14438
  }
14439
+ if (!this.tableStore.areaSelection) {
14440
+ this.tableStore.selectCellEnd(this.editor);
14441
+ }
14256
14442
  mouseoverObservable.unsubscribe();
14257
14443
  });
14258
14444
  }
@@ -14274,13 +14460,13 @@ class TheTdComponent extends TheBaseElementComponent {
14274
14460
  }))
14275
14461
  .subscribe(hoveredCellInfo => {
14276
14462
  if (hoveredCellInfo && hoveredCellInfo.position) {
14277
- this.hoverdDirection = hoveredCellInfo.position;
14463
+ this.hoveredDirection = hoveredCellInfo.position;
14278
14464
  }
14279
14465
  else {
14280
- this.hoverdDirection = null;
14466
+ this.hoveredDirection = null;
14281
14467
  }
14282
14468
  if (hoveredCellInfo) {
14283
- this.hoverdDirection = hoveredCellInfo.position;
14469
+ this.hoveredDirection = hoveredCellInfo.position;
14284
14470
  if (!this.overlayRef || !this.overlayRef.hasAttached()) {
14285
14471
  this.overlayRef = this._createOverlayForHandle();
14286
14472
  this._showHandleOverlay();
@@ -14300,16 +14486,20 @@ class TheTdComponent extends TheBaseElementComponent {
14300
14486
  merge(this.resizeNotifier.resizeCanceled, this.resizeNotifier.triggerResize)
14301
14487
  .pipe(takeUntilDestroyed, filter(columnSize => columnSize.tableCell === this.elementRef.nativeElement))
14302
14488
  .subscribe(({ deltaSize, previousSize, completeImmediately }) => {
14489
+ // 如果偏移的值不存在就不要进行后续的计算了
14490
+ if (isUndefined(deltaSize) || isUndefined(previousSize)) {
14491
+ return;
14492
+ }
14303
14493
  const { top, left, height, width } = this.elementRef.nativeElement.getBoundingClientRect();
14304
14494
  const { clientY, clientX } = event;
14305
14495
  let isPreventApplySize = false;
14306
14496
  // 向下,或者向右移动(deltaSize > 0),鼠标位置不在当前单元格拖拽线上,阻止应用拖拽尺寸
14307
14497
  if (this.isXAxisHover) {
14308
- const cellWidth = this.hoverdDirection === Position.left ? 0 : width;
14498
+ const cellWidth = this.hoveredDirection === Position.left ? 0 : width;
14309
14499
  isPreventApplySize = deltaSize > 0 && left + cellWidth - clientX > 0;
14310
14500
  }
14311
14501
  else {
14312
- const cellHeight = this.hoverdDirection === Position.top ? 0 : height;
14502
+ const cellHeight = this.hoveredDirection === Position.top ? 0 : height;
14313
14503
  isPreventApplySize = deltaSize > 0 && top + cellHeight - clientY > 0;
14314
14504
  }
14315
14505
  if (isPreventApplySize) {
@@ -14358,7 +14548,7 @@ class TheTdComponent extends TheBaseElementComponent {
14358
14548
  this.isXAxisHover ? this.updateOverlayHandleColumnSize() : this.updateOverlayHandleRowSize();
14359
14549
  this.overlayRef?.updatePositionStrategy(this.createPositionStrategy());
14360
14550
  this.resizeRef.setDirection(this.isXAxisHover ? 'X' : 'Y');
14361
- this.resizeRef.setPosition(this.hoverdDirection);
14551
+ this.resizeRef.setPosition(this.hoveredDirection);
14362
14552
  }
14363
14553
  updateOverlayHandleColumnSize() {
14364
14554
  let height = 0;
@@ -14433,8 +14623,8 @@ class TheTdComponent extends TheBaseElementComponent {
14433
14623
  let offsetY = this.calculateOverlayHandleOffsetY();
14434
14624
  let offsetX = this.calculateOverlayHandleOffsetX();
14435
14625
  const position = this.isXAxisHover
14436
- ? { ...POSITION_MAP[this.hoverdDirection], offsetY }
14437
- : { ...POSITION_MAP[this.hoverdDirection], offsetX };
14626
+ ? { ...POSITION_MAP[this.hoveredDirection], offsetY }
14627
+ : { ...POSITION_MAP[this.hoveredDirection], offsetX };
14438
14628
  return this.overlay
14439
14629
  .position()
14440
14630
  .flexibleConnectedTo(this.elementRef.nativeElement)
@@ -14470,7 +14660,7 @@ class TheTdComponent extends TheBaseElementComponent {
14470
14660
  this.resizingStore.storeTableWidth(cols);
14471
14661
  this.resizingStore.initDirection(deltaX);
14472
14662
  let cellIndex = this.elementRef.nativeElement.cellIndex;
14473
- if (this.hoverdDirection === 'left') {
14663
+ if (this.hoveredDirection === 'left') {
14474
14664
  cellIndex = cellIndex - 1;
14475
14665
  }
14476
14666
  const colspan = this.elementRef.nativeElement.getAttribute('colspan') || 1;
@@ -14564,7 +14754,7 @@ class TheTdComponent extends TheBaseElementComponent {
14564
14754
  this.resizingStore.storeTableHeight(rows);
14565
14755
  this.resizingStore.initDirection(deltaY, this.isXAxisHover);
14566
14756
  let rowIndex = this.elementRef.nativeElement.parentElement.rowIndex - 1; // subtract thead's tr
14567
- if (this.hoverdDirection === Position.top) {
14757
+ if (this.hoveredDirection === Position.top) {
14568
14758
  rowIndex = rowIndex - 1;
14569
14759
  }
14570
14760
  const rowSpan = this.elementRef.nativeElement.rowSpan;
@@ -16432,5 +16622,5 @@ const withTestPlugin = (plugins, initValue) => {
16432
16622
  * Generated bundle index. Do not edit.
16433
16623
  */
16434
16624
 
16435
- export { ALIGN_BLOCK_TYPES, A_TAG_REL_ATTR, AlignEditor, Alignment, BLOCK_DELETE_BACKWARD_TYPES, BlockquoteEditor, CLIPBOARD_FORMAT_KEY, CODEMIRROR_PADDING_TOP, CODE_MODES, COMPONENTS, CONTAINER_BLOCKS, CONTROL_KEY, CodeEditor, ColorEditor, ColumnResizeNotifierSource, DEFAULT_LANGUAGE, DEFAULT_SCROLL_CONTAINER, DISABLED_OPERATE_TYPES, DefaultElementOptions, DefaultGlobalToolbarDefinition, DefaultInlineToolbarDefinition, DefaultPluginMenu, DropdownMode, ELEMENT_UNIQUE_ID, ElementKinds, ErrorCodes, FontSizeTypes, FontSizes, HEADING_TYPES, HeadingEditor, HoveredCellInfo, HrEditor, IS_MAC, ImageEditor, IndentEditor, Indents, InlineCodeEditor, LINK_DEFAULT_TEXT, LIST_BLOCK_TYPES, LayoutTypes, LinkEditor, ListEditor, MarkEditor, MarkProps, MarkTypes, MentionEditor, PICTURE_ACCEPTED_UPLOAD_MIME, PICTURE_ACCEPTED_UPLOAD_SIZE, PLUGIN_COMPONENTS, PluginKeys, PluginMenuIcons, PluginMenuSvgs, Position, QuickInsertEditor, STANDARD_HEADING_TYPES, ScrollDirection, SpecialBackgroundColor, TAB_SPACE, THE_EDITOR_CONVERSION_HINT_REF, THE_EDITOR_ORIGIN_ANCHOR, THE_EDITOR_POPOVER_REF, THE_EDITOR_PREVIOUS_SELECTION, THE_EDITOR_UUID, THE_INLINE_TOOLBAR_TYPES, THE_LISTBOX_PARENT_GROUP_TOKEN, THE_LISTBOX_PARENT_OPTION_TOKEN, THE_LISTBOX_TOKEN, THE_MODE_PROVIDER, THE_MODE_TOKEN, THE_PLUGIN_MENU_REF, THE_UPLOAD_SERVICE_TOKEN, TableCellEventDispatcher, TableEditor, TableHeaderBackgroundColor, TheBaseElementComponent, TheBaseSuggestion, TheBaseToolbarDropdown, TheBaseToolbarItem, TheContextService, TheDataMode, TheDefaultElementComponent, TheEditor, TheEditorComponent, TheEditorModule, TheImageComponent, TheListboxDirective, TheListboxGroupDirective, TheListboxOptionDirective, TheMode, TheModeConfig, ThePluginMenu, ThePluginMenuComponent, ThePluginMenuItemType, ThePreventDefaultDirective, index$1 as TheQueries, TheToolbarComponent, TheToolbarDropdownComponent, TheToolbarGroupComponent, TheToolbarGroupToken, TheToolbarItemComponent, TheToolbarService, index as TheTransforms, TodoItemEditor, ToolbarActionTypes, ToolbarAlignment, ToolbarItemType, ToolbarMoreGroup, VOID_BLOCK_TYPES, VerticalAlignEditor, VerticalAlignment, ZERO_WIDTH_CHAR, autoFocus, base64toBlob, buildPluginMenu, buildPluginMenuItemMap, coercePixelsFromCssValue, combinePlugins, copyNode, copyNodeForSafari, createEmptyParagraph, createMentionPlugin, createPluginFactory, createToolbar, createVerticalAlignPlugin, dataDeserialize, dataSerializing, deleteElementKey, extractFragment, filterTextFormat, flattenDeepPlugins, getColsTotalWidth, getEditorUUID, getElementClassByPrefix, getElementHeight, getElementWidth, getEndBlock, getPlugin, getPluginOptions, getPlugins, getRowsTotalHeight, getStartBlock, getToolbarClass, headingOptions, htmlToTheia, idCreator, inValidTypes, initializeDefaultMenuIcons, insertDataByInvalidType, internalPlugins, isCleanEmptyParagraph, isDirectionKeydown, isPureEmptyParagraph, mergeArray, mergeDeepPlugins, mergeElementOptions, mergeOptions, nestedStructureByKey, plainToTheia, pluginsByKey, reSelection, recursionNodes, refocus, scrollIntoView, setEditorUUID, useElementStyle, withMention, withTestPlugin, withTheia };
16625
+ export { ALIGN_BLOCK_TYPES, A_TAG_REL_ATTR, AlignEditor, Alignment, BLOCK_DELETE_BACKWARD_TYPES, BlockquoteEditor, CLIPBOARD_FORMAT_KEY, CODEMIRROR_PADDING_TOP, CODE_MODES, COMPONENTS, CONTAINER_BLOCKS, CONTROL_KEY, CodeEditor, ColorEditor, ColumnResizeNotifierSource, DEFAULT_LANGUAGE, DEFAULT_SCROLL_CONTAINER, DISABLED_OPERATE_TYPES, DefaultElementOptions, DefaultGlobalToolbarDefinition, DefaultInlineToolbarDefinition, DefaultPluginMenu, DropdownMode, ELEMENT_UNIQUE_ID, ElementKinds, ErrorCodes, FontSizeTypes, FontSizes, HEADING_TYPES, HeadingEditor, HoveredCellInfo, HrEditor, IS_MAC, ImageEditor, IndentEditor, Indents, InlineCodeEditor, LINK_DEFAULT_TEXT, LIST_BLOCK_TYPES, LayoutTypes, LinkEditor, ListEditor, MarkEditor, MarkProps, MarkTypes, MentionEditor, PICTURE_ACCEPTED_UPLOAD_MIME, PICTURE_ACCEPTED_UPLOAD_SIZE, PLUGIN_COMPONENTS, PluginKeys, PluginMenuIcons, PluginMenuSvgs, Position, QuickInsertEditor, STANDARD_HEADING_TYPES, ScrollDirection, SpecialBackgroundColor, TAB_SPACE, THE_EDITOR_CONVERSION_HINT_REF, THE_EDITOR_ORIGIN_ANCHOR, THE_EDITOR_POPOVER_REF, THE_EDITOR_PREVIOUS_SELECTION, THE_EDITOR_UUID, THE_INLINE_TOOLBAR_TYPES, THE_LISTBOX_PARENT_GROUP_TOKEN, THE_LISTBOX_PARENT_OPTION_TOKEN, THE_LISTBOX_TOKEN, THE_MODE_PROVIDER, THE_MODE_TOKEN, THE_PLUGIN_MENU_REF, THE_UPLOAD_SERVICE_TOKEN, TableCellEventDispatcher, TableEditor, TableHeaderBackgroundColor, TheBaseElementComponent, TheBaseSuggestion, TheBaseToolbarDropdown, TheBaseToolbarItem, TheContextService, TheDataMode, TheDefaultElementComponent, TheEditor, TheEditorComponent, TheEditorModule, TheImageComponent, TheListboxDirective, TheListboxGroupDirective, TheListboxOptionDirective, TheMode, TheModeConfig, ThePluginMenu, ThePluginMenuComponent, ThePluginMenuItemType, ThePreventDefaultDirective, index$1 as TheQueries, TheToolbarComponent, TheToolbarDropdownComponent, TheToolbarGroupComponent, TheToolbarGroupToken, TheToolbarItemComponent, TheToolbarService, index as TheTransforms, TodoItemEditor, ToolbarActionTypes, ToolbarAlignment, ToolbarItemType, ToolbarMoreGroup, VOID_BLOCK_TYPES, VerticalAlignEditor, VerticalAlignment, ZERO_WIDTH_CHAR, autoFocus, base64toBlob, buildPluginMenu, buildPluginMenuItemMap, coercePixelsFromCssValue, combinePlugins, copyNode, copyNodeForSafari, createEmptyParagraph, createMentionPlugin, createPluginFactory, createToolbar, createVerticalAlignPlugin, dataDeserialize, dataSerializing, deleteElementKey, extractFragment, filterTextFormat, flattenDeepPlugins, getColsTotalWidth, getEditorUUID, getElementClassByPrefix, getElementHeight, getElementWidth, getEndBlock, getPlugin, getPluginOptions, getPlugins, getRowsTotalHeight, getStartBlock, getToolbarClass, headingOptions, htmlToTheia, idCreator, inValidTypes, initializeDefaultMenuIcons, insertDataByInvalidType, internalPlugins, isCleanEmptyParagraph, isColorIndicator, isColorInput, isColorPanel, isDirectionKeydown, isPureEmptyParagraph, mergeArray, mergeDeepPlugins, mergeElementOptions, mergeOptions, nestedStructureByKey, plainToTheia, pluginsByKey, reSelection, recursionNodes, refocus, scrollIntoView, setEditorUUID, useElementStyle, withMention, withTestPlugin, withTheia };
16436
16626
  //# sourceMappingURL=worktile-theia.mjs.map