@openleaf-editor/plugins-table 0.1.0-beta.1 → 0.1.0-beta.3
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/README.md +98 -0
- package/dist/commands.d.ts +119 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +754 -0
- package/dist/commands.js.map +1 -0
- package/dist/dialogs.d.ts +14 -0
- package/dist/dialogs.d.ts.map +1 -0
- package/dist/dialogs.js +159 -0
- package/dist/dialogs.js.map +1 -0
- package/dist/grid.d.ts +15 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +230 -0
- package/dist/grid.js.map +1 -0
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +4 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +8 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +112 -106
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts +23 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +275 -0
- package/dist/menu.js.map +1 -0
- package/dist/styles.d.ts +9 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +93 -0
- package/dist/styles.js.map +1 -0
- package/package.json +15 -7
package/dist/index.js
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* So everyone gets tables that read and write correctly, for about a kilobyte.
|
|
14
14
|
* What is opt-in is the weight: cell selection, column resizing, the row and
|
|
15
|
-
* column commands,
|
|
16
|
-
*
|
|
15
|
+
* column commands, property dialogs, the insert grid, the context menu, and the
|
|
16
|
+
* toolbar controls.
|
|
17
17
|
*
|
|
18
18
|
* ## Loading it
|
|
19
19
|
*
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* ```
|
|
26
26
|
*
|
|
27
27
|
* The second bundle shares the first one's ProseMirror runtime rather than
|
|
28
|
-
* carrying its own copy
|
|
28
|
+
* carrying its own copy.
|
|
29
29
|
*
|
|
30
30
|
* Or as a module:
|
|
31
31
|
*
|
|
@@ -34,12 +34,21 @@
|
|
|
34
34
|
* installTableEditing()
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
import {
|
|
38
|
-
import { registerIcons, registerToolbarItem } from '@openleaf-editor/ui';
|
|
37
|
+
import { registerEditorPlugin } from '@openleaf-editor/core';
|
|
38
|
+
import { registerIcons, registerStyles, registerToolbarItem } from '@openleaf-editor/ui';
|
|
39
|
+
import { columnResizing, deleteTable, mergeCells, splitCell, tableEditing, TableView, } from 'prosemirror-tables';
|
|
40
|
+
import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, colgroupSyncPlugin, deleteColumn, deleteRow, inTable, insertTable, toggleHeaderRow, } from './commands.js';
|
|
41
|
+
import { openCaptionDialog, openCellProperties, openRowProperties, openTableProperties } from './dialogs.js';
|
|
42
|
+
import { buildInsertGrid } from './grid.js';
|
|
39
43
|
import { TABLE_ICON_PATHS } from './icons.js';
|
|
40
|
-
import {
|
|
44
|
+
import { tableContextMenu } from './menu.js';
|
|
45
|
+
import { TABLE_UI_CSS } from './styles.js';
|
|
41
46
|
export const TABLE_TOOLBAR_ITEMS = [
|
|
42
47
|
'insertTable',
|
|
48
|
+
'tableProperties',
|
|
49
|
+
'rowProperties',
|
|
50
|
+
'cellProperties',
|
|
51
|
+
'tableCaption',
|
|
43
52
|
'addRowBefore',
|
|
44
53
|
'addRowAfter',
|
|
45
54
|
'deleteRow',
|
|
@@ -53,112 +62,89 @@ export const TABLE_TOOLBAR_ITEMS = [
|
|
|
53
62
|
];
|
|
54
63
|
/** A layout string for the default toolbar plus the table controls. */
|
|
55
64
|
export const TABLE_LAYOUT_SUFFIX = ` | ${TABLE_TOOLBAR_ITEMS.join(' ')}`;
|
|
56
|
-
/** Is the selection inside a table? Table commands are useless outside one. */
|
|
57
|
-
export function inTable(state) {
|
|
58
|
-
return isNodeActive(state, 'table');
|
|
59
|
-
}
|
|
60
65
|
/**
|
|
61
|
-
*
|
|
66
|
+
* `TableView`, plus the caption it does not know about.
|
|
62
67
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
|
|
67
|
-
export function insertTable(rows = 3, cols = 3) {
|
|
68
|
-
return (state, dispatch) => {
|
|
69
|
-
if (!canInsert(state, 'table'))
|
|
70
|
-
return false;
|
|
71
|
-
if (dispatch) {
|
|
72
|
-
// From the state's schema, not an imported singleton: a plugin that
|
|
73
|
-
// captured one schema would build nodes the editor's schema rejects.
|
|
74
|
-
const cell = state.schema.nodes['table_cell'];
|
|
75
|
-
const header = state.schema.nodes['table_header'];
|
|
76
|
-
const row = state.schema.nodes['table_row'];
|
|
77
|
-
const tableType = state.schema.nodes['table'];
|
|
78
|
-
if (!cell || !header || !row || !tableType)
|
|
79
|
-
return false;
|
|
80
|
-
const headerCells = Array.from({ length: cols }, () => header.createAndFill({ scope: 'col' })).filter((n) => n !== null);
|
|
81
|
-
const bodyRows = Array.from({ length: Math.max(0, rows - 1) }, () => row.create(null, Array.from({ length: cols }, () => cell.createAndFill()).filter((n) => n !== null)));
|
|
82
|
-
const table = tableType.create(null, [row.create(null, headerCells), ...bodyRows]);
|
|
83
|
-
dispatch(state.tr.replaceSelectionWith(table).scrollIntoView());
|
|
84
|
-
}
|
|
85
|
-
return true;
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Keep `scope` valid when cells change role.
|
|
68
|
+
* `columnResizing` installs a node view for tables, and that node view builds
|
|
69
|
+
* the element itself: a wrapper div, a `<colgroup>` it owns for resize widths,
|
|
70
|
+
* and a `<tbody>`. It never consults the table node's `toDOM`, so once this
|
|
71
|
+
* bundle loads, the caption core renders is simply absent from the editor.
|
|
90
72
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
73
|
+
* That produced the worst version of the bug it was meant to fix. Saving still
|
|
74
|
+
* kept the caption -- serialization goes through `toDOM` and never through a
|
|
75
|
+
* node view -- so the caption was invisible while editing and reappeared in the
|
|
76
|
+
* stored HTML. An author would reasonably conclude it had been deleted, and the
|
|
77
|
+
* only way to find out otherwise is to read the database.
|
|
78
|
+
*
|
|
79
|
+
* Only the caption is re-added. The preserved `<colgroup>` markup deliberately
|
|
80
|
+
* is not: this view's own colgroup is what drives column resizing, and a second
|
|
81
|
+
* one would fight it for the same columns. The author's colgroup is still
|
|
82
|
+
* stored and still emitted on save; it is the resize widths that win on screen,
|
|
83
|
+
* which is the same bargain the resizing feature already makes.
|
|
95
84
|
*/
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
85
|
+
class CaptionedTableView extends TableView {
|
|
86
|
+
constructor(node, defaultCellMinWidth) {
|
|
87
|
+
super(node, defaultCellMinWidth);
|
|
88
|
+
this.syncCaption(node);
|
|
89
|
+
}
|
|
90
|
+
update(node) {
|
|
91
|
+
const handled = super.update(node);
|
|
92
|
+
if (handled)
|
|
93
|
+
this.syncCaption(node);
|
|
94
|
+
return handled;
|
|
95
|
+
}
|
|
96
|
+
ignoreMutation(record) {
|
|
97
|
+
// The caption is ours, not content. Without this, ProseMirror treats a
|
|
98
|
+
// change inside it as an edit to the document and tries to re-read it.
|
|
99
|
+
const caption = this.currentCaption();
|
|
100
|
+
if (caption && record.target instanceof Node && caption.contains(record.target))
|
|
101
|
+
return true;
|
|
102
|
+
return super.ignoreMutation(record);
|
|
103
|
+
}
|
|
104
|
+
currentCaption() {
|
|
105
|
+
const first = this.table.firstElementChild;
|
|
106
|
+
return first && first.nodeName === 'CAPTION' ? first : null;
|
|
107
|
+
}
|
|
108
|
+
syncCaption(node) {
|
|
109
|
+
const html = node.attrs['caption'] ?? null;
|
|
110
|
+
const existing = this.currentCaption();
|
|
111
|
+
if (!html) {
|
|
112
|
+
existing?.remove();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Rebuild only when the markup actually changed. Replacing it on every
|
|
116
|
+
// update would discard the DOM under the user's selection on every
|
|
117
|
+
// keystroke inside the table.
|
|
118
|
+
if (existing && existing.getAttribute('data-openleaf-caption') === html)
|
|
119
|
+
return;
|
|
120
|
+
const tpl = document.createElement('template');
|
|
121
|
+
tpl.innerHTML = html;
|
|
122
|
+
const rebuilt = tpl.content.firstElementChild;
|
|
123
|
+
if (!rebuilt || rebuilt.nodeName !== 'CAPTION') {
|
|
124
|
+
existing?.remove();
|
|
125
|
+
return;
|
|
106
126
|
}
|
|
127
|
+
// Editor-only. The caption is not part of `contentDOM`, so a caret must not
|
|
128
|
+
// enter it. `toDOM` no longer stamps this: clipboard serialization shares
|
|
129
|
+
// that path and would persist the marker. This view never runs on save.
|
|
130
|
+
rebuilt.setAttribute('contenteditable', 'false');
|
|
131
|
+
rebuilt.setAttribute('data-openleaf-caption', html);
|
|
132
|
+
// A caption must be the table's first child for the browser to render it.
|
|
133
|
+
if (existing)
|
|
134
|
+
existing.replaceWith(rebuilt);
|
|
135
|
+
else
|
|
136
|
+
this.table.insertBefore(rebuilt, this.table.firstChild);
|
|
107
137
|
}
|
|
108
|
-
if (tablePos < 0)
|
|
109
|
-
return tr;
|
|
110
|
-
const table = tr.doc.nodeAt(tablePos);
|
|
111
|
-
if (!table)
|
|
112
|
-
return tr;
|
|
113
|
-
// Walked by row and column rather than as a flat descendant list, because a
|
|
114
|
-
// header's scope depends on where it sits. `setNodeMarkup` only changes
|
|
115
|
-
// attributes, so every node keeps its size and these positions stay valid.
|
|
116
|
-
table.forEach((row, rowOffset, rowIndex) => {
|
|
117
|
-
const rowPos = tablePos + 1 + rowOffset;
|
|
118
|
-
row.forEach((cellNode, cellOffset, cellIndex) => {
|
|
119
|
-
const pos = rowPos + 1 + cellOffset;
|
|
120
|
-
if (cellNode.type === cell && cellNode.attrs['scope']) {
|
|
121
|
-
tr.setNodeMarkup(pos, undefined, { ...cellNode.attrs, scope: null });
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (cellNode.type !== header)
|
|
125
|
-
return;
|
|
126
|
-
const scope = cellNode.attrs['scope'];
|
|
127
|
-
if (scope !== null && scope !== undefined && scope !== '')
|
|
128
|
-
return;
|
|
129
|
-
// A header in the top row labels a column. A header that opens a later
|
|
130
|
-
// row labels that row -- writing "col" there tells a screen reader the
|
|
131
|
-
// opposite of the truth, which is worse than the missing scope this
|
|
132
|
-
// replaces.
|
|
133
|
-
tr.setNodeMarkup(pos, undefined, {
|
|
134
|
-
...cellNode.attrs,
|
|
135
|
-
scope: rowIndex === 0 || cellIndex > 0 ? 'col' : 'row',
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
return tr;
|
|
140
|
-
}
|
|
141
|
-
function withCellScope(command) {
|
|
142
|
-
return (state, dispatch, view) => {
|
|
143
|
-
if (!dispatch)
|
|
144
|
-
return command(state, undefined, view);
|
|
145
|
-
return command(state, (tr) => {
|
|
146
|
-
dispatch(applyCellScope(tr));
|
|
147
|
-
}, view);
|
|
148
|
-
};
|
|
149
138
|
}
|
|
150
|
-
export const addColumnAfter = withCellScope(addColumnAfterRaw);
|
|
151
|
-
export const addColumnBefore = withCellScope(addColumnBeforeRaw);
|
|
152
|
-
export const addRowAfter = withCellScope(addRowAfterRaw);
|
|
153
|
-
export const addRowBefore = withCellScope(addRowBeforeRaw);
|
|
154
|
-
export const toggleHeaderRow = withCellScope(toggleHeaderRowRaw);
|
|
155
139
|
/** The ProseMirror plugins table editing needs. */
|
|
156
140
|
export function tableEditingPlugins() {
|
|
157
141
|
return [
|
|
158
142
|
// Resizing must come first: it reads cell geometry that tableEditing's
|
|
159
143
|
// selection handling would otherwise have already consumed.
|
|
160
|
-
columnResizing(),
|
|
144
|
+
columnResizing({ View: CaptionedTableView }),
|
|
161
145
|
tableEditing({ allowTableNodeSelection: true }),
|
|
146
|
+
colgroupSyncPlugin(),
|
|
147
|
+
tableContextMenu(),
|
|
162
148
|
];
|
|
163
149
|
}
|
|
164
150
|
let installed = false;
|
|
@@ -173,15 +159,35 @@ export function installTableEditing() {
|
|
|
173
159
|
return;
|
|
174
160
|
installed = true;
|
|
175
161
|
registerIcons(TABLE_ICON_PATHS);
|
|
162
|
+
registerStyles(TABLE_UI_CSS);
|
|
176
163
|
registerEditorPlugin(() => tableEditingPlugins());
|
|
177
164
|
registerToolbarItem({
|
|
178
165
|
id: 'insertTable',
|
|
179
|
-
type: '
|
|
180
|
-
kind: 'action',
|
|
166
|
+
type: 'custom',
|
|
181
167
|
label: 'Insert table',
|
|
182
168
|
icon: 'table',
|
|
183
|
-
|
|
169
|
+
render: (ctx) => buildInsertGrid(ctx),
|
|
170
|
+
isEnabled: (state) => insertTable()(state),
|
|
184
171
|
});
|
|
172
|
+
const dialogs = [
|
|
173
|
+
['tableProperties', 'Table properties', 'tableProperties', openTableProperties],
|
|
174
|
+
['rowProperties', 'Row properties', 'rowProperties', openRowProperties],
|
|
175
|
+
['cellProperties', 'Cell properties', 'cellProperties', openCellProperties],
|
|
176
|
+
['tableCaption', 'Table caption', 'tableCaption', openCaptionDialog],
|
|
177
|
+
];
|
|
178
|
+
for (const [id, label, icon, open] of dialogs) {
|
|
179
|
+
registerToolbarItem({
|
|
180
|
+
id,
|
|
181
|
+
type: 'button',
|
|
182
|
+
kind: 'action',
|
|
183
|
+
label,
|
|
184
|
+
icon,
|
|
185
|
+
run: ({ view, host }) => {
|
|
186
|
+
void open(view, host);
|
|
187
|
+
},
|
|
188
|
+
isEnabled: (state) => inTable(state),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
185
191
|
const commands = [
|
|
186
192
|
['addRowBefore', 'Insert row above', addRowBefore],
|
|
187
193
|
['addRowAfter', 'Insert row below', addRowAfter],
|
|
@@ -214,12 +220,12 @@ export function installTableEditing() {
|
|
|
214
220
|
label,
|
|
215
221
|
...(icons[id] ? { icon: icons[id] } : {}),
|
|
216
222
|
command,
|
|
217
|
-
// Every one of these is meaningless outside a table. Reporting them as
|
|
218
|
-
// disabled rather than letting them silently no-op is the difference
|
|
219
|
-
// between a control that looks broken and one that looks unavailable.
|
|
220
223
|
isEnabled: (state) => inTable(state) && command(state),
|
|
221
224
|
});
|
|
222
225
|
}
|
|
223
226
|
}
|
|
224
|
-
export { deleteColumn, deleteRow,
|
|
227
|
+
export { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, colgroupHtmlWithWidths, colgroupSyncPlugin, deleteColumn, deleteRow, inTable, insertTable, mergeStyle, setCellAttrs, setCellVerticalAlign, setRowAttrs, setTableAttrs, setTableCaption, setTableColgroup, styleValueOrNull, toggleHeaderRow, widthsFromColgroup, } from './commands.js';
|
|
228
|
+
export { buildInsertGrid, GRID_SIZE } from './grid.js';
|
|
229
|
+
export { tableContextMenu } from './menu.js';
|
|
230
|
+
export { deleteTable, mergeCells, splitCell, } from 'prosemirror-tables';
|
|
225
231
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/menu.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table context menu.
|
|
3
|
+
*
|
|
4
|
+
* Right-click (and Shift+F10, which fires `contextmenu`) on a table opens the
|
|
5
|
+
* same commands the toolbar exposes, plus the property dialogs. Authors who
|
|
6
|
+
* live in the document rather than the bar should not have to leave the cell
|
|
7
|
+
* they are editing to add a row.
|
|
8
|
+
*
|
|
9
|
+
* Bound on `view.dom` rather than `handleDOMEvents`, because cell-selection
|
|
10
|
+
* handling in `prosemirror-tables` can swallow the event before a later plugin
|
|
11
|
+
* sees it. A capture listener on the editable surface always runs first.
|
|
12
|
+
*
|
|
13
|
+
* That is also what takes this menu out of ProseMirror's `editable` gate, which
|
|
14
|
+
* is the guard typing, paste, drop and the keymaps get for free -- so read-only
|
|
15
|
+
* has to be checked here explicitly, and it was not. A read-only editor opened
|
|
16
|
+
* this menu with all fourteen entries live and Delete row worked, from the mouse
|
|
17
|
+
* and from Shift+F10. The check is made in three places below rather than one,
|
|
18
|
+
* on purpose: at open time, in the enabled state each item advertises, and again
|
|
19
|
+
* before an item runs.
|
|
20
|
+
*/
|
|
21
|
+
import { Plugin } from 'prosemirror-state';
|
|
22
|
+
export declare function tableContextMenu(): Plugin;
|
|
23
|
+
//# sourceMappingURL=menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,MAAM,EAAiB,MAAM,mBAAmB,CAAA;AAyFzD,wBAAgB,gBAAgB,IAAI,MAAM,CA0LzC"}
|
package/dist/menu.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table context menu.
|
|
3
|
+
*
|
|
4
|
+
* Right-click (and Shift+F10, which fires `contextmenu`) on a table opens the
|
|
5
|
+
* same commands the toolbar exposes, plus the property dialogs. Authors who
|
|
6
|
+
* live in the document rather than the bar should not have to leave the cell
|
|
7
|
+
* they are editing to add a row.
|
|
8
|
+
*
|
|
9
|
+
* Bound on `view.dom` rather than `handleDOMEvents`, because cell-selection
|
|
10
|
+
* handling in `prosemirror-tables` can swallow the event before a later plugin
|
|
11
|
+
* sees it. A capture listener on the editable surface always runs first.
|
|
12
|
+
*
|
|
13
|
+
* That is also what takes this menu out of ProseMirror's `editable` gate, which
|
|
14
|
+
* is the guard typing, paste, drop and the keymaps get for free -- so read-only
|
|
15
|
+
* has to be checked here explicitly, and it was not. A read-only editor opened
|
|
16
|
+
* this menu with all fourteen entries live and Delete row worked, from the mouse
|
|
17
|
+
* and from Shift+F10. The check is made in three places below rather than one,
|
|
18
|
+
* on purpose: at open time, in the enabled state each item advertises, and again
|
|
19
|
+
* before an item runs.
|
|
20
|
+
*/
|
|
21
|
+
import { Plugin, TextSelection } from 'prosemirror-state';
|
|
22
|
+
import { deleteTable, mergeCells, splitCell } from 'prosemirror-tables';
|
|
23
|
+
import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, deleteColumn, deleteRow, findTable, inTable, toggleHeaderRow, } from './commands.js';
|
|
24
|
+
import { openCaptionDialog, openCellProperties, openRowProperties, openTableProperties } from './dialogs.js';
|
|
25
|
+
function commandItem(label, command) {
|
|
26
|
+
return {
|
|
27
|
+
label,
|
|
28
|
+
enabled: (view) => command(view.state),
|
|
29
|
+
run: (view) => {
|
|
30
|
+
command(view.state, view.dispatch, view);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function groups() {
|
|
35
|
+
return [
|
|
36
|
+
{
|
|
37
|
+
items: [
|
|
38
|
+
commandItem('Insert row above', addRowBefore),
|
|
39
|
+
commandItem('Insert row below', addRowAfter),
|
|
40
|
+
commandItem('Delete row', deleteRow),
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
items: [
|
|
45
|
+
commandItem('Insert column before', addColumnBefore),
|
|
46
|
+
commandItem('Insert column after', addColumnAfter),
|
|
47
|
+
commandItem('Delete column', deleteColumn),
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
items: [
|
|
52
|
+
commandItem('Merge cells', mergeCells),
|
|
53
|
+
commandItem('Split cell', splitCell),
|
|
54
|
+
commandItem('Toggle header row', toggleHeaderRow),
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
items: [
|
|
59
|
+
{
|
|
60
|
+
label: 'Table properties',
|
|
61
|
+
run: (view, host) => {
|
|
62
|
+
void openTableProperties(view, host);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: 'Row properties',
|
|
67
|
+
run: (view, host) => {
|
|
68
|
+
void openRowProperties(view, host);
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'Cell properties',
|
|
73
|
+
run: (view, host) => {
|
|
74
|
+
void openCellProperties(view, host);
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
label: 'Caption',
|
|
79
|
+
run: (view, host) => {
|
|
80
|
+
void openCaptionDialog(view, host);
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
items: [commandItem('Delete table', deleteTable)],
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
export function tableContextMenu() {
|
|
91
|
+
return new Plugin({
|
|
92
|
+
view(view) {
|
|
93
|
+
let menu = null;
|
|
94
|
+
let open = false;
|
|
95
|
+
const hostFor = () => view.dom.closest('openleaf-editor') ??
|
|
96
|
+
view.dom.parentElement ??
|
|
97
|
+
view.dom;
|
|
98
|
+
/**
|
|
99
|
+
* The gate everything else on this surface is behind.
|
|
100
|
+
*
|
|
101
|
+
* `view.editable` rather than the host's `readonly` attribute, because it
|
|
102
|
+
* is the flag ProseMirror itself consults before running an edit handler
|
|
103
|
+
* and the one `prosemirror-tables`' column resizing checks. The element
|
|
104
|
+
* derives it from the attribute (`editable: () => !hasAttribute(readonly)`)
|
|
105
|
+
* and a view mounted without the custom element can set it directly, so
|
|
106
|
+
* this covers both.
|
|
107
|
+
*
|
|
108
|
+
* Read at each use rather than captured once: it is re-evaluated whenever
|
|
109
|
+
* the attribute changes.
|
|
110
|
+
*/
|
|
111
|
+
const isReadonly = () => !view.editable;
|
|
112
|
+
const close = (returnFocus = false) => {
|
|
113
|
+
if (!open || !menu)
|
|
114
|
+
return;
|
|
115
|
+
menu.hidden = true;
|
|
116
|
+
open = false;
|
|
117
|
+
view.dom.ownerDocument.removeEventListener('pointerdown', onPointerDown, true);
|
|
118
|
+
if (returnFocus)
|
|
119
|
+
view.focus();
|
|
120
|
+
};
|
|
121
|
+
const onPointerDown = (event) => {
|
|
122
|
+
const target = event.target;
|
|
123
|
+
if (!(target instanceof Node) || menu?.contains(target))
|
|
124
|
+
return;
|
|
125
|
+
close();
|
|
126
|
+
};
|
|
127
|
+
const fill = () => {
|
|
128
|
+
if (!menu)
|
|
129
|
+
return;
|
|
130
|
+
menu.replaceChildren();
|
|
131
|
+
const doc = menu.ownerDocument;
|
|
132
|
+
for (const group of groups()) {
|
|
133
|
+
const list = doc.createElement('div');
|
|
134
|
+
list.className = 'ol-table-menu-group';
|
|
135
|
+
for (const item of group.items) {
|
|
136
|
+
const button = doc.createElement('button');
|
|
137
|
+
button.type = 'button';
|
|
138
|
+
button.className = 'ol-table-menu-item';
|
|
139
|
+
button.setAttribute('role', 'menuitem');
|
|
140
|
+
button.tabIndex = -1;
|
|
141
|
+
button.textContent = item.label;
|
|
142
|
+
// Nothing here edits a read-only document, so nothing here
|
|
143
|
+
// advertises that it can. Unreachable today, because the menu is
|
|
144
|
+
// never filled while read-only -- kept so a future entry point into
|
|
145
|
+
// the same menu cannot reintroduce the defect.
|
|
146
|
+
const enabled = !isReadonly() && (item.enabled ? item.enabled(view) : true);
|
|
147
|
+
button.setAttribute('aria-disabled', enabled ? 'false' : 'true');
|
|
148
|
+
button.addEventListener('click', () => {
|
|
149
|
+
// `enabled` was computed when the menu was filled, and read-only
|
|
150
|
+
// can arrive after that. Re-asked here so a menu that was
|
|
151
|
+
// legitimately open a moment ago cannot still act.
|
|
152
|
+
if (!enabled || isReadonly())
|
|
153
|
+
return;
|
|
154
|
+
close();
|
|
155
|
+
item.run(view, hostFor());
|
|
156
|
+
});
|
|
157
|
+
list.appendChild(button);
|
|
158
|
+
}
|
|
159
|
+
menu.appendChild(list);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const showAt = (x, y) => {
|
|
163
|
+
const host = hostFor();
|
|
164
|
+
if (!menu) {
|
|
165
|
+
menu = host.ownerDocument.createElement('div');
|
|
166
|
+
menu.className = 'ol-table-menu';
|
|
167
|
+
menu.setAttribute('role', 'menu');
|
|
168
|
+
menu.setAttribute('aria-label', 'Table');
|
|
169
|
+
host.appendChild(menu);
|
|
170
|
+
}
|
|
171
|
+
fill();
|
|
172
|
+
menu.hidden = false;
|
|
173
|
+
menu.style.position = 'fixed';
|
|
174
|
+
menu.style.left = `${Math.round(x)}px`;
|
|
175
|
+
menu.style.top = `${Math.round(y)}px`;
|
|
176
|
+
open = true;
|
|
177
|
+
view.dom.ownerDocument.addEventListener('pointerdown', onPointerDown, true);
|
|
178
|
+
focusItem(menu.querySelector('button:not([aria-disabled="true"])'));
|
|
179
|
+
};
|
|
180
|
+
const onContextMenu = (event) => {
|
|
181
|
+
if (!(event instanceof MouseEvent))
|
|
182
|
+
return;
|
|
183
|
+
// Before anything else, and before `preventDefault`: a read-only author
|
|
184
|
+
// should get the browser's own menu -- copy, inspect -- not a table
|
|
185
|
+
// editor. Shift+F10 fires `contextmenu` too, so this closes the keyboard
|
|
186
|
+
// route with the same line.
|
|
187
|
+
if (isReadonly())
|
|
188
|
+
return;
|
|
189
|
+
// Every item in this menu acts on `state.selection`, and a secondary
|
|
190
|
+
// click does not always move it -- right-clicking a second table while a
|
|
191
|
+
// cell selection is live in the first leaves the old one in place. Read
|
|
192
|
+
// the position under the pointer and work from that, or Delete table
|
|
193
|
+
// deletes the table the author did not click.
|
|
194
|
+
const at = view.posAtCoords({ left: event.clientX, top: event.clientY });
|
|
195
|
+
if (!at)
|
|
196
|
+
return;
|
|
197
|
+
const $pos = view.state.doc.resolve(at.pos);
|
|
198
|
+
if (!findTable($pos))
|
|
199
|
+
return;
|
|
200
|
+
// Only retargeted when the click lands outside the current selection: a
|
|
201
|
+
// right-click inside a multi-cell selection has to keep it, or "Delete
|
|
202
|
+
// row" would silently narrow to the one row under the pointer.
|
|
203
|
+
const { from, to } = view.state.selection;
|
|
204
|
+
if (at.pos < from || at.pos > to) {
|
|
205
|
+
view.dispatch(view.state.tr.setSelection(TextSelection.near($pos)));
|
|
206
|
+
}
|
|
207
|
+
if (!inTable(view.state))
|
|
208
|
+
return;
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
event.stopPropagation();
|
|
211
|
+
showAt(event.clientX, event.clientY);
|
|
212
|
+
};
|
|
213
|
+
/*
|
|
214
|
+
* Escape, and the arrow keys, bound on the MENU.
|
|
215
|
+
*
|
|
216
|
+
* They were bound on `view.dom`, which never saw them: `showAt` appends
|
|
217
|
+
* the menu to the editor host and moves focus into it, and because the
|
|
218
|
+
* element builds its chrome in the light DOM, `view.dom` is not an
|
|
219
|
+
* ancestor of the menu. Shift+F10 is a documented way in, so that left a
|
|
220
|
+
* widget with an entrance and no exit.
|
|
221
|
+
*/
|
|
222
|
+
const items = () => menu ? [...menu.querySelectorAll('[role="menuitem"]')] : [];
|
|
223
|
+
const focusItem = (next) => {
|
|
224
|
+
if (!next)
|
|
225
|
+
return;
|
|
226
|
+
for (const item of items())
|
|
227
|
+
item.tabIndex = item === next ? 0 : -1;
|
|
228
|
+
next.focus();
|
|
229
|
+
};
|
|
230
|
+
const onKeyDown = (event) => {
|
|
231
|
+
if (!open)
|
|
232
|
+
return;
|
|
233
|
+
// Tab out of a popup menu closes it rather than walking through it.
|
|
234
|
+
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
235
|
+
event.preventDefault();
|
|
236
|
+
close(true);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const all = items();
|
|
240
|
+
const index = all.indexOf(event.target);
|
|
241
|
+
if (index < 0)
|
|
242
|
+
return;
|
|
243
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
const delta = event.key === 'ArrowDown' ? 1 : -1;
|
|
246
|
+
focusItem(all[(index + delta + all.length) % all.length]);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (event.key === 'Home' || event.key === 'End') {
|
|
250
|
+
event.preventDefault();
|
|
251
|
+
focusItem(event.key === 'Home' ? all[0] : all[all.length - 1]);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
view.dom.addEventListener('contextmenu', onContextMenu);
|
|
255
|
+
view.dom.ownerDocument.addEventListener('keydown', onKeyDown, true);
|
|
256
|
+
return {
|
|
257
|
+
update() {
|
|
258
|
+
// Read-only can arrive while the menu is open: the element's
|
|
259
|
+
// `attributeChangedCallback` calls `#applyReadonly`, which calls
|
|
260
|
+
// `view.setProps({})` so the view re-reads `editable` -- and that runs
|
|
261
|
+
// the plugin views. An open menu is dismissed rather than left armed.
|
|
262
|
+
if (isReadonly())
|
|
263
|
+
close();
|
|
264
|
+
},
|
|
265
|
+
destroy() {
|
|
266
|
+
view.dom.removeEventListener('contextmenu', onContextMenu);
|
|
267
|
+
view.dom.ownerDocument.removeEventListener('keydown', onKeyDown, true);
|
|
268
|
+
close();
|
|
269
|
+
menu?.remove();
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=menu.js.map
|
package/dist/menu.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.js","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"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"}
|