@atlaskit/editor-plugin-table 5.1.0 → 5.2.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.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/plugins/table/index.js +3 -2
- package/dist/cjs/plugins/table/nodeviews/TableCell.js +111 -0
- package/dist/cjs/plugins/table/nodeviews/TableNodeViewBase.js +30 -0
- package/dist/cjs/plugins/table/{pm-plugins/sticky-headers/nodeviews/tableRow.js → nodeviews/TableRow.js} +363 -303
- package/dist/cjs/plugins/table/pm-plugins/main.js +16 -13
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/index.js +1 -8
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/plugin.js +1 -9
- package/dist/cjs/plugins/table/types.js +4 -1
- package/dist/cjs/plugins/table/utils/dom.js +31 -1
- package/dist/cjs/plugins/table/utils/index.js +12 -0
- package/dist/cjs/plugins/table/utils/nodes.js +31 -7
- package/dist/es2019/plugins/table/index.js +3 -2
- package/dist/es2019/plugins/table/nodeviews/{tableCell.js → TableCell.js} +28 -24
- package/dist/es2019/plugins/table/nodeviews/TableNodeViewBase.js +22 -0
- package/dist/es2019/plugins/table/{pm-plugins/sticky-headers/nodeviews/tableRow.js → nodeviews/TableRow.js} +324 -280
- package/dist/es2019/plugins/table/pm-plugins/main.js +8 -8
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/index.js +1 -2
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/plugin.js +1 -9
- package/dist/es2019/plugins/table/types.js +5 -1
- package/dist/es2019/plugins/table/utils/dom.js +30 -0
- package/dist/es2019/plugins/table/utils/index.js +1 -1
- package/dist/es2019/plugins/table/utils/nodes.js +16 -0
- package/dist/esm/plugins/table/index.js +3 -2
- package/dist/esm/plugins/table/nodeviews/TableCell.js +105 -0
- package/dist/esm/plugins/table/nodeviews/TableNodeViewBase.js +24 -0
- package/dist/esm/plugins/table/{pm-plugins/sticky-headers/nodeviews/tableRow.js → nodeviews/TableRow.js} +364 -303
- package/dist/esm/plugins/table/pm-plugins/main.js +16 -13
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/index.js +1 -2
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/plugin.js +1 -9
- package/dist/esm/plugins/table/types.js +5 -1
- package/dist/esm/plugins/table/utils/dom.js +30 -0
- package/dist/esm/plugins/table/utils/index.js +1 -1
- package/dist/esm/plugins/table/utils/nodes.js +24 -0
- package/dist/types/plugins/table/nodeviews/TableCell.d.ts +13 -0
- package/dist/types/plugins/table/nodeviews/TableNodeViewBase.d.ts +18 -0
- package/dist/types/plugins/table/nodeviews/TableRow.d.ts +62 -0
- package/dist/types/plugins/table/pm-plugins/main.d.ts +1 -1
- package/dist/types/plugins/table/pm-plugins/sticky-headers/index.d.ts +0 -1
- package/dist/types/plugins/table/pm-plugins/sticky-headers/plugin.d.ts +1 -1
- package/dist/types/plugins/table/types.d.ts +15 -0
- package/dist/types/plugins/table/utils/dom.d.ts +6 -0
- package/dist/types/plugins/table/utils/index.d.ts +1 -1
- package/dist/types/plugins/table/utils/nodes.d.ts +12 -2
- package/dist/types-ts4.5/plugins/table/nodeviews/TableCell.d.ts +13 -0
- package/dist/types-ts4.5/plugins/table/nodeviews/TableNodeViewBase.d.ts +18 -0
- package/dist/types-ts4.5/plugins/table/nodeviews/TableRow.d.ts +62 -0
- package/dist/types-ts4.5/plugins/table/pm-plugins/main.d.ts +1 -1
- package/dist/types-ts4.5/plugins/table/pm-plugins/sticky-headers/index.d.ts +0 -1
- package/dist/types-ts4.5/plugins/table/pm-plugins/sticky-headers/plugin.d.ts +1 -1
- package/dist/types-ts4.5/plugins/table/types.d.ts +15 -0
- package/dist/types-ts4.5/plugins/table/utils/dom.d.ts +6 -0
- package/dist/types-ts4.5/plugins/table/utils/index.d.ts +1 -1
- package/dist/types-ts4.5/plugins/table/utils/nodes.d.ts +12 -2
- package/package.json +4 -2
- package/src/__tests__/unit/nodeviews/cell.ts +2 -2
- package/src/__tests__/unit/pm-plugins/sticky-headers/tableRow.tsx +25 -148
- package/src/plugins/table/index.tsx +2 -0
- package/src/plugins/table/nodeviews/{tableCell.tsx → TableCell.ts} +41 -46
- package/src/plugins/table/nodeviews/TableNodeViewBase.ts +32 -0
- package/src/plugins/table/{pm-plugins/sticky-headers/nodeviews/tableRow.ts → nodeviews/TableRow.ts} +246 -246
- package/src/plugins/table/pm-plugins/main.ts +10 -19
- package/src/plugins/table/pm-plugins/sticky-headers/index.ts +0 -1
- package/src/plugins/table/pm-plugins/sticky-headers/plugin.ts +1 -9
- package/src/plugins/table/types.ts +18 -0
- package/src/plugins/table/utils/dom.ts +38 -0
- package/src/plugins/table/utils/index.ts +2 -0
- package/src/plugins/table/utils/nodes.ts +30 -2
- package/tsconfig.app.json +6 -0
- package/dist/cjs/plugins/table/nodeviews/tableCell.js +0 -99
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.js +0 -35
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.js +0 -29
- package/dist/esm/plugins/table/nodeviews/tableCell.js +0 -93
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.js +0 -29
- package/dist/types/plugins/table/nodeviews/tableCell.d.ts +0 -17
- package/dist/types/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.d.ts +0 -6
- package/dist/types/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.d.ts +0 -73
- package/dist/types-ts4.5/plugins/table/nodeviews/tableCell.d.ts +0 -17
- package/dist/types-ts4.5/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.d.ts +0 -6
- package/dist/types-ts4.5/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.d.ts +0 -73
- package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/dom.ts +0 -37
|
@@ -2,13 +2,18 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
2
2
|
import debounce from 'lodash/debounce';
|
|
3
3
|
import throttle from 'lodash/throttle';
|
|
4
4
|
import { findOverflowScrollParent } from '@atlaskit/editor-common/ui';
|
|
5
|
-
import { browser
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { updateStickyState } from '../commands';
|
|
11
|
-
import {
|
|
5
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
6
|
+
import { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/addon/closest-edge';
|
|
7
|
+
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
|
|
8
|
+
import { getPluginState } from '../pm-plugins/plugin-factory';
|
|
9
|
+
import { pluginKey as tablePluginKey } from '../pm-plugins/plugin-key';
|
|
10
|
+
import { updateStickyState } from '../pm-plugins/sticky-headers/commands';
|
|
11
|
+
import { syncStickyRowToTable, updateStickyMargins as updateTableMargin } from '../pm-plugins/table-resizing/utils/dom';
|
|
12
|
+
import { TableCssClassName as ClassName, TableCssClassName } from '../types';
|
|
13
|
+
import { STICKY_HEADER_TOGGLE_TOLERANCE_MS, stickyHeaderBorderBottomWidth, stickyRowOffsetTop, tableControlsSpacing, tableScrollbarOffset } from '../ui/consts';
|
|
14
|
+
import { getTop, getTree } from '../utils/dom';
|
|
15
|
+
import { supportedHeaderRow } from '../utils/nodes';
|
|
16
|
+
import TableNodeView from './TableNodeViewBase';
|
|
12
17
|
|
|
13
18
|
// limit scroll event calls
|
|
14
19
|
const HEADER_ROW_SCROLL_THROTTLE_TIMEOUT = 200;
|
|
@@ -16,33 +21,16 @@ const HEADER_ROW_SCROLL_THROTTLE_TIMEOUT = 200;
|
|
|
16
21
|
// timeout for resetting the scroll class - if it’s too long then users won’t be able to click on the header cells,
|
|
17
22
|
// if too short it would trigger too many dom updates.
|
|
18
23
|
const HEADER_ROW_SCROLL_RESET_DEBOUNCE_TIMEOUT = 400;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Check if a given node is a header row with this definition:
|
|
23
|
-
* - all children are tableHeader cells
|
|
24
|
-
* - no table cells have been have merged with other table row cells
|
|
25
|
-
*
|
|
26
|
-
* @param node ProseMirror node
|
|
27
|
-
* @return boolean if it meets definition
|
|
28
|
-
*/
|
|
29
|
-
export const supportedHeaderRow = node => {
|
|
30
|
-
const allHeaders = mapChildren(node, child => child.type.name === 'tableHeader').every(Boolean);
|
|
31
|
-
const someMerged = anyChildCellMergedAcrossRow(node);
|
|
32
|
-
return allHeaders && !someMerged;
|
|
33
|
-
};
|
|
34
|
-
export class TableRowNodeView {
|
|
35
|
-
get tree() {
|
|
36
|
-
return getTree(this.dom);
|
|
37
|
-
}
|
|
24
|
+
export default class TableRow extends TableNodeView {
|
|
38
25
|
constructor(node, view, getPos, eventDispatcher) {
|
|
39
|
-
|
|
26
|
+
super(node, view, getPos, eventDispatcher);
|
|
40
27
|
_defineProperty(this, "colControlsOffset", 0);
|
|
41
28
|
_defineProperty(this, "focused", false);
|
|
42
29
|
_defineProperty(this, "topPosEditorElement", 0);
|
|
43
30
|
_defineProperty(this, "sentinels", {});
|
|
44
|
-
/* external events */
|
|
45
31
|
_defineProperty(this, "listening", false);
|
|
32
|
+
_defineProperty(this, "padding", 0);
|
|
33
|
+
_defineProperty(this, "top", 0);
|
|
46
34
|
_defineProperty(this, "headerRowMouseScrollEnd", debounce(() => {
|
|
47
35
|
this.dom.classList.remove('no-pointer-events');
|
|
48
36
|
}, HEADER_ROW_SCROLL_RESET_DEBOUNCE_TIMEOUT));
|
|
@@ -55,215 +43,148 @@ export class TableRowNodeView {
|
|
|
55
43
|
this.headerRowMouseScrollEnd();
|
|
56
44
|
}
|
|
57
45
|
}, HEADER_ROW_SCROLL_THROTTLE_TIMEOUT));
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
this.isHeaderRow = supportedHeaderRow(node);
|
|
47
|
+
this.isSticky = false;
|
|
48
|
+
const {
|
|
49
|
+
pluginConfig,
|
|
50
|
+
isDragAndDropEnabled
|
|
51
|
+
} = getPluginState(view.state);
|
|
52
|
+
this.isStickyHeaderEnabled = !!pluginConfig.stickyHeaders;
|
|
53
|
+
this.isDragAndDropEnabled = !!isDragAndDropEnabled;
|
|
54
|
+
if (this.isHeaderRow) {
|
|
55
|
+
this.dom.setAttribute('data-header-row', 'true');
|
|
56
|
+
if (this.isStickyHeaderEnabled) {
|
|
57
|
+
this.subscribe();
|
|
64
58
|
}
|
|
59
|
+
}
|
|
60
|
+
if (this.isDragAndDropEnabled) {
|
|
61
|
+
this.addDropTarget(this.contentDOM);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (el) {
|
|
70
|
-
delete el.dataset.isObserved;
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
const isCurrentTableSelected = tableRef === tree.table;
|
|
65
|
+
/**
|
|
66
|
+
* Variables
|
|
67
|
+
*/
|
|
75
68
|
|
|
76
|
-
|
|
77
|
-
if (isCurrentTableSelected && !state.isHeaderRowEnabled && this.tree) {
|
|
78
|
-
this.makeRowHeaderNotSticky(this.tree.table);
|
|
79
|
-
}
|
|
80
|
-
this.focused = isCurrentTableSelected;
|
|
81
|
-
const {
|
|
82
|
-
wrapper
|
|
83
|
-
} = tree;
|
|
84
|
-
const tableContainer = wrapper.parentElement;
|
|
85
|
-
const tableContentWrapper = tableContainer.parentElement;
|
|
86
|
-
const layoutContainer = tableContentWrapper && tableContentWrapper.parentElement;
|
|
87
|
-
if (isCurrentTableSelected) {
|
|
88
|
-
this.colControlsOffset = tableControlsSpacing;
|
|
89
|
-
if (layoutContainer && layoutContainer.getAttribute('data-layout-content')) {
|
|
90
|
-
// move table a little out of the way
|
|
91
|
-
// to provide spacing for table controls
|
|
92
|
-
tableContentWrapper.style.paddingLeft = '11px';
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
this.colControlsOffset = 0;
|
|
96
|
-
if (layoutContainer && layoutContainer.getAttribute('data-layout-content')) {
|
|
97
|
-
tableContentWrapper.style.removeProperty('padding-left');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
69
|
+
// @ts-ignore
|
|
100
70
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!tree) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
syncStickyRowToTable(tree.table);
|
|
113
|
-
});
|
|
114
|
-
_defineProperty(this, "shouldHeaderStick", tree => {
|
|
115
|
-
const {
|
|
116
|
-
wrapper
|
|
117
|
-
} = tree;
|
|
118
|
-
const tableWrapperRect = wrapper.getBoundingClientRect();
|
|
119
|
-
const editorAreaRect = this.editorScrollableElement.getBoundingClientRect();
|
|
120
|
-
const stickyHeaderRect = this.contentDOM.getBoundingClientRect();
|
|
121
|
-
const firstHeaderRow = !this.dom.previousElementSibling;
|
|
122
|
-
const subsequentRows = !!this.dom.nextElementSibling;
|
|
123
|
-
const isHeaderValid = firstHeaderRow && subsequentRows;
|
|
71
|
+
/**
|
|
72
|
+
* Methods: Nodeview Lifecycle
|
|
73
|
+
*/
|
|
74
|
+
update(node, ..._args) {
|
|
75
|
+
// do nothing if nodes were identical
|
|
76
|
+
if (node === this.node) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
124
79
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
80
|
+
// see if we're changing into a header row or
|
|
81
|
+
// changing away from one
|
|
82
|
+
const newNodeIsHeaderRow = supportedHeaderRow(node);
|
|
83
|
+
if (this.isHeaderRow !== newNodeIsHeaderRow) {
|
|
84
|
+
return false; // re-create nodeview
|
|
85
|
+
}
|
|
131
86
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
87
|
+
// node is different but no need to re-create nodeview
|
|
88
|
+
this.node = node;
|
|
89
|
+
|
|
90
|
+
// don't do anything if we're just a regular tr
|
|
91
|
+
if (!this.isHeaderRow) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// something changed, sync widths
|
|
96
|
+
if (this.isStickyHeaderEnabled) {
|
|
97
|
+
const tbody = this.dom.parentElement;
|
|
98
|
+
const table = tbody && tbody.parentElement;
|
|
99
|
+
syncStickyRowToTable(table);
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
destroy() {
|
|
104
|
+
var _this$dropTargetClean;
|
|
105
|
+
if (this.isStickyHeaderEnabled) {
|
|
106
|
+
this.unsubscribe();
|
|
107
|
+
const tree = getTree(this.dom);
|
|
108
|
+
if (tree) {
|
|
109
|
+
this.makeRowHeaderNotSticky(tree.table, true);
|
|
135
110
|
}
|
|
111
|
+
this.emitOff(true);
|
|
112
|
+
}
|
|
136
113
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
114
|
+
// If a drop target cleanup method has been set then we should call it.
|
|
115
|
+
(_this$dropTargetClean = this.dropTargetCleanup) === null || _this$dropTargetClean === void 0 ? void 0 : _this$dropTargetClean.call(this);
|
|
116
|
+
}
|
|
117
|
+
ignoreMutation(mutationRecord) {
|
|
118
|
+
/* tableRows are not directly editable by the user
|
|
119
|
+
* so it should be safe to ignore mutations that we cause
|
|
120
|
+
* by updating styles and classnames on this DOM element
|
|
121
|
+
*
|
|
122
|
+
* Update: should not ignore mutations for row selection to avoid known issue with table selection highlight in firefox
|
|
123
|
+
* Related bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=1289673
|
|
124
|
+
* */
|
|
125
|
+
const isTableSelection = mutationRecord.type === 'selection' && mutationRecord.target.nodeName === 'TR';
|
|
140
126
|
/**
|
|
141
|
-
*
|
|
142
|
-
*
|
|
127
|
+
* Update: should not ignore mutations when an node is added, as this interferes with
|
|
128
|
+
* prosemirrors handling of some language inputs in Safari (ie. Pinyin, Hiragana).
|
|
129
|
+
*
|
|
130
|
+
* In paticular, when a composition occurs at the start of the first node inside a table cell, if the resulting mutation
|
|
131
|
+
* from the composition end is ignored than prosemirror will end up with; invalid table markup nesting and a misplaced
|
|
132
|
+
* selection and insertion.
|
|
143
133
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
_defineProperty(this, "makeHeaderRowSticky", (tree, scrollTop) => {
|
|
155
|
-
var _tbody$firstChild;
|
|
156
|
-
// If header row height is more than 50% of viewport height don't do this
|
|
157
|
-
if (this.isSticky || this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const {
|
|
161
|
-
table,
|
|
162
|
-
wrapper
|
|
163
|
-
} = tree;
|
|
134
|
+
const isNodeInsertion = mutationRecord.type === 'childList' && mutationRecord.target.nodeName === 'TR' && mutationRecord.addedNodes.length;
|
|
135
|
+
if (isTableSelection || isNodeInsertion) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
164
140
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (!isFirstHeader) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const currentTableTop = this.getCurrentTableTop(tree);
|
|
172
|
-
if (!scrollTop) {
|
|
173
|
-
scrollTop = getTop(this.editorScrollableElement);
|
|
174
|
-
}
|
|
175
|
-
const domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
|
|
176
|
-
if (!this.isSticky) {
|
|
177
|
-
var _this$editorScrollabl;
|
|
178
|
-
syncStickyRowToTable(table);
|
|
179
|
-
this.dom.classList.add('sticky');
|
|
180
|
-
table.classList.add(ClassName.TABLE_STICKY);
|
|
181
|
-
this.isSticky = true;
|
|
141
|
+
/**
|
|
142
|
+
* Methods
|
|
143
|
+
*/
|
|
182
144
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
145
|
+
addDropTarget(element) {
|
|
146
|
+
const pos = this.getPos();
|
|
147
|
+
if (!Number.isFinite(pos)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (this.dropTargetCleanup) {
|
|
151
|
+
this.dropTargetCleanup();
|
|
152
|
+
}
|
|
153
|
+
const resolvedPos = this.view.state.doc.resolve(pos);
|
|
154
|
+
const targetIndex = resolvedPos.index();
|
|
155
|
+
const localId = resolvedPos.parent.attrs.localId;
|
|
156
|
+
this.dropTargetCleanup = dropTargetForElements({
|
|
157
|
+
element: element,
|
|
158
|
+
canDrop({
|
|
159
|
+
source
|
|
160
|
+
}) {
|
|
161
|
+
var _data$indexes, _data$indexes2;
|
|
162
|
+
const data = source.data;
|
|
163
|
+
return (
|
|
164
|
+
// Only draggables of row type can be dropped on this target
|
|
165
|
+
data.type === 'table-row' &&
|
|
166
|
+
// Only draggables which came from the same table can be dropped on this target
|
|
167
|
+
data.localId === localId &&
|
|
168
|
+
// Only draggables which DO NOT include this drop targets index can be dropped
|
|
169
|
+
!!((_data$indexes = data.indexes) !== null && _data$indexes !== void 0 && _data$indexes.length) && ((_data$indexes2 = data.indexes) === null || _data$indexes2 === void 0 ? void 0 : _data$indexes2.indexOf(targetIndex)) === -1
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
getData({
|
|
173
|
+
input,
|
|
174
|
+
element
|
|
175
|
+
}) {
|
|
176
|
+
const data = {
|
|
177
|
+
localId,
|
|
178
|
+
type: 'table-row',
|
|
179
|
+
targetIndex
|
|
180
|
+
};
|
|
181
|
+
return attachClosestEdge(data, {
|
|
182
|
+
input,
|
|
183
|
+
element,
|
|
184
|
+
allowedEdges: ['top', 'bottom']
|
|
191
185
|
});
|
|
192
|
-
const fastScrollThresholdMs = 500;
|
|
193
|
-
setTimeout(() => {
|
|
194
|
-
this.refireIntersectionObservers();
|
|
195
|
-
}, fastScrollThresholdMs);
|
|
196
186
|
}
|
|
197
|
-
this.dom.style.top = `${domTop}px`;
|
|
198
|
-
updateTableMargin(table);
|
|
199
|
-
this.dom.scrollLeft = wrapper.scrollLeft;
|
|
200
|
-
this.emitOn(domTop, this.colControlsOffset);
|
|
201
187
|
});
|
|
202
|
-
_defineProperty(this, "makeRowHeaderNotSticky", (table, isEditorDestroyed = false) => {
|
|
203
|
-
if (!this.isSticky || !table || !this.dom) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
this.dom.style.removeProperty('width');
|
|
207
|
-
this.dom.classList.remove('sticky');
|
|
208
|
-
table.classList.remove(ClassName.TABLE_STICKY);
|
|
209
|
-
this.isSticky = false;
|
|
210
|
-
this.dom.style.top = '';
|
|
211
|
-
table.style.removeProperty('margin-top');
|
|
212
|
-
this.emitOff(isEditorDestroyed);
|
|
213
|
-
});
|
|
214
|
-
_defineProperty(this, "getWrapperoffset", (inverse = false) => {
|
|
215
|
-
const focusValue = inverse ? !this.focused : this.focused;
|
|
216
|
-
return focusValue ? 0 : tableControlsSpacing;
|
|
217
|
-
});
|
|
218
|
-
_defineProperty(this, "getWrapperRefTop", wrapper => Math.round(getTop(wrapper)) + this.getWrapperoffset());
|
|
219
|
-
// TODO: rename!
|
|
220
|
-
_defineProperty(this, "getScrolledTableTop", wrapper => this.getWrapperRefTop(wrapper) - this.topPosEditorElement);
|
|
221
|
-
_defineProperty(this, "getCurrentTableTop", tree => this.getScrolledTableTop(tree.wrapper) + tree.table.clientHeight);
|
|
222
|
-
/* emit external events */
|
|
223
|
-
_defineProperty(this, "padding", 0);
|
|
224
|
-
_defineProperty(this, "top", 0);
|
|
225
|
-
_defineProperty(this, "emitOn", (top, padding) => {
|
|
226
|
-
if (top === this.top && padding === this.padding) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
this.top = top;
|
|
230
|
-
this.padding = padding;
|
|
231
|
-
updateStickyState({
|
|
232
|
-
pos: this.getPos(),
|
|
233
|
-
top,
|
|
234
|
-
sticky: true,
|
|
235
|
-
padding
|
|
236
|
-
})(this.view.state, this.view.dispatch, this.view);
|
|
237
|
-
});
|
|
238
|
-
_defineProperty(this, "emitOff", isEditorDestroyed => {
|
|
239
|
-
if (this.top === 0 && this.padding === 0) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
this.top = 0;
|
|
243
|
-
this.padding = 0;
|
|
244
|
-
if (!isEditorDestroyed) {
|
|
245
|
-
updateStickyState({
|
|
246
|
-
pos: this.getPos(),
|
|
247
|
-
sticky: false,
|
|
248
|
-
top: this.top,
|
|
249
|
-
padding: this.padding
|
|
250
|
-
})(this.view.state, this.view.dispatch, this.view);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
this.view = view;
|
|
254
|
-
this.node = node;
|
|
255
|
-
this.getPos = getPos;
|
|
256
|
-
this.eventDispatcher = eventDispatcher;
|
|
257
|
-
this.dom = document.createElement('tr');
|
|
258
|
-
this.contentDOM = this.dom;
|
|
259
|
-
this.lastTimePainted = 0;
|
|
260
|
-
this.isHeaderRow = supportedHeaderRow(node);
|
|
261
|
-
this.isSticky = false;
|
|
262
|
-
this.lastStickyTimestamp = undefined;
|
|
263
|
-
if (this.isHeaderRow) {
|
|
264
|
-
this.dom.setAttribute('data-header-row', 'true');
|
|
265
|
-
this.subscribe();
|
|
266
|
-
}
|
|
267
188
|
}
|
|
268
189
|
subscribe() {
|
|
269
190
|
this.editorScrollableElement = findOverflowScrollParent(this.view.dom) || window;
|
|
@@ -271,8 +192,8 @@ export class TableRowNodeView {
|
|
|
271
192
|
this.initObservers();
|
|
272
193
|
this.topPosEditorElement = getTop(this.editorScrollableElement);
|
|
273
194
|
}
|
|
274
|
-
this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth);
|
|
275
|
-
this.eventDispatcher.on(tablePluginKey.key, this.onTablePluginState);
|
|
195
|
+
this.eventDispatcher.on('widthPlugin', this.updateStickyHeaderWidth.bind(this));
|
|
196
|
+
this.eventDispatcher.on(tablePluginKey.key, this.onTablePluginState.bind(this));
|
|
276
197
|
this.listening = true;
|
|
277
198
|
this.dom.addEventListener('wheel', this.headerRowMouseScroll.bind(this), {
|
|
278
199
|
passive: true
|
|
@@ -321,9 +242,9 @@ export class TableRowNodeView {
|
|
|
321
242
|
this.resizeObserver.observe(this.editorScrollableElement);
|
|
322
243
|
}
|
|
323
244
|
window.requestAnimationFrame(() => {
|
|
324
|
-
var
|
|
245
|
+
var _getTree;
|
|
325
246
|
// we expect tree to be defined after animation frame
|
|
326
|
-
const tableContainer = (
|
|
247
|
+
const tableContainer = (_getTree = getTree(this.dom)) === null || _getTree === void 0 ? void 0 : _getTree.wrapper.closest(`.${TableCssClassName.NODEVIEW_WRAPPER}`);
|
|
327
248
|
if (tableContainer) {
|
|
328
249
|
this.sentinels.top = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_TOP).item(0);
|
|
329
250
|
this.sentinels.bottom = tableContainer.getElementsByClassName(ClassName.TABLE_STICKY_SENTINEL_BOTTOM).item(0);
|
|
@@ -342,17 +263,18 @@ export class TableRowNodeView {
|
|
|
342
263
|
// to allocate for new header height
|
|
343
264
|
createResizeObserver() {
|
|
344
265
|
this.resizeObserver = new ResizeObserver(entries => {
|
|
345
|
-
|
|
266
|
+
const tree = getTree(this.dom);
|
|
267
|
+
if (!tree) {
|
|
346
268
|
return;
|
|
347
269
|
}
|
|
348
270
|
const {
|
|
349
271
|
table
|
|
350
|
-
} =
|
|
272
|
+
} = tree;
|
|
351
273
|
entries.forEach(entry => {
|
|
352
|
-
var _this$
|
|
274
|
+
var _this$editorScrollabl;
|
|
353
275
|
// On resize of the parent scroll element we need to adjust the width
|
|
354
276
|
// of the sticky header
|
|
355
|
-
if (entry.target.className === ((_this$
|
|
277
|
+
if (entry.target.className === ((_this$editorScrollabl = this.editorScrollableElement) === null || _this$editorScrollabl === void 0 ? void 0 : _this$editorScrollabl.className)) {
|
|
356
278
|
this.updateStickyHeaderWidth();
|
|
357
279
|
} else {
|
|
358
280
|
const newHeight = entry.contentRect ? entry.contentRect.height : entry.target.offsetHeight;
|
|
@@ -370,12 +292,13 @@ export class TableRowNodeView {
|
|
|
370
292
|
}
|
|
371
293
|
createIntersectionObserver() {
|
|
372
294
|
this.intersectionObserver = new IntersectionObserver((entries, _) => {
|
|
373
|
-
|
|
295
|
+
const tree = getTree(this.dom);
|
|
296
|
+
if (!tree) {
|
|
374
297
|
return;
|
|
375
298
|
}
|
|
376
299
|
const {
|
|
377
300
|
table
|
|
378
|
-
} =
|
|
301
|
+
} = tree;
|
|
379
302
|
if (table.rows.length < 2) {
|
|
380
303
|
// ED-19307 - When there's only one row in a table the top & bottom sentinels become inverted. This creates some nasty visiblity
|
|
381
304
|
// toggling side-effects because the intersection observers gets confused.
|
|
@@ -394,7 +317,7 @@ export class TableRowNodeView {
|
|
|
394
317
|
const sentinelIsBelowScrollArea = (((_entry$rootBounds2 = entry.rootBounds) === null || _entry$rootBounds2 === void 0 ? void 0 : _entry$rootBounds2.bottom) || 0) < entry.boundingClientRect.bottom;
|
|
395
318
|
if (!entry.isIntersecting && !sentinelIsBelowScrollArea) {
|
|
396
319
|
var _entry$rootBounds3;
|
|
397
|
-
|
|
320
|
+
tree && this.makeHeaderRowSticky(tree, (_entry$rootBounds3 = entry.rootBounds) === null || _entry$rootBounds3 === void 0 ? void 0 : _entry$rootBounds3.top);
|
|
398
321
|
this.lastStickyTimestamp = Date.now();
|
|
399
322
|
} else {
|
|
400
323
|
table && this.makeRowHeaderNotSticky(table);
|
|
@@ -414,7 +337,7 @@ export class TableRowNodeView {
|
|
|
414
337
|
}
|
|
415
338
|
} else if (entry.isIntersecting && sentinelIsAboveScrollArea) {
|
|
416
339
|
var _entry$rootBounds5;
|
|
417
|
-
|
|
340
|
+
tree && this.makeHeaderRowSticky(tree, entry === null || entry === void 0 ? void 0 : (_entry$rootBounds5 = entry.rootBounds) === null || _entry$rootBounds5 === void 0 ? void 0 : _entry$rootBounds5.top);
|
|
418
341
|
this.lastStickyTimestamp = Date.now();
|
|
419
342
|
}
|
|
420
343
|
}
|
|
@@ -424,65 +347,186 @@ export class TableRowNodeView {
|
|
|
424
347
|
root: this.editorScrollableElement
|
|
425
348
|
});
|
|
426
349
|
}
|
|
350
|
+
/* receive external events */
|
|
427
351
|
|
|
428
|
-
|
|
352
|
+
onTablePluginState(state) {
|
|
353
|
+
const tableRef = state.tableRef;
|
|
354
|
+
const tree = getTree(this.dom);
|
|
355
|
+
if (!tree) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
429
358
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
359
|
+
// when header rows are toggled off - mark sentinels as unobserved
|
|
360
|
+
if (!state.isHeaderRowEnabled) {
|
|
361
|
+
[this.sentinels.top, this.sentinels.bottom].forEach(el => {
|
|
362
|
+
if (el) {
|
|
363
|
+
delete el.dataset.isObserved;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
435
366
|
}
|
|
367
|
+
const isCurrentTableSelected = tableRef === tree.table;
|
|
436
368
|
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
369
|
+
// If current table selected and header row is toggled off, turn off sticky header
|
|
370
|
+
if (isCurrentTableSelected && !state.isHeaderRowEnabled && tree) {
|
|
371
|
+
this.makeRowHeaderNotSticky(tree.table);
|
|
372
|
+
}
|
|
373
|
+
this.focused = isCurrentTableSelected;
|
|
374
|
+
const {
|
|
375
|
+
wrapper
|
|
376
|
+
} = tree;
|
|
377
|
+
const tableContainer = wrapper.parentElement;
|
|
378
|
+
const tableContentWrapper = tableContainer.parentElement;
|
|
379
|
+
const layoutContainer = tableContentWrapper && tableContentWrapper.parentElement;
|
|
380
|
+
if (isCurrentTableSelected) {
|
|
381
|
+
this.colControlsOffset = tableControlsSpacing;
|
|
382
|
+
if (layoutContainer && layoutContainer.getAttribute('data-layout-content')) {
|
|
383
|
+
// move table a little out of the way
|
|
384
|
+
// to provide spacing for table controls
|
|
385
|
+
tableContentWrapper.style.paddingLeft = '11px';
|
|
386
|
+
}
|
|
387
|
+
} else {
|
|
388
|
+
this.colControlsOffset = 0;
|
|
389
|
+
if (layoutContainer && layoutContainer.getAttribute('data-layout-content')) {
|
|
390
|
+
tableContentWrapper.style.removeProperty('padding-left');
|
|
391
|
+
}
|
|
442
392
|
}
|
|
443
393
|
|
|
444
|
-
//
|
|
445
|
-
|
|
394
|
+
// run after table style changes have been committed
|
|
395
|
+
setTimeout(() => {
|
|
396
|
+
syncStickyRowToTable(tree.table);
|
|
397
|
+
}, 0);
|
|
398
|
+
}
|
|
399
|
+
updateStickyHeaderWidth() {
|
|
400
|
+
// table width might have changed, sync that back to sticky row
|
|
401
|
+
const tree = getTree(this.dom);
|
|
402
|
+
if (!tree) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
syncStickyRowToTable(tree.table);
|
|
406
|
+
}
|
|
446
407
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Manually refire the intersection observers.
|
|
410
|
+
* Useful when the header may have detached from the table.
|
|
411
|
+
*/
|
|
412
|
+
refireIntersectionObservers() {
|
|
413
|
+
if (this.isSticky) {
|
|
414
|
+
[this.sentinels.top, this.sentinels.bottom].forEach(el => {
|
|
415
|
+
if (el && this.intersectionObserver) {
|
|
416
|
+
this.intersectionObserver.unobserve(el);
|
|
417
|
+
this.intersectionObserver.observe(el);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
450
420
|
}
|
|
421
|
+
}
|
|
422
|
+
makeHeaderRowSticky(tree, scrollTop) {
|
|
423
|
+
var _tbody$firstChild;
|
|
424
|
+
// If header row height is more than 50% of viewport height don't do this
|
|
425
|
+
if (this.isSticky || this.stickyRowHeight && this.stickyRowHeight > window.innerHeight / 2) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const {
|
|
429
|
+
table,
|
|
430
|
+
wrapper
|
|
431
|
+
} = tree;
|
|
451
432
|
|
|
452
|
-
//
|
|
433
|
+
// ED-16035 Make sure sticky header is only applied to first row
|
|
453
434
|
const tbody = this.dom.parentElement;
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
435
|
+
const isFirstHeader = tbody === null || tbody === void 0 ? void 0 : (_tbody$firstChild = tbody.firstChild) === null || _tbody$firstChild === void 0 ? void 0 : _tbody$firstChild.isEqualNode(this.dom);
|
|
436
|
+
if (!isFirstHeader) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const currentTableTop = this.getCurrentTableTop(tree);
|
|
440
|
+
if (!scrollTop) {
|
|
441
|
+
scrollTop = getTop(this.editorScrollableElement);
|
|
442
|
+
}
|
|
443
|
+
const domTop = currentTableTop > 0 ? scrollTop : scrollTop + currentTableTop;
|
|
444
|
+
if (!this.isSticky) {
|
|
445
|
+
var _this$editorScrollabl2;
|
|
446
|
+
syncStickyRowToTable(table);
|
|
447
|
+
this.dom.classList.add('sticky');
|
|
448
|
+
table.classList.add(ClassName.TABLE_STICKY);
|
|
449
|
+
this.isSticky = true;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* The logic below is not desirable, but acts as a fail safe for scenarios where the sticky header
|
|
453
|
+
* detaches from the table. This typically happens during a fast scroll by the user which causes
|
|
454
|
+
* the intersection observer logic to not fire as expected.
|
|
455
|
+
*/
|
|
456
|
+
(_this$editorScrollabl2 = this.editorScrollableElement) === null || _this$editorScrollabl2 === void 0 ? void 0 : _this$editorScrollabl2.addEventListener('scrollend', this.refireIntersectionObservers, {
|
|
457
|
+
passive: true,
|
|
458
|
+
once: true
|
|
459
|
+
});
|
|
460
|
+
const fastScrollThresholdMs = 500;
|
|
461
|
+
setTimeout(() => {
|
|
462
|
+
this.refireIntersectionObservers();
|
|
463
|
+
}, fastScrollThresholdMs);
|
|
464
|
+
}
|
|
465
|
+
this.dom.style.top = `${domTop}px`;
|
|
466
|
+
updateTableMargin(table);
|
|
467
|
+
this.dom.scrollLeft = wrapper.scrollLeft;
|
|
468
|
+
this.emitOn(domTop, this.colControlsOffset);
|
|
457
469
|
}
|
|
458
|
-
|
|
459
|
-
this.
|
|
460
|
-
|
|
461
|
-
this.makeRowHeaderNotSticky(this.tree.table, true);
|
|
470
|
+
makeRowHeaderNotSticky(table, isEditorDestroyed = false) {
|
|
471
|
+
if (!this.isSticky || !table || !this.dom) {
|
|
472
|
+
return;
|
|
462
473
|
}
|
|
463
|
-
this.
|
|
474
|
+
this.dom.style.removeProperty('width');
|
|
475
|
+
this.dom.classList.remove('sticky');
|
|
476
|
+
table.classList.remove(ClassName.TABLE_STICKY);
|
|
477
|
+
this.isSticky = false;
|
|
478
|
+
this.dom.style.top = '';
|
|
479
|
+
table.style.removeProperty('margin-top');
|
|
480
|
+
this.emitOff(isEditorDestroyed);
|
|
464
481
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
482
|
+
getWrapperoffset(inverse = false) {
|
|
483
|
+
const focusValue = inverse ? !this.focused : this.focused;
|
|
484
|
+
return focusValue ? 0 : tableControlsSpacing;
|
|
485
|
+
}
|
|
486
|
+
getWrapperRefTop(wrapper) {
|
|
487
|
+
return Math.round(getTop(wrapper)) + this.getWrapperoffset();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// TODO: rename!
|
|
491
|
+
getScrolledTableTop(wrapper) {
|
|
492
|
+
return this.getWrapperRefTop(wrapper) - this.topPosEditorElement;
|
|
493
|
+
}
|
|
494
|
+
getCurrentTableTop(tree) {
|
|
495
|
+
return this.getScrolledTableTop(tree.wrapper) + tree.table.clientHeight;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* emit external events */
|
|
499
|
+
|
|
500
|
+
emitOn(top, padding) {
|
|
501
|
+
if (top === this.top && padding === this.padding) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
this.top = top;
|
|
505
|
+
this.padding = padding;
|
|
506
|
+
const pos = this.getPos();
|
|
507
|
+
if (Number.isFinite(pos)) {
|
|
508
|
+
updateStickyState({
|
|
509
|
+
pos,
|
|
510
|
+
top,
|
|
511
|
+
sticky: true,
|
|
512
|
+
padding
|
|
513
|
+
})(this.view.state, this.view.dispatch, this.view);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
emitOff(isEditorDestroyed) {
|
|
517
|
+
if (this.top === 0 && this.padding === 0) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
this.top = 0;
|
|
521
|
+
this.padding = 0;
|
|
522
|
+
const pos = this.getPos();
|
|
523
|
+
if (!isEditorDestroyed && Number.isFinite(pos)) {
|
|
524
|
+
updateStickyState({
|
|
525
|
+
pos,
|
|
526
|
+
sticky: false,
|
|
527
|
+
top: this.top,
|
|
528
|
+
padding: this.padding
|
|
529
|
+
})(this.view.state, this.view.dispatch, this.view);
|
|
485
530
|
}
|
|
486
|
-
return true;
|
|
487
531
|
}
|
|
488
532
|
}
|