@milkdown/preset-gfm 6.1.5 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/auto-link.d.ts.map +1 -1
- package/lib/footnote/definition.d.ts +1 -5
- package/lib/footnote/definition.d.ts.map +1 -1
- package/lib/footnote/reference.d.ts +1 -5
- package/lib/footnote/reference.d.ts.map +1 -1
- package/lib/index.d.ts +1 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +1671 -16
- package/lib/index.es.js.map +1 -1
- package/lib/strike-through.d.ts +1 -5
- package/lib/strike-through.d.ts.map +1 -1
- package/lib/table/command.d.ts +1 -1
- package/lib/table/command.d.ts.map +1 -1
- package/lib/table/nodes/cell-selection.d.ts +38 -0
- package/lib/table/nodes/cell-selection.d.ts.map +1 -0
- package/lib/table/nodes/column-resizing.d.ts +10 -0
- package/lib/table/nodes/column-resizing.d.ts.map +1 -0
- package/lib/table/nodes/commands.d.ts +30 -0
- package/lib/table/nodes/commands.d.ts.map +1 -0
- package/lib/table/nodes/copy-paste.d.ts +13 -0
- package/lib/table/nodes/copy-paste.d.ts.map +1 -0
- package/lib/table/nodes/fix-tables.d.ts +6 -0
- package/lib/table/nodes/fix-tables.d.ts.map +1 -0
- package/lib/table/nodes/index.d.ts +5 -23
- package/lib/table/nodes/index.d.ts.map +1 -1
- package/lib/table/nodes/schema.d.ts +3 -1
- package/lib/table/nodes/schema.d.ts.map +1 -1
- package/lib/table/nodes/table-editing.d.ts +9 -0
- package/lib/table/nodes/table-editing.d.ts.map +1 -0
- package/lib/table/nodes/table-map.d.ts +44 -0
- package/lib/table/nodes/table-map.d.ts.map +1 -0
- package/lib/table/nodes/table-view.d.ts +15 -0
- package/lib/table/nodes/table-view.d.ts.map +1 -0
- package/lib/table/nodes/types.d.ts +15 -0
- package/lib/table/nodes/types.d.ts.map +1 -0
- package/lib/table/nodes/util.d.ts +16 -0
- package/lib/table/nodes/util.d.ts.map +1 -0
- package/lib/table/operator-plugin/actions.d.ts +1 -1
- package/lib/table/operator-plugin/actions.d.ts.map +1 -1
- package/lib/table/operator-plugin/calc-pos.d.ts.map +1 -1
- package/lib/table/operator-plugin/helper.d.ts +1 -1
- package/lib/table/operator-plugin/helper.d.ts.map +1 -1
- package/lib/table/operator-plugin/index.d.ts +1 -1
- package/lib/table/operator-plugin/index.d.ts.map +1 -1
- package/lib/table/operator-plugin/widget.d.ts +4 -4
- package/lib/table/operator-plugin/widget.d.ts.map +1 -1
- package/lib/table/utils.d.ts +4 -4
- package/lib/table/utils.d.ts.map +1 -1
- package/lib/task-list-item.d.ts +1 -5
- package/lib/task-list-item.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/auto-link.ts +4 -3
- package/src/table/command.ts +3 -3
- package/src/table/nodes/cell-selection.ts +352 -0
- package/src/table/nodes/column-resizing.ts +260 -0
- package/src/table/nodes/commands.ts +551 -0
- package/src/table/nodes/copy-paste.ts +306 -0
- package/src/table/nodes/fix-tables.ts +117 -0
- package/src/table/nodes/index.ts +7 -1
- package/src/table/nodes/schema.ts +100 -2
- package/src/table/nodes/table-editing.ts +275 -0
- package/src/table/nodes/table-map.ts +280 -0
- package/src/table/nodes/table-view.ts +76 -0
- package/src/table/nodes/types.ts +16 -0
- package/src/table/nodes/util.ts +107 -0
- package/src/table/operator-plugin/actions.ts +4 -4
- package/src/table/operator-plugin/calc-pos.ts +2 -1
- package/src/table/operator-plugin/helper.ts +2 -1
- package/src/table/operator-plugin/index.ts +1 -1
- package/src/table/operator-plugin/widget.ts +4 -14
- package/src/table/utils.ts +5 -2
- package/src/task-list-item.ts +2 -1
package/lib/index.es.js
CHANGED
|
@@ -24,27 +24,33 @@ import remarkGFM from "remark-gfm";
|
|
|
24
24
|
import { inputRules, InputRule, wrappingInputRule } from "@milkdown/prose/inputrules";
|
|
25
25
|
import { createCmdKey, editorViewCtx, createCmd, commandsCtx, themeManagerCtx, ThemeIcon, ThemeBorder, ThemeShadow, getPalette, ThemeSize, schemaCtx } from "@milkdown/core";
|
|
26
26
|
import { findSelectedNodeOfType, findParentNode, cloneTr, calculateNodePosition, markRule } from "@milkdown/prose";
|
|
27
|
-
import { PluginKey, NodeSelection, Plugin, Selection, TextSelection } from "@milkdown/prose/state";
|
|
27
|
+
import { PluginKey, NodeSelection, Plugin, Selection, SelectionRange, TextSelection } from "@milkdown/prose/state";
|
|
28
28
|
import { toggleMark, wrapIn } from "@milkdown/prose/commands";
|
|
29
|
-
import {
|
|
29
|
+
import { Fragment, Slice } from "@milkdown/prose/model";
|
|
30
30
|
import { Decoration, DecorationSet } from "@milkdown/prose/view";
|
|
31
|
+
import { keydownHandler } from "@milkdown/prose/keymap";
|
|
32
|
+
import { Transform } from "@milkdown/prose/transform";
|
|
31
33
|
import { splitListItem, sinkListItem, liftListItem } from "@milkdown/prose/schema-list";
|
|
32
34
|
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$/;
|
|
33
35
|
const proseUrlPlugin = () => inputRules({
|
|
34
36
|
rules: [
|
|
35
37
|
new InputRule(urlRegex, (state, match, start, end) => {
|
|
38
|
+
var _a;
|
|
36
39
|
const { schema: schema2 } = state;
|
|
37
40
|
const [text2] = match;
|
|
38
41
|
if (!text2)
|
|
39
42
|
return null;
|
|
40
|
-
|
|
43
|
+
const link2 = (_a = schema2.marks["link"]) == null ? void 0 : _a.create({ href: text2 });
|
|
44
|
+
if (!link2)
|
|
45
|
+
return null;
|
|
46
|
+
return state.tr.replaceWith(start, end, schema2.text(text2)).addMark(start, text2.length + start, link2);
|
|
41
47
|
})
|
|
42
48
|
]
|
|
43
49
|
});
|
|
44
50
|
const urlPlugin = $prose(() => proseUrlPlugin());
|
|
45
51
|
const getFootnoteRefId = (label) => `footnote-ref-${label}`;
|
|
46
52
|
const getFootnoteDefId = (label) => `footnote-def-${label}`;
|
|
47
|
-
const key$
|
|
53
|
+
const key$2 = new PluginKey("MILKDOWN_FOOTNOTE_DEF_INPUT");
|
|
48
54
|
const ModifyFootnoteDef = createCmdKey("ModifyFootnoteDef");
|
|
49
55
|
const footnoteDefinition = createNode((utils) => {
|
|
50
56
|
const id2 = "footnote_definition";
|
|
@@ -143,7 +149,7 @@ const footnoteDefinition = createNode((utils) => {
|
|
|
143
149
|
prosePlugins: (type, ctx) => {
|
|
144
150
|
return [
|
|
145
151
|
new Plugin({
|
|
146
|
-
key: key$
|
|
152
|
+
key: key$2,
|
|
147
153
|
view: (editorView) => {
|
|
148
154
|
const inputChipRenderer = utils.themeManager.get("input-chip", {
|
|
149
155
|
width: "12em",
|
|
@@ -195,7 +201,7 @@ const footnoteDefinition = createNode((utils) => {
|
|
|
195
201
|
};
|
|
196
202
|
});
|
|
197
203
|
const ModifyFootnoteRef = createCmdKey("ModifyFootnoteRef");
|
|
198
|
-
const key = new PluginKey("MILKDOWN_FOOTNOTE_REF_INPUT");
|
|
204
|
+
const key$1 = new PluginKey("MILKDOWN_FOOTNOTE_REF_INPUT");
|
|
199
205
|
const footnoteReference = createNode((utils) => {
|
|
200
206
|
const id2 = "footnote_reference";
|
|
201
207
|
return {
|
|
@@ -326,7 +332,7 @@ const footnoteReference = createNode((utils) => {
|
|
|
326
332
|
};
|
|
327
333
|
return [
|
|
328
334
|
new Plugin({
|
|
329
|
-
key,
|
|
335
|
+
key: key$1,
|
|
330
336
|
view: (editorView) => {
|
|
331
337
|
inputChipRenderer.init(editorView);
|
|
332
338
|
renderByView(editorView);
|
|
@@ -347,6 +353,684 @@ const footnoteReference = createNode((utils) => {
|
|
|
347
353
|
}
|
|
348
354
|
};
|
|
349
355
|
});
|
|
356
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
357
|
+
const readFromCache = (key2) => cache.get(key2);
|
|
358
|
+
const addToCache = (key2, value) => {
|
|
359
|
+
cache.set(key2, value);
|
|
360
|
+
return value;
|
|
361
|
+
};
|
|
362
|
+
class Rect {
|
|
363
|
+
constructor(left, top, right, bottom) {
|
|
364
|
+
this.left = left;
|
|
365
|
+
this.top = top;
|
|
366
|
+
this.right = right;
|
|
367
|
+
this.bottom = bottom;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
class TableMap {
|
|
371
|
+
constructor(width, height, map, problems) {
|
|
372
|
+
this.width = width;
|
|
373
|
+
this.height = height;
|
|
374
|
+
this.map = map;
|
|
375
|
+
this.problems = problems;
|
|
376
|
+
this.width = width;
|
|
377
|
+
this.height = height;
|
|
378
|
+
this.map = map;
|
|
379
|
+
this.problems = problems;
|
|
380
|
+
}
|
|
381
|
+
findCell(pos) {
|
|
382
|
+
for (let i = 0; i < this.map.length; i++) {
|
|
383
|
+
const curPos = this.map[i];
|
|
384
|
+
if (curPos != pos)
|
|
385
|
+
continue;
|
|
386
|
+
const left = i % this.width, top = i / this.width | 0;
|
|
387
|
+
let right = left + 1, bottom = top + 1;
|
|
388
|
+
for (let j = 1; right < this.width && this.map[i + j] == curPos; j++)
|
|
389
|
+
right++;
|
|
390
|
+
for (let j = 1; bottom < this.height && this.map[i + this.width * j] == curPos; j++)
|
|
391
|
+
bottom++;
|
|
392
|
+
return new Rect(left, top, right, bottom);
|
|
393
|
+
}
|
|
394
|
+
throw new RangeError("No cell with offset " + pos + " found");
|
|
395
|
+
}
|
|
396
|
+
colCount(pos) {
|
|
397
|
+
for (let i = 0; i < this.map.length; i++)
|
|
398
|
+
if (this.map[i] == pos)
|
|
399
|
+
return i % this.width;
|
|
400
|
+
throw new RangeError("No cell with offset " + pos + " found");
|
|
401
|
+
}
|
|
402
|
+
nextCell(pos, axis, dir) {
|
|
403
|
+
const { left, right, top, bottom } = this.findCell(pos);
|
|
404
|
+
if (axis == "horiz") {
|
|
405
|
+
if (dir < 0 ? left == 0 : right == this.width)
|
|
406
|
+
return void 0;
|
|
407
|
+
return this.map[top * this.width + (dir < 0 ? left - 1 : right)];
|
|
408
|
+
} else {
|
|
409
|
+
if (dir < 0 ? top == 0 : bottom == this.height)
|
|
410
|
+
return void 0;
|
|
411
|
+
return this.map[left + this.width * (dir < 0 ? top - 1 : bottom)];
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
rectBetween(a, b) {
|
|
415
|
+
const { left: leftA, right: rightA, top: topA, bottom: bottomA } = this.findCell(a);
|
|
416
|
+
const { left: leftB, right: rightB, top: topB, bottom: bottomB } = this.findCell(b);
|
|
417
|
+
return new Rect(Math.min(leftA, leftB), Math.min(topA, topB), Math.max(rightA, rightB), Math.max(bottomA, bottomB));
|
|
418
|
+
}
|
|
419
|
+
cellsInRect(rect) {
|
|
420
|
+
const result = [], seen = {};
|
|
421
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
422
|
+
for (let col = rect.left; col < rect.right; col++) {
|
|
423
|
+
const index = row * this.width + col, pos = this.map[index];
|
|
424
|
+
if (seen[pos])
|
|
425
|
+
continue;
|
|
426
|
+
seen[pos] = true;
|
|
427
|
+
if ((col != rect.left || !col || this.map[index - 1] != pos) && (row != rect.top || !row || this.map[index - this.width] != pos))
|
|
428
|
+
result.push(pos);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
positionAt(row, col, table2) {
|
|
434
|
+
for (let i = 0, rowStart = 0; ; i++) {
|
|
435
|
+
const rowEnd = rowStart + table2.child(i).nodeSize;
|
|
436
|
+
if (i == row) {
|
|
437
|
+
let index = col + row * this.width;
|
|
438
|
+
const rowEndIndex = (row + 1) * this.width;
|
|
439
|
+
while (index < rowEndIndex && this.map[index] < rowStart)
|
|
440
|
+
index++;
|
|
441
|
+
return index == rowEndIndex ? rowEnd - 1 : this.map[index];
|
|
442
|
+
}
|
|
443
|
+
rowStart = rowEnd;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
static get(table2) {
|
|
447
|
+
return readFromCache(table2) || addToCache(table2, computeMap(table2));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function computeMap(table2) {
|
|
451
|
+
if (table2.type.spec["tableRole"] != "table")
|
|
452
|
+
throw new RangeError("Not a table node: " + table2.type.name);
|
|
453
|
+
const width = findWidth(table2), height = table2.childCount;
|
|
454
|
+
const map = [];
|
|
455
|
+
const colWidths = [];
|
|
456
|
+
let mapPos = 0, problems = void 0;
|
|
457
|
+
for (let i = 0, e = width * height; i < e; i++)
|
|
458
|
+
map[i] = 0;
|
|
459
|
+
for (let row = 0, pos = 0; row < height; row++) {
|
|
460
|
+
const rowNode = table2.child(row);
|
|
461
|
+
pos++;
|
|
462
|
+
for (let i = 0; ; i++) {
|
|
463
|
+
while (mapPos < map.length && map[mapPos] != 0)
|
|
464
|
+
mapPos++;
|
|
465
|
+
if (i == rowNode.childCount)
|
|
466
|
+
break;
|
|
467
|
+
const cellNode = rowNode.child(i), { colspan, rowspan, colwidth } = cellNode.attrs;
|
|
468
|
+
for (let h = 0; h < rowspan; h++) {
|
|
469
|
+
if (h + row >= height) {
|
|
470
|
+
(problems || (problems = [])).push({
|
|
471
|
+
type: "overlong_rowspan",
|
|
472
|
+
pos,
|
|
473
|
+
n: rowspan - h
|
|
474
|
+
});
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
const start = mapPos + h * width;
|
|
478
|
+
for (let w = 0; w < colspan; w++) {
|
|
479
|
+
if (map[start + w] == 0)
|
|
480
|
+
map[start + w] = pos;
|
|
481
|
+
else
|
|
482
|
+
(problems || (problems = [])).push({
|
|
483
|
+
type: "collision",
|
|
484
|
+
row,
|
|
485
|
+
pos,
|
|
486
|
+
n: colspan - w
|
|
487
|
+
});
|
|
488
|
+
const colW = colwidth && colwidth[w];
|
|
489
|
+
if (colW) {
|
|
490
|
+
const widthIndex = (start + w) % width * 2, prev = colWidths[widthIndex];
|
|
491
|
+
if (prev == null || prev != colW && colWidths[widthIndex + 1] == 1) {
|
|
492
|
+
colWidths[widthIndex] = colW;
|
|
493
|
+
colWidths[widthIndex + 1] = 1;
|
|
494
|
+
} else if (prev == colW) {
|
|
495
|
+
colWidths[widthIndex + 1]++;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
mapPos += colspan;
|
|
501
|
+
pos += cellNode.nodeSize;
|
|
502
|
+
}
|
|
503
|
+
const expectedPos = (row + 1) * width;
|
|
504
|
+
let missing = 0;
|
|
505
|
+
while (mapPos < expectedPos)
|
|
506
|
+
if (map[mapPos++] == 0)
|
|
507
|
+
missing++;
|
|
508
|
+
if (missing)
|
|
509
|
+
(problems || (problems = [])).push({ type: "missing", row, n: missing });
|
|
510
|
+
pos++;
|
|
511
|
+
}
|
|
512
|
+
const tableMap = new TableMap(width, height, map, problems);
|
|
513
|
+
let badWidths = false;
|
|
514
|
+
for (let i = 0; !badWidths && i < colWidths.length; i += 2)
|
|
515
|
+
if (colWidths[i] != null && colWidths[i + 1] < height)
|
|
516
|
+
badWidths = true;
|
|
517
|
+
if (badWidths)
|
|
518
|
+
findBadColWidths(tableMap, colWidths, table2);
|
|
519
|
+
return tableMap;
|
|
520
|
+
}
|
|
521
|
+
function findWidth(table2) {
|
|
522
|
+
let width = -1, hasRowSpan = false;
|
|
523
|
+
for (let row = 0; row < table2.childCount; row++) {
|
|
524
|
+
const rowNode = table2.child(row);
|
|
525
|
+
let rowWidth = 0;
|
|
526
|
+
if (hasRowSpan)
|
|
527
|
+
for (let j = 0; j < row; j++) {
|
|
528
|
+
const prevRow = table2.child(j);
|
|
529
|
+
for (let i = 0; i < prevRow.childCount; i++) {
|
|
530
|
+
const cell = prevRow.child(i);
|
|
531
|
+
if (j + cell.attrs["rowspan"] > row)
|
|
532
|
+
rowWidth += cell.attrs["colspan"];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
for (let i = 0; i < rowNode.childCount; i++) {
|
|
536
|
+
const cell = rowNode.child(i);
|
|
537
|
+
rowWidth += cell.attrs["colspan"];
|
|
538
|
+
if (cell.attrs["rowspan"] > 1)
|
|
539
|
+
hasRowSpan = true;
|
|
540
|
+
}
|
|
541
|
+
if (width == -1)
|
|
542
|
+
width = rowWidth;
|
|
543
|
+
else if (width != rowWidth)
|
|
544
|
+
width = Math.max(width, rowWidth);
|
|
545
|
+
}
|
|
546
|
+
return width;
|
|
547
|
+
}
|
|
548
|
+
function findBadColWidths(map, colWidths, table2) {
|
|
549
|
+
if (!map.problems)
|
|
550
|
+
map.problems = [];
|
|
551
|
+
for (let i = 0, seen = {}; i < map.map.length; i++) {
|
|
552
|
+
const pos = map.map[i];
|
|
553
|
+
if (seen[pos])
|
|
554
|
+
continue;
|
|
555
|
+
seen[pos] = true;
|
|
556
|
+
const node = table2.nodeAt(pos);
|
|
557
|
+
let updated = null;
|
|
558
|
+
for (let j = 0; j < node.attrs["colspan"]; j++) {
|
|
559
|
+
const col = (i + j) % map.width, colWidth = colWidths[col * 2];
|
|
560
|
+
if (colWidth != null && (!node.attrs["colwidth"] || node.attrs["colwidth"][j] != colWidth))
|
|
561
|
+
(updated || (updated = freshColWidth(node.attrs)))[j] = colWidth;
|
|
562
|
+
}
|
|
563
|
+
if (updated)
|
|
564
|
+
map.problems.unshift({
|
|
565
|
+
type: "colwidth mismatch",
|
|
566
|
+
pos,
|
|
567
|
+
colwidth: updated
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function freshColWidth(attrs) {
|
|
572
|
+
if (attrs["colwidth"])
|
|
573
|
+
return attrs["colwidth"].slice();
|
|
574
|
+
const result = [];
|
|
575
|
+
for (let i = 0; i < attrs["colspan"]; i++)
|
|
576
|
+
result.push(0);
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
class CellSelection extends Selection {
|
|
580
|
+
constructor($anchorCell, $headCell = $anchorCell) {
|
|
581
|
+
const table2 = $anchorCell.node(-1), map = TableMap.get(table2), start = $anchorCell.start(-1);
|
|
582
|
+
const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
583
|
+
const doc2 = $anchorCell.node(0);
|
|
584
|
+
const cells = map.cellsInRect(rect).filter((p) => p != $headCell.pos - start);
|
|
585
|
+
cells.unshift($headCell.pos - start);
|
|
586
|
+
const ranges = cells.map((pos) => {
|
|
587
|
+
const cell = table2.nodeAt(pos), from = pos + start + 1;
|
|
588
|
+
return new SelectionRange(doc2.resolve(from), doc2.resolve(from + cell.content.size));
|
|
589
|
+
});
|
|
590
|
+
super(ranges[0].$from, ranges[0].$to, ranges);
|
|
591
|
+
this.$anchorCell = $anchorCell;
|
|
592
|
+
this.$headCell = $headCell;
|
|
593
|
+
this.$anchorCell = $anchorCell;
|
|
594
|
+
this.$headCell = $headCell;
|
|
595
|
+
}
|
|
596
|
+
map(doc2, mapping) {
|
|
597
|
+
const $anchorCell = doc2.resolve(mapping.map(this.$anchorCell.pos));
|
|
598
|
+
const $headCell = doc2.resolve(mapping.map(this.$headCell.pos));
|
|
599
|
+
if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
|
|
600
|
+
const tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1);
|
|
601
|
+
if (tableChanged && this.isRowSelection())
|
|
602
|
+
return CellSelection.rowSelection($anchorCell, $headCell);
|
|
603
|
+
else if (tableChanged && this.isColSelection())
|
|
604
|
+
return CellSelection.colSelection($anchorCell, $headCell);
|
|
605
|
+
else
|
|
606
|
+
return new CellSelection($anchorCell, $headCell);
|
|
607
|
+
}
|
|
608
|
+
return TextSelection.between($anchorCell, $headCell);
|
|
609
|
+
}
|
|
610
|
+
content() {
|
|
611
|
+
const table2 = this.$anchorCell.node(-1), map = TableMap.get(table2), start = this.$anchorCell.start(-1);
|
|
612
|
+
const rect = map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start);
|
|
613
|
+
const seen = {}, rows = [];
|
|
614
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
615
|
+
const rowContent = [];
|
|
616
|
+
for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
|
|
617
|
+
const pos = map.map[index];
|
|
618
|
+
if (!seen[pos]) {
|
|
619
|
+
seen[pos] = true;
|
|
620
|
+
const cellRect = map.findCell(pos);
|
|
621
|
+
let cell = table2.nodeAt(pos);
|
|
622
|
+
const extraLeft = rect.left - cellRect.left, extraRight = cellRect.right - rect.right;
|
|
623
|
+
if (extraLeft > 0 || extraRight > 0) {
|
|
624
|
+
let attrs = cell.attrs;
|
|
625
|
+
if (extraLeft > 0)
|
|
626
|
+
attrs = removeColSpan(attrs, 0, extraLeft);
|
|
627
|
+
if (extraRight > 0)
|
|
628
|
+
attrs = removeColSpan(attrs, attrs["colspan"] - extraRight, extraRight);
|
|
629
|
+
if (cellRect.left < rect.left)
|
|
630
|
+
cell = cell.type.createAndFill(attrs);
|
|
631
|
+
else
|
|
632
|
+
cell = cell.type.create(attrs, cell.content);
|
|
633
|
+
}
|
|
634
|
+
if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
|
|
635
|
+
const attrs = setAttr(cell.attrs, "rowspan", Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top));
|
|
636
|
+
if (cellRect.top < rect.top)
|
|
637
|
+
cell = cell.type.createAndFill(attrs);
|
|
638
|
+
else
|
|
639
|
+
cell = cell.type.create(attrs, cell.content);
|
|
640
|
+
}
|
|
641
|
+
rowContent.push(cell);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
rows.push(table2.child(row).copy(Fragment.from(rowContent)));
|
|
645
|
+
}
|
|
646
|
+
const fragment = this.isColSelection() && this.isRowSelection() ? table2 : rows;
|
|
647
|
+
return new Slice(Fragment.from(fragment), 1, 1);
|
|
648
|
+
}
|
|
649
|
+
replace(tr, content = Slice.empty) {
|
|
650
|
+
const mapFrom = tr.steps.length, ranges = this.ranges;
|
|
651
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
652
|
+
const { $from, $to } = ranges[i], mapping = tr.mapping.slice(mapFrom);
|
|
653
|
+
tr.replace(mapping.map($from.pos), mapping.map($to.pos), i ? Slice.empty : content);
|
|
654
|
+
}
|
|
655
|
+
const sel = Selection.findFrom(tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)), -1);
|
|
656
|
+
if (sel)
|
|
657
|
+
tr.setSelection(sel);
|
|
658
|
+
}
|
|
659
|
+
replaceWith(tr, node) {
|
|
660
|
+
this.replace(tr, new Slice(Fragment.from(node), 0, 0));
|
|
661
|
+
}
|
|
662
|
+
forEachCell(f) {
|
|
663
|
+
const table2 = this.$anchorCell.node(-1), map = TableMap.get(table2), start = this.$anchorCell.start(-1);
|
|
664
|
+
const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start));
|
|
665
|
+
for (let i = 0; i < cells.length; i++)
|
|
666
|
+
f(table2.nodeAt(cells[i]), start + cells[i]);
|
|
667
|
+
}
|
|
668
|
+
isColSelection() {
|
|
669
|
+
const anchorTop = this.$anchorCell.index(-1), headTop = this.$headCell.index(-1);
|
|
670
|
+
if (Math.min(anchorTop, headTop) > 0)
|
|
671
|
+
return false;
|
|
672
|
+
const anchorBot = anchorTop + this.$anchorCell.nodeAfter.attrs["rowspan"], headBot = headTop + this.$headCell.nodeAfter.attrs["rowspan"];
|
|
673
|
+
return Math.max(anchorBot, headBot) == this.$headCell.node(-1).childCount;
|
|
674
|
+
}
|
|
675
|
+
static colSelection($anchorCell, $headCell = $anchorCell) {
|
|
676
|
+
const map = TableMap.get($anchorCell.node(-1)), start = $anchorCell.start(-1);
|
|
677
|
+
const anchorRect = map.findCell($anchorCell.pos - start), headRect = map.findCell($headCell.pos - start);
|
|
678
|
+
const doc2 = $anchorCell.node(0);
|
|
679
|
+
if (anchorRect.top <= headRect.top) {
|
|
680
|
+
if (anchorRect.top > 0) {
|
|
681
|
+
const left = map.map[anchorRect.left];
|
|
682
|
+
$anchorCell = doc2.resolve(start + left);
|
|
683
|
+
}
|
|
684
|
+
if (headRect.bottom < map.height) {
|
|
685
|
+
const pos = map.map[map.width * (map.height - 1) + headRect.right - 1];
|
|
686
|
+
$headCell = doc2.resolve(start + pos);
|
|
687
|
+
}
|
|
688
|
+
} else {
|
|
689
|
+
if (headRect.top > 0) {
|
|
690
|
+
const left = map.map[anchorRect.left];
|
|
691
|
+
$headCell = doc2.resolve(start + left);
|
|
692
|
+
}
|
|
693
|
+
if (anchorRect.bottom < map.height) {
|
|
694
|
+
const pos = map.map[map.width * (map.height - 1) + anchorRect.right - 1];
|
|
695
|
+
$anchorCell = doc2.resolve(start + pos);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return new CellSelection($anchorCell, $headCell);
|
|
699
|
+
}
|
|
700
|
+
isRowSelection() {
|
|
701
|
+
const map = TableMap.get(this.$anchorCell.node(-1)), start = this.$anchorCell.start(-1);
|
|
702
|
+
const anchorLeft = map.colCount(this.$anchorCell.pos - start), headLeft = map.colCount(this.$headCell.pos - start);
|
|
703
|
+
if (Math.min(anchorLeft, headLeft) > 0)
|
|
704
|
+
return false;
|
|
705
|
+
const anchorRight = anchorLeft + this.$anchorCell.nodeAfter.attrs["colspan"], headRight = headLeft + this.$headCell.nodeAfter.attrs["colspan"];
|
|
706
|
+
return Math.max(anchorRight, headRight) == map.width;
|
|
707
|
+
}
|
|
708
|
+
eq(other) {
|
|
709
|
+
return other instanceof CellSelection && other.$anchorCell.pos == this.$anchorCell.pos && other.$headCell.pos == this.$headCell.pos;
|
|
710
|
+
}
|
|
711
|
+
static rowSelection($anchorCell, $headCell = $anchorCell) {
|
|
712
|
+
const map = TableMap.get($anchorCell.node(-1)), start = $anchorCell.start(-1);
|
|
713
|
+
const anchorRect = map.findCell($anchorCell.pos - start), headRect = map.findCell($headCell.pos - start);
|
|
714
|
+
const doc2 = $anchorCell.node(0);
|
|
715
|
+
if (anchorRect.left <= headRect.left) {
|
|
716
|
+
if (anchorRect.left > 0) {
|
|
717
|
+
const pos = map.map[anchorRect.top * map.width];
|
|
718
|
+
$anchorCell = doc2.resolve(start + pos);
|
|
719
|
+
}
|
|
720
|
+
if (headRect.right < map.width) {
|
|
721
|
+
const pos = map.map[map.width * (headRect.top + 1) - 1];
|
|
722
|
+
$headCell = doc2.resolve(start + pos);
|
|
723
|
+
}
|
|
724
|
+
} else {
|
|
725
|
+
if (headRect.left > 0) {
|
|
726
|
+
const pos = map.map[headRect.top * map.width];
|
|
727
|
+
$headCell = doc2.resolve(start + pos);
|
|
728
|
+
}
|
|
729
|
+
if (anchorRect.right < map.width) {
|
|
730
|
+
const pos = map.map[map.width * (anchorRect.top + 1) - 1];
|
|
731
|
+
$anchorCell = doc2.resolve(start + pos);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return new CellSelection($anchorCell, $headCell);
|
|
735
|
+
}
|
|
736
|
+
toJSON() {
|
|
737
|
+
return {
|
|
738
|
+
type: "cell",
|
|
739
|
+
anchor: this.$anchorCell.pos,
|
|
740
|
+
head: this.$headCell.pos
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
static fromJSON(doc2, json) {
|
|
744
|
+
return new CellSelection(doc2.resolve(json.anchor), doc2.resolve(json.head));
|
|
745
|
+
}
|
|
746
|
+
static create(doc2, anchorCell, headCell = anchorCell) {
|
|
747
|
+
return new CellSelection(doc2.resolve(anchorCell), doc2.resolve(headCell));
|
|
748
|
+
}
|
|
749
|
+
getBookmark() {
|
|
750
|
+
return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
CellSelection.prototype.visible = false;
|
|
754
|
+
Selection.jsonID("cell", CellSelection);
|
|
755
|
+
class CellBookmark {
|
|
756
|
+
constructor(anchor, head) {
|
|
757
|
+
this.anchor = anchor;
|
|
758
|
+
this.head = head;
|
|
759
|
+
this.anchor = anchor;
|
|
760
|
+
this.head = head;
|
|
761
|
+
}
|
|
762
|
+
map(mapping) {
|
|
763
|
+
return new CellBookmark(mapping.map(this.anchor), mapping.map(this.head));
|
|
764
|
+
}
|
|
765
|
+
resolve(doc2) {
|
|
766
|
+
const $anchorCell = doc2.resolve(this.anchor), $headCell = doc2.resolve(this.head);
|
|
767
|
+
if ($anchorCell.parent.type.spec["tableRole"] == "row" && $headCell.parent.type.spec["tableRole"] == "row" && $anchorCell.index() < $anchorCell.parent.childCount && $headCell.index() < $headCell.parent.childCount && inSameTable($anchorCell, $headCell))
|
|
768
|
+
return new CellSelection($anchorCell, $headCell);
|
|
769
|
+
else
|
|
770
|
+
return Selection.near($headCell, 1);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
function drawCellSelection(state) {
|
|
774
|
+
if (!(state.selection instanceof CellSelection))
|
|
775
|
+
return null;
|
|
776
|
+
const cells = [];
|
|
777
|
+
state.selection.forEachCell((node, pos) => {
|
|
778
|
+
cells.push(Decoration.node(pos, pos + node.nodeSize, { class: "selectedCell" }));
|
|
779
|
+
});
|
|
780
|
+
return DecorationSet.create(state.doc, cells);
|
|
781
|
+
}
|
|
782
|
+
function isCellBoundarySelection({ $from, $to }) {
|
|
783
|
+
if ($from.pos == $to.pos || $from.pos < $from.pos - 6)
|
|
784
|
+
return false;
|
|
785
|
+
let afterFrom = $from.pos, beforeTo = $to.pos, depth = $from.depth;
|
|
786
|
+
for (; depth >= 0; depth--, afterFrom++)
|
|
787
|
+
if ($from.after(depth + 1) < $from.end(depth))
|
|
788
|
+
break;
|
|
789
|
+
for (let d = $to.depth; d >= 0; d--, beforeTo--)
|
|
790
|
+
if ($to.before(d + 1) > $to.start(d))
|
|
791
|
+
break;
|
|
792
|
+
return afterFrom == beforeTo && /row|table/.test($from.node(depth).type.spec["tableRole"]);
|
|
793
|
+
}
|
|
794
|
+
function isTextSelectionAcrossCells({ $from, $to }) {
|
|
795
|
+
let fromCellBoundaryNode;
|
|
796
|
+
let toCellBoundaryNode;
|
|
797
|
+
for (let i = $from.depth; i > 0; i--) {
|
|
798
|
+
const node = $from.node(i);
|
|
799
|
+
if (node.type.spec["tableRole"] === "cell" || node.type.spec["tableRole"] === "header_cell") {
|
|
800
|
+
fromCellBoundaryNode = node;
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
for (let i = $to.depth; i > 0; i--) {
|
|
805
|
+
const node = $to.node(i);
|
|
806
|
+
if (node.type.spec["tableRole"] === "cell" || node.type.spec["tableRole"] === "header_cell") {
|
|
807
|
+
toCellBoundaryNode = node;
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return fromCellBoundaryNode !== toCellBoundaryNode && $to.parentOffset === 0;
|
|
812
|
+
}
|
|
813
|
+
function normalizeSelection(state, tr, allowTableNodeSelection) {
|
|
814
|
+
const sel = (tr || state).selection, doc2 = (tr || state).doc;
|
|
815
|
+
let normalize, role;
|
|
816
|
+
if (sel instanceof NodeSelection && (role = sel.node.type.spec["tableRole"])) {
|
|
817
|
+
if (role == "cell" || role == "header_cell") {
|
|
818
|
+
normalize = CellSelection.create(doc2, sel.from);
|
|
819
|
+
} else if (role == "row") {
|
|
820
|
+
const $cell = doc2.resolve(sel.from + 1);
|
|
821
|
+
normalize = CellSelection.rowSelection($cell, $cell);
|
|
822
|
+
} else if (!allowTableNodeSelection) {
|
|
823
|
+
const map = TableMap.get(sel.node), start = sel.from + 1;
|
|
824
|
+
const pos = map.map[map.width * map.height - 1];
|
|
825
|
+
const lastCell = start + pos;
|
|
826
|
+
normalize = CellSelection.create(doc2, start + 1, lastCell);
|
|
827
|
+
}
|
|
828
|
+
} else if (sel instanceof TextSelection && isCellBoundarySelection(sel)) {
|
|
829
|
+
normalize = TextSelection.create(doc2, sel.from);
|
|
830
|
+
} else if (sel instanceof TextSelection && isTextSelectionAcrossCells(sel)) {
|
|
831
|
+
normalize = TextSelection.create(doc2, sel.$from.start(), sel.$from.end());
|
|
832
|
+
}
|
|
833
|
+
if (normalize)
|
|
834
|
+
(tr || (tr = state.tr)).setSelection(normalize);
|
|
835
|
+
return tr;
|
|
836
|
+
}
|
|
837
|
+
function getCellAttrs(dom, extraAttrs) {
|
|
838
|
+
const widthAttr = dom.getAttribute("data-colwidth");
|
|
839
|
+
const widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(",").map((s) => Number(s)) : null;
|
|
840
|
+
const colspan = Number(dom.getAttribute("colspan") || 1);
|
|
841
|
+
const result = {
|
|
842
|
+
colspan,
|
|
843
|
+
rowspan: Number(dom.getAttribute("rowspan") || 1),
|
|
844
|
+
colwidth: widths && widths.length == colspan ? widths : null
|
|
845
|
+
};
|
|
846
|
+
for (const prop in extraAttrs) {
|
|
847
|
+
const getter = extraAttrs[prop].getFromDOM;
|
|
848
|
+
const value = getter && getter(dom);
|
|
849
|
+
if (value != null)
|
|
850
|
+
result[prop] = value;
|
|
851
|
+
}
|
|
852
|
+
return result;
|
|
853
|
+
}
|
|
854
|
+
function setCellAttrs(node, extraAttrs) {
|
|
855
|
+
const attrs = {};
|
|
856
|
+
if (node.attrs["colspan"] != 1)
|
|
857
|
+
attrs["colspan"] = node.attrs["colspan"];
|
|
858
|
+
if (node.attrs["rowspan"] != 1)
|
|
859
|
+
attrs["rowspan"] = node.attrs["rowspan"];
|
|
860
|
+
if (node.attrs["colwidth"])
|
|
861
|
+
attrs["data-colwidth"] = node.attrs["colwidth"].join(",");
|
|
862
|
+
for (const prop in extraAttrs) {
|
|
863
|
+
const setter = extraAttrs[prop].setDOMAttr;
|
|
864
|
+
if (setter)
|
|
865
|
+
setter(node.attrs[prop], attrs);
|
|
866
|
+
}
|
|
867
|
+
return attrs;
|
|
868
|
+
}
|
|
869
|
+
function tableNodesSpecCreator(options) {
|
|
870
|
+
const extraAttrs = options.cellAttributes || {};
|
|
871
|
+
const cellAttrs = {
|
|
872
|
+
colspan: { default: 1 },
|
|
873
|
+
rowspan: { default: 1 },
|
|
874
|
+
colwidth: { default: null }
|
|
875
|
+
};
|
|
876
|
+
for (const prop in extraAttrs)
|
|
877
|
+
cellAttrs[prop] = { default: extraAttrs[prop].default };
|
|
878
|
+
const finalAttrs = cellAttrs;
|
|
879
|
+
const schema2 = {
|
|
880
|
+
table: {
|
|
881
|
+
content: "table_row+",
|
|
882
|
+
tableRole: "table",
|
|
883
|
+
isolating: true,
|
|
884
|
+
group: options.tableGroup,
|
|
885
|
+
parseDOM: [{ tag: "table" }],
|
|
886
|
+
toDOM() {
|
|
887
|
+
return ["table", ["tbody", 0]];
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
table_row: {
|
|
891
|
+
content: "(table_cell | table_header)*",
|
|
892
|
+
tableRole: "row",
|
|
893
|
+
parseDOM: [{ tag: "tr" }],
|
|
894
|
+
toDOM() {
|
|
895
|
+
return ["tr", 0];
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
table_cell: {
|
|
899
|
+
content: options.cellContent,
|
|
900
|
+
attrs: finalAttrs,
|
|
901
|
+
tableRole: "cell",
|
|
902
|
+
isolating: true,
|
|
903
|
+
parseDOM: [{ tag: "td", getAttrs: (dom) => getCellAttrs(dom, extraAttrs) }],
|
|
904
|
+
toDOM(node) {
|
|
905
|
+
return ["td", setCellAttrs(node, extraAttrs), 0];
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
table_header: {
|
|
909
|
+
content: options.cellContent,
|
|
910
|
+
attrs: finalAttrs,
|
|
911
|
+
tableRole: "header_cell",
|
|
912
|
+
isolating: true,
|
|
913
|
+
parseDOM: [{ tag: "th", getAttrs: (dom) => getCellAttrs(dom, extraAttrs) }],
|
|
914
|
+
toDOM(node) {
|
|
915
|
+
return ["th", setCellAttrs(node, extraAttrs), 0];
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
return schema2;
|
|
920
|
+
}
|
|
921
|
+
function tableNodeTypes(schema2) {
|
|
922
|
+
let result = schema2.cached["tableNodeTypes"];
|
|
923
|
+
if (!result) {
|
|
924
|
+
result = schema2.cached["tableNodeTypes"] = {};
|
|
925
|
+
for (const name in schema2.nodes) {
|
|
926
|
+
const type = schema2.nodes[name], role = type == null ? void 0 : type.spec["tableRole"];
|
|
927
|
+
if (role)
|
|
928
|
+
result[role] = type;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return result;
|
|
932
|
+
}
|
|
933
|
+
const schema = tableNodesSpecCreator({
|
|
934
|
+
tableGroup: "block",
|
|
935
|
+
cellContent: "paragraph",
|
|
936
|
+
cellAttributes: {
|
|
937
|
+
alignment: {
|
|
938
|
+
default: "left",
|
|
939
|
+
getFromDOM: (dom) => dom.style.textAlign || "left",
|
|
940
|
+
setDOMAttr: (value, attrs) => {
|
|
941
|
+
attrs["style"] = `text-align: ${value || "left"}`;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
function cellAround($pos) {
|
|
947
|
+
for (let d = $pos.depth - 1; d > 0; d--)
|
|
948
|
+
if ($pos.node(d).type.spec["tableRole"] == "row")
|
|
949
|
+
return $pos.node(0).resolve($pos.before(d + 1));
|
|
950
|
+
return void 0;
|
|
951
|
+
}
|
|
952
|
+
function pointsAtCell($pos) {
|
|
953
|
+
if ($pos.parent.type.spec["tableRole"] == "row")
|
|
954
|
+
return $pos.nodeAfter;
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
function moveCellForward($pos) {
|
|
958
|
+
return $pos.node(0).resolve($pos.pos + $pos.nodeAfter.nodeSize);
|
|
959
|
+
}
|
|
960
|
+
function inSameTable($a, $b) {
|
|
961
|
+
return $a.depth == $b.depth && $a.pos >= $b.start(-1) && $a.pos <= $b.end(-1);
|
|
962
|
+
}
|
|
963
|
+
function nextCell($pos, axis, dir) {
|
|
964
|
+
const start = $pos.start(-1), map = TableMap.get($pos.node(-1));
|
|
965
|
+
const moved = map.nextCell($pos.pos - start, axis, dir);
|
|
966
|
+
return moved == null ? null : $pos.node(0).resolve(start + moved);
|
|
967
|
+
}
|
|
968
|
+
function setAttr(attrs, name, value) {
|
|
969
|
+
const result = {};
|
|
970
|
+
for (const prop in attrs)
|
|
971
|
+
result[prop] = attrs[prop];
|
|
972
|
+
result[name] = value;
|
|
973
|
+
return result;
|
|
974
|
+
}
|
|
975
|
+
function removeColSpan(attrs, pos, n = 1) {
|
|
976
|
+
const result = setAttr(attrs, "colspan", attrs["colspan"] - n);
|
|
977
|
+
if (result["colwidth"]) {
|
|
978
|
+
const widths = result["colwidth"];
|
|
979
|
+
result["colwidth"] = widths.slice();
|
|
980
|
+
widths.splice(pos, n);
|
|
981
|
+
if (!widths.some((w) => w > 0))
|
|
982
|
+
result["colwidth"] = null;
|
|
983
|
+
}
|
|
984
|
+
return result;
|
|
985
|
+
}
|
|
986
|
+
function isInTable(state) {
|
|
987
|
+
const $head = state.selection.$head;
|
|
988
|
+
for (let d = $head.depth; d > 0; d--)
|
|
989
|
+
if ($head.node(d).type.spec["tableRole"] == "row")
|
|
990
|
+
return true;
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
function selectionCell(state) {
|
|
994
|
+
const sel = state.selection;
|
|
995
|
+
if (sel instanceof CellSelection) {
|
|
996
|
+
return sel.$anchorCell.pos > sel.$headCell.pos ? sel.$anchorCell : sel.$headCell;
|
|
997
|
+
} else if (sel.node && sel.node.type.spec["tableRole"] == "cell") {
|
|
998
|
+
return sel.$anchor;
|
|
999
|
+
}
|
|
1000
|
+
return cellAround(sel.$head) || cellNear(sel.$head);
|
|
1001
|
+
}
|
|
1002
|
+
function cellNear($pos) {
|
|
1003
|
+
for (let after = $pos.nodeAfter, pos = $pos.pos; after; after = after.firstChild, pos++) {
|
|
1004
|
+
const role = after.type.spec["tableRole"];
|
|
1005
|
+
if (role == "cell" || role == "header_cell")
|
|
1006
|
+
return $pos.doc.resolve(pos);
|
|
1007
|
+
}
|
|
1008
|
+
for (let before = $pos.nodeBefore, pos = $pos.pos; before; before = before.lastChild, pos--) {
|
|
1009
|
+
const role = before.type.spec["tableRole"];
|
|
1010
|
+
if (role == "cell" || role == "header_cell")
|
|
1011
|
+
return $pos.doc.resolve(pos - before.nodeSize);
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
function addColSpan(attrs, pos, n = 1) {
|
|
1016
|
+
const result = setAttr(attrs, "colspan", attrs["colspan"] + n);
|
|
1017
|
+
if (result["colwidth"]) {
|
|
1018
|
+
const widths = result["colwidth"];
|
|
1019
|
+
result["colwidth"] = widths.slice();
|
|
1020
|
+
for (let i = 0; i < n; i++)
|
|
1021
|
+
widths.splice(pos, 0, 0);
|
|
1022
|
+
}
|
|
1023
|
+
return result;
|
|
1024
|
+
}
|
|
1025
|
+
function columnIsHeader(map, table2, col) {
|
|
1026
|
+
const headerCell = tableNodeTypes(table2.type.schema).header_cell;
|
|
1027
|
+
for (let row = 0; row < map.height; row++) {
|
|
1028
|
+
const pos = map.map[col + row * map.width];
|
|
1029
|
+
if (table2.nodeAt(pos).type != headerCell)
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
return true;
|
|
1033
|
+
}
|
|
350
1034
|
const exitTable = (node) => (state, dispatch) => {
|
|
351
1035
|
if (!isInTable(state)) {
|
|
352
1036
|
return false;
|
|
@@ -835,19 +1519,990 @@ const operatorPlugin = (ctx, utils) => {
|
|
|
835
1519
|
}
|
|
836
1520
|
});
|
|
837
1521
|
};
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1522
|
+
class TableView {
|
|
1523
|
+
constructor(node, cellMinWidth) {
|
|
1524
|
+
this.node = node;
|
|
1525
|
+
this.cellMinWidth = cellMinWidth;
|
|
1526
|
+
this.node = node;
|
|
1527
|
+
this.cellMinWidth = cellMinWidth;
|
|
1528
|
+
this.dom = document.createElement("div");
|
|
1529
|
+
this.dom.className = "tableWrapper";
|
|
1530
|
+
this.table = this.dom.appendChild(document.createElement("table"));
|
|
1531
|
+
this.colgroup = this.table.appendChild(document.createElement("colgroup"));
|
|
1532
|
+
updateColumns(node, this.colgroup, this.table, cellMinWidth);
|
|
1533
|
+
this.contentDOM = this.table.appendChild(document.createElement("tbody"));
|
|
1534
|
+
}
|
|
1535
|
+
update(node) {
|
|
1536
|
+
if (node.type != this.node.type)
|
|
1537
|
+
return false;
|
|
1538
|
+
this.node = node;
|
|
1539
|
+
updateColumns(node, this.colgroup, this.table, this.cellMinWidth);
|
|
1540
|
+
return true;
|
|
1541
|
+
}
|
|
1542
|
+
ignoreMutation(record) {
|
|
1543
|
+
return record.type == "attributes" && (record.target == this.table || this.colgroup.contains(record.target));
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
function updateColumns(node, colgroup, table2, cellMinWidth, overrideCol, overrideValue) {
|
|
1547
|
+
var _a;
|
|
1548
|
+
let totalWidth = 0, fixedWidth = true;
|
|
1549
|
+
let nextDOM = colgroup.firstChild;
|
|
1550
|
+
const row = node.firstChild;
|
|
1551
|
+
for (let i = 0, col = 0; i < row.childCount; i++) {
|
|
1552
|
+
const { colspan, colwidth } = row.child(i).attrs;
|
|
1553
|
+
for (let j = 0; j < colspan; j++, col++) {
|
|
1554
|
+
const hasWidth = overrideCol == col ? overrideValue : colwidth && colwidth[j];
|
|
1555
|
+
const cssWidth = hasWidth ? hasWidth + "px" : "";
|
|
1556
|
+
totalWidth += hasWidth || cellMinWidth;
|
|
1557
|
+
if (!hasWidth)
|
|
1558
|
+
fixedWidth = false;
|
|
1559
|
+
if (!nextDOM) {
|
|
1560
|
+
colgroup.appendChild(document.createElement("col")).style.width = cssWidth;
|
|
1561
|
+
} else {
|
|
1562
|
+
if (nextDOM.style.width != cssWidth)
|
|
1563
|
+
nextDOM.style.width = cssWidth;
|
|
1564
|
+
nextDOM = nextDOM.nextSibling;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
while (nextDOM) {
|
|
1569
|
+
const after = nextDOM.nextSibling;
|
|
1570
|
+
(_a = nextDOM.parentNode) == null ? void 0 : _a.removeChild(nextDOM);
|
|
1571
|
+
nextDOM = after;
|
|
1572
|
+
}
|
|
1573
|
+
if (fixedWidth) {
|
|
1574
|
+
table2.style.width = totalWidth + "px";
|
|
1575
|
+
table2.style.minWidth = "";
|
|
1576
|
+
} else {
|
|
1577
|
+
table2.style.width = "";
|
|
1578
|
+
table2.style.minWidth = totalWidth + "px";
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
const key = new PluginKey("tableColumnResizing");
|
|
1582
|
+
function columnResizing({
|
|
1583
|
+
handleWidth = 5,
|
|
1584
|
+
cellMinWidth = 25,
|
|
1585
|
+
View = TableView,
|
|
1586
|
+
lastColumnResizable = true
|
|
1587
|
+
} = {}) {
|
|
1588
|
+
const plugin = new Plugin({
|
|
1589
|
+
key,
|
|
1590
|
+
state: {
|
|
1591
|
+
init(_, state) {
|
|
1592
|
+
this.spec.props.nodeViews[tableNodeTypes(state.schema).table.name] = (node) => new View(node, cellMinWidth);
|
|
1593
|
+
return new ResizeState(-1, false);
|
|
1594
|
+
},
|
|
1595
|
+
apply(tr, prev) {
|
|
1596
|
+
return prev.apply(tr);
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1599
|
+
props: {
|
|
1600
|
+
attributes(state) {
|
|
1601
|
+
const pluginState = key.getState(state);
|
|
1602
|
+
return pluginState.activeHandle > -1 ? { class: "resize-cursor" } : void 0;
|
|
1603
|
+
},
|
|
1604
|
+
handleDOMEvents: {
|
|
1605
|
+
mousemove(view, event) {
|
|
1606
|
+
handleMouseMove(view, event, handleWidth, lastColumnResizable);
|
|
1607
|
+
},
|
|
1608
|
+
mouseleave(view) {
|
|
1609
|
+
handleMouseLeave(view);
|
|
1610
|
+
},
|
|
1611
|
+
mousedown(view, event) {
|
|
1612
|
+
handleMouseDown$1(view, event, cellMinWidth);
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
decorations(state) {
|
|
1616
|
+
const pluginState = key.getState(state);
|
|
1617
|
+
if (pluginState.activeHandle > -1)
|
|
1618
|
+
return handleDecorations(state, pluginState.activeHandle);
|
|
1619
|
+
return null;
|
|
1620
|
+
},
|
|
1621
|
+
nodeViews: {}
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
return plugin;
|
|
1625
|
+
}
|
|
1626
|
+
class ResizeState {
|
|
1627
|
+
constructor(activeHandle, dragging) {
|
|
1628
|
+
this.activeHandle = activeHandle;
|
|
1629
|
+
this.dragging = dragging;
|
|
1630
|
+
this.activeHandle = activeHandle;
|
|
1631
|
+
this.dragging = dragging;
|
|
1632
|
+
}
|
|
1633
|
+
apply(tr) {
|
|
1634
|
+
let state = this;
|
|
1635
|
+
const action = tr.getMeta(key);
|
|
1636
|
+
if (action && action.setHandle != null)
|
|
1637
|
+
return new ResizeState(action.setHandle, null);
|
|
1638
|
+
if (action && action.setDragging !== void 0)
|
|
1639
|
+
return new ResizeState(state.activeHandle, action.setDragging);
|
|
1640
|
+
if (state.activeHandle > -1 && tr.docChanged) {
|
|
1641
|
+
let handle = tr.mapping.map(state.activeHandle, -1);
|
|
1642
|
+
if (!pointsAtCell(tr.doc.resolve(handle)))
|
|
1643
|
+
handle = 0;
|
|
1644
|
+
state = new ResizeState(handle, state.dragging);
|
|
1645
|
+
}
|
|
1646
|
+
return state;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
function handleMouseMove(view, event, handleWidth, lastColumnResizable) {
|
|
1650
|
+
const pluginState = key.getState(view.state);
|
|
1651
|
+
if (!pluginState.dragging) {
|
|
1652
|
+
const target = domCellAround(event.target);
|
|
1653
|
+
let cell = -1;
|
|
1654
|
+
if (target) {
|
|
1655
|
+
const { left, right } = target.getBoundingClientRect();
|
|
1656
|
+
if (event.clientX - left <= handleWidth)
|
|
1657
|
+
cell = edgeCell(view, event, "left");
|
|
1658
|
+
else if (right - event.clientX <= handleWidth)
|
|
1659
|
+
cell = edgeCell(view, event, "right");
|
|
1660
|
+
}
|
|
1661
|
+
if (cell != pluginState.activeHandle) {
|
|
1662
|
+
if (!lastColumnResizable && cell !== -1) {
|
|
1663
|
+
const $cell = view.state.doc.resolve(cell);
|
|
1664
|
+
const table2 = $cell.node(-1), map = TableMap.get(table2), start = $cell.start(-1);
|
|
1665
|
+
const col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs["colspan"] - 1;
|
|
1666
|
+
if (col == map.width - 1) {
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
updateHandle(view, cell);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
function handleMouseLeave(view) {
|
|
1675
|
+
const pluginState = key.getState(view.state);
|
|
1676
|
+
if (pluginState.activeHandle > -1 && !pluginState.dragging)
|
|
1677
|
+
updateHandle(view, -1);
|
|
1678
|
+
}
|
|
1679
|
+
function handleMouseDown$1(view, event, cellMinWidth) {
|
|
1680
|
+
const pluginState = key.getState(view.state);
|
|
1681
|
+
if (pluginState.activeHandle == -1 || pluginState.dragging)
|
|
1682
|
+
return false;
|
|
1683
|
+
const cell = view.state.doc.nodeAt(pluginState.activeHandle);
|
|
1684
|
+
const width = currentColWidth(view, pluginState.activeHandle, cell.attrs);
|
|
1685
|
+
view.dispatch(view.state.tr.setMeta(key, {
|
|
1686
|
+
setDragging: { startX: event.clientX, startWidth: width }
|
|
1687
|
+
}));
|
|
1688
|
+
function finish(event2) {
|
|
1689
|
+
window.removeEventListener("mouseup", finish);
|
|
1690
|
+
window.removeEventListener("mousemove", move);
|
|
1691
|
+
const pluginState2 = key.getState(view.state);
|
|
1692
|
+
if (pluginState2.dragging) {
|
|
1693
|
+
updateColumnWidth(view, pluginState2.activeHandle, draggedWidth(pluginState2.dragging, event2, cellMinWidth));
|
|
1694
|
+
view.dispatch(view.state.tr.setMeta(key, { setDragging: null }));
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
function move(event2) {
|
|
1698
|
+
if (!event2.which)
|
|
1699
|
+
return finish(event2);
|
|
1700
|
+
const pluginState2 = key.getState(view.state);
|
|
1701
|
+
const dragged = draggedWidth(pluginState2.dragging, event2, cellMinWidth);
|
|
1702
|
+
displayColumnWidth(view, pluginState2.activeHandle, dragged, cellMinWidth);
|
|
1703
|
+
}
|
|
1704
|
+
window.addEventListener("mouseup", finish);
|
|
1705
|
+
window.addEventListener("mousemove", move);
|
|
1706
|
+
event.preventDefault();
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
function currentColWidth(view, cellPos, { colspan, colwidth }) {
|
|
1710
|
+
const width = colwidth && colwidth[colwidth.length - 1];
|
|
1711
|
+
if (width)
|
|
1712
|
+
return width;
|
|
1713
|
+
const dom = view.domAtPos(cellPos);
|
|
1714
|
+
const node = dom.node.childNodes[dom.offset];
|
|
1715
|
+
let domWidth = node.offsetWidth, parts = colspan;
|
|
1716
|
+
if (colwidth) {
|
|
1717
|
+
for (let i = 0; i < colspan; i++)
|
|
1718
|
+
if (colwidth[i]) {
|
|
1719
|
+
domWidth -= colwidth[i];
|
|
1720
|
+
parts--;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return domWidth / parts;
|
|
1724
|
+
}
|
|
1725
|
+
function domCellAround(target) {
|
|
1726
|
+
while (target && target.nodeName != "TD" && target.nodeName != "TH")
|
|
1727
|
+
target = target.classList.contains("ProseMirror") ? null : target.parentNode;
|
|
1728
|
+
return target;
|
|
1729
|
+
}
|
|
1730
|
+
function edgeCell(view, event, side) {
|
|
1731
|
+
const found = view.posAtCoords({ left: event.clientX, top: event.clientY });
|
|
1732
|
+
if (!found)
|
|
1733
|
+
return -1;
|
|
1734
|
+
const { pos } = found;
|
|
1735
|
+
const $cell = cellAround(view.state.doc.resolve(pos));
|
|
1736
|
+
if (!$cell)
|
|
1737
|
+
return -1;
|
|
1738
|
+
if (side == "right")
|
|
1739
|
+
return $cell.pos;
|
|
1740
|
+
const map = TableMap.get($cell.node(-1)), start = $cell.start(-1);
|
|
1741
|
+
const index = map.map.indexOf($cell.pos - start);
|
|
1742
|
+
return index % map.width == 0 ? -1 : start + map.map[index - 1];
|
|
1743
|
+
}
|
|
1744
|
+
function draggedWidth(dragging, event, cellMinWidth) {
|
|
1745
|
+
const offset = event.clientX - dragging.startX;
|
|
1746
|
+
return Math.max(cellMinWidth, dragging.startWidth + offset);
|
|
1747
|
+
}
|
|
1748
|
+
function updateHandle(view, value) {
|
|
1749
|
+
view.dispatch(view.state.tr.setMeta(key, { setHandle: value }));
|
|
1750
|
+
}
|
|
1751
|
+
function updateColumnWidth(view, cell, width) {
|
|
1752
|
+
const $cell = view.state.doc.resolve(cell);
|
|
1753
|
+
const table2 = $cell.node(-1), map = TableMap.get(table2), start = $cell.start(-1);
|
|
1754
|
+
const col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs["colspan"] - 1;
|
|
1755
|
+
const tr = view.state.tr;
|
|
1756
|
+
for (let row = 0; row < map.height; row++) {
|
|
1757
|
+
const mapIndex = row * map.width + col;
|
|
1758
|
+
if (row && map.map[mapIndex] == map.map[mapIndex - map.width])
|
|
1759
|
+
continue;
|
|
1760
|
+
const pos = map.map[mapIndex], { attrs } = table2.nodeAt(pos);
|
|
1761
|
+
const index = attrs["colspan"] == 1 ? 0 : col - map.colCount(pos);
|
|
1762
|
+
if (attrs["colwidth"] && attrs["colwidth"][index] == width)
|
|
1763
|
+
continue;
|
|
1764
|
+
const colwidth = attrs["colwidth"] ? attrs["colwidth"].slice() : zeroes(attrs["colspan"]);
|
|
1765
|
+
colwidth[index] = width;
|
|
1766
|
+
tr.setNodeMarkup(start + pos, null, setAttr(attrs, "colwidth", colwidth));
|
|
1767
|
+
}
|
|
1768
|
+
if (tr.docChanged)
|
|
1769
|
+
view.dispatch(tr);
|
|
1770
|
+
}
|
|
1771
|
+
function displayColumnWidth(view, cell, width, cellMinWidth) {
|
|
1772
|
+
const $cell = view.state.doc.resolve(cell);
|
|
1773
|
+
const table2 = $cell.node(-1), start = $cell.start(-1);
|
|
1774
|
+
const col = TableMap.get(table2).colCount($cell.pos - start) + $cell.nodeAfter.attrs["colspan"] - 1;
|
|
1775
|
+
let dom = view.domAtPos($cell.start(-1)).node;
|
|
1776
|
+
while (dom.nodeName != "TABLE")
|
|
1777
|
+
dom = dom.parentNode;
|
|
1778
|
+
updateColumns(table2, dom.firstChild, dom, cellMinWidth, col, width);
|
|
1779
|
+
}
|
|
1780
|
+
function zeroes(n) {
|
|
1781
|
+
const result = [];
|
|
1782
|
+
for (let i = 0; i < n; i++)
|
|
1783
|
+
result.push(0);
|
|
1784
|
+
return result;
|
|
1785
|
+
}
|
|
1786
|
+
function handleDecorations(state, cell) {
|
|
1787
|
+
const decorations = [];
|
|
1788
|
+
const $cell = state.doc.resolve(cell);
|
|
1789
|
+
const table2 = $cell.node(-1), map = TableMap.get(table2), start = $cell.start(-1);
|
|
1790
|
+
const col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs["colspan"];
|
|
1791
|
+
for (let row = 0; row < map.height; row++) {
|
|
1792
|
+
const index = col + row * map.width - 1;
|
|
1793
|
+
if ((col == map.width || map.map[index] != map.map[index + 1]) && (row == 0 || map.map[index - 1] != map.map[index - 1 - map.width])) {
|
|
1794
|
+
const cellPos = map.map[index];
|
|
1795
|
+
const pos = start + cellPos + table2.nodeAt(cellPos).nodeSize - 1;
|
|
1796
|
+
const dom = document.createElement("div");
|
|
1797
|
+
dom.className = "column-resize-handle";
|
|
1798
|
+
decorations.push(Decoration.widget(pos, dom));
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
return DecorationSet.create(state.doc, decorations);
|
|
1802
|
+
}
|
|
1803
|
+
function selectedRect(state) {
|
|
1804
|
+
const sel = state.selection, $pos = selectionCell(state);
|
|
1805
|
+
const table2 = $pos.node(-1), tableStart = $pos.start(-1), map = TableMap.get(table2);
|
|
1806
|
+
let rect;
|
|
1807
|
+
if (sel instanceof CellSelection)
|
|
1808
|
+
rect = map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart);
|
|
1809
|
+
else
|
|
1810
|
+
rect = map.findCell($pos.pos - tableStart);
|
|
1811
|
+
rect.tableStart = tableStart;
|
|
1812
|
+
rect.map = map;
|
|
1813
|
+
rect.table = table2;
|
|
1814
|
+
return rect;
|
|
1815
|
+
}
|
|
1816
|
+
function addColumn(tr, { map, tableStart, table: table2 }, col) {
|
|
1817
|
+
map = map;
|
|
1818
|
+
table2 = table2;
|
|
1819
|
+
tableStart = tableStart;
|
|
1820
|
+
let refColumn = col > 0 ? -1 : 0;
|
|
1821
|
+
if (columnIsHeader(map, table2, col + refColumn))
|
|
1822
|
+
refColumn = col == 0 || col == map.width ? null : 0;
|
|
1823
|
+
for (let row = 0; row < map.height; row++) {
|
|
1824
|
+
const index = row * map.width + col;
|
|
1825
|
+
if (col > 0 && col < map.width && map.map[index - 1] == map.map[index]) {
|
|
1826
|
+
const pos = map.map[index], cell = table2.nodeAt(pos);
|
|
1827
|
+
tr.setNodeMarkup(tr.mapping.map(tableStart + pos), null, addColSpan(cell.attrs, col - map.colCount(pos)));
|
|
1828
|
+
row += cell.attrs["rowspan"] - 1;
|
|
1829
|
+
} else {
|
|
1830
|
+
const offset = map.map[index + refColumn];
|
|
1831
|
+
const type = refColumn == null ? tableNodeTypes(table2.type.schema).cell : table2.nodeAt(offset).type;
|
|
1832
|
+
const pos = map.positionAt(row, col, table2);
|
|
1833
|
+
tr.insert(tr.mapping.map(tableStart + pos), type.createAndFill());
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return tr;
|
|
1837
|
+
}
|
|
1838
|
+
const addColumnBefore = (state, dispatch) => {
|
|
1839
|
+
if (!isInTable(state))
|
|
1840
|
+
return false;
|
|
1841
|
+
if (dispatch) {
|
|
1842
|
+
const rect = selectedRect(state);
|
|
1843
|
+
dispatch(addColumn(state.tr, rect, rect.left));
|
|
1844
|
+
}
|
|
1845
|
+
return true;
|
|
1846
|
+
};
|
|
1847
|
+
const addColumnAfter = (state, dispatch) => {
|
|
1848
|
+
if (!isInTable(state))
|
|
1849
|
+
return false;
|
|
1850
|
+
if (dispatch) {
|
|
1851
|
+
const rect = selectedRect(state);
|
|
1852
|
+
dispatch(addColumn(state.tr, rect, rect.right));
|
|
1853
|
+
}
|
|
1854
|
+
return true;
|
|
1855
|
+
};
|
|
1856
|
+
function removeColumn(tr, { map, table: table2, tableStart }, col) {
|
|
1857
|
+
map = map;
|
|
1858
|
+
table2 = table2;
|
|
1859
|
+
tableStart = tableStart;
|
|
1860
|
+
const mapStart = tr.mapping.maps.length;
|
|
1861
|
+
for (let row = 0; row < map.height; ) {
|
|
1862
|
+
const index = row * map.width + col, pos = map.map[index], cell = table2.nodeAt(pos);
|
|
1863
|
+
if (col > 0 && map.map[index - 1] == pos || col < map.width - 1 && map.map[index + 1] == pos) {
|
|
1864
|
+
tr.setNodeMarkup(tr.mapping.slice(mapStart).map(tableStart + pos), null, removeColSpan(cell.attrs, col - map.colCount(pos)));
|
|
1865
|
+
} else {
|
|
1866
|
+
const start = tr.mapping.slice(mapStart).map(tableStart + pos);
|
|
1867
|
+
tr.delete(start, start + cell.nodeSize);
|
|
1868
|
+
}
|
|
1869
|
+
row += cell.attrs["rowspan"];
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
const deleteColumn = (state, dispatch) => {
|
|
1873
|
+
if (!isInTable(state))
|
|
1874
|
+
return false;
|
|
1875
|
+
if (dispatch) {
|
|
1876
|
+
const rect = selectedRect(state), tr = state.tr;
|
|
1877
|
+
if (rect.left == 0 && rect.right == rect.map.width)
|
|
1878
|
+
return false;
|
|
1879
|
+
for (let i = rect.right - 1; ; i--) {
|
|
1880
|
+
removeColumn(tr, rect, i);
|
|
1881
|
+
if (i == rect.left)
|
|
1882
|
+
break;
|
|
1883
|
+
rect.table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
|
|
1884
|
+
rect.map = TableMap.get(rect.table);
|
|
1885
|
+
}
|
|
1886
|
+
dispatch(tr);
|
|
1887
|
+
}
|
|
1888
|
+
return true;
|
|
1889
|
+
};
|
|
1890
|
+
function removeRow(tr, { map, tableStart, table: table2 }, row) {
|
|
1891
|
+
map = map;
|
|
1892
|
+
table2 = table2;
|
|
1893
|
+
tableStart = tableStart;
|
|
1894
|
+
let rowPos = 0;
|
|
1895
|
+
for (let i = 0; i < row; i++)
|
|
1896
|
+
rowPos += table2.child(i).nodeSize;
|
|
1897
|
+
const nextRow = rowPos + table2.child(row).nodeSize;
|
|
1898
|
+
const mapFrom = tr.mapping.maps.length;
|
|
1899
|
+
tr.delete(rowPos + tableStart, nextRow + tableStart);
|
|
1900
|
+
for (let col = 0, index = row * map.width; col < map.width; col++, index++) {
|
|
1901
|
+
const pos = map.map[index];
|
|
1902
|
+
if (row > 0 && pos == map.map[index - map.width]) {
|
|
1903
|
+
const attrs = table2.nodeAt(pos).attrs;
|
|
1904
|
+
tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + tableStart), null, setAttr(attrs, "rowspan", attrs["rowspan"] - 1));
|
|
1905
|
+
col += attrs["colspan"] - 1;
|
|
1906
|
+
} else if (row < map.width && pos == map.map[index + map.width]) {
|
|
1907
|
+
const cell = table2.nodeAt(pos);
|
|
1908
|
+
const copy = cell.type.create(setAttr(cell.attrs, "rowspan", cell.attrs["rowspan"] - 1), cell.content);
|
|
1909
|
+
const newPos = map.positionAt(row + 1, col, table2);
|
|
1910
|
+
tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy);
|
|
1911
|
+
col += cell.attrs["colspan"] - 1;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
const deleteRow = (state, dispatch) => {
|
|
1916
|
+
if (!isInTable(state))
|
|
1917
|
+
return false;
|
|
1918
|
+
if (dispatch) {
|
|
1919
|
+
const rect = selectedRect(state), tr = state.tr;
|
|
1920
|
+
if (rect.top == 0 && rect.bottom == rect.map.height)
|
|
1921
|
+
return false;
|
|
1922
|
+
for (let i = rect.bottom - 1; ; i--) {
|
|
1923
|
+
removeRow(tr, rect, i);
|
|
1924
|
+
if (i == rect.top)
|
|
1925
|
+
break;
|
|
1926
|
+
rect.table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
|
|
1927
|
+
rect.map = TableMap.get(rect.table);
|
|
1928
|
+
}
|
|
1929
|
+
dispatch(tr);
|
|
1930
|
+
}
|
|
1931
|
+
return true;
|
|
1932
|
+
};
|
|
1933
|
+
function setCellAttr(name, value) {
|
|
1934
|
+
return (state, dispatch) => {
|
|
1935
|
+
if (!isInTable(state))
|
|
1936
|
+
return false;
|
|
1937
|
+
const $cell = selectionCell(state);
|
|
1938
|
+
if ($cell.nodeAfter.attrs[name] === value)
|
|
1939
|
+
return false;
|
|
1940
|
+
if (dispatch) {
|
|
1941
|
+
const tr = state.tr;
|
|
1942
|
+
if (state.selection instanceof CellSelection)
|
|
1943
|
+
state.selection.forEachCell((node, pos) => {
|
|
1944
|
+
if (node.attrs[name] !== value)
|
|
1945
|
+
tr.setNodeMarkup(pos, null, setAttr(node.attrs, name, value));
|
|
1946
|
+
});
|
|
1947
|
+
else
|
|
1948
|
+
tr.setNodeMarkup($cell.pos, null, setAttr($cell.nodeAfter.attrs, name, value));
|
|
1949
|
+
dispatch(tr);
|
|
1950
|
+
}
|
|
1951
|
+
return true;
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
function findNextCell($cell, dir) {
|
|
1955
|
+
if (dir < 0) {
|
|
1956
|
+
const before = $cell.nodeBefore;
|
|
1957
|
+
if (before)
|
|
1958
|
+
return $cell.pos - before.nodeSize;
|
|
1959
|
+
for (let row = $cell.index(-1) - 1, rowEnd = $cell.before(); row >= 0; row--) {
|
|
1960
|
+
const rowNode = $cell.node(-1).child(row);
|
|
1961
|
+
if (rowNode.childCount)
|
|
1962
|
+
return rowEnd - 1 - rowNode.lastChild.nodeSize;
|
|
1963
|
+
rowEnd -= rowNode.nodeSize;
|
|
1964
|
+
}
|
|
1965
|
+
} else {
|
|
1966
|
+
if ($cell.index() < $cell.parent.childCount - 1)
|
|
1967
|
+
return $cell.pos + $cell.nodeAfter.nodeSize;
|
|
1968
|
+
const table2 = $cell.node(-1);
|
|
1969
|
+
for (let row = $cell.indexAfter(-1), rowStart = $cell.after(); row < table2.childCount; row++) {
|
|
1970
|
+
const rowNode = table2.child(row);
|
|
1971
|
+
if (rowNode.childCount)
|
|
1972
|
+
return rowStart + 1;
|
|
1973
|
+
rowStart += rowNode.nodeSize;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
function goToNextCell(direction) {
|
|
1979
|
+
return (state, dispatch) => {
|
|
1980
|
+
if (!isInTable(state))
|
|
1981
|
+
return false;
|
|
1982
|
+
const cell = findNextCell(selectionCell(state), direction);
|
|
1983
|
+
if (cell == null)
|
|
1984
|
+
return false;
|
|
1985
|
+
if (dispatch) {
|
|
1986
|
+
const $cell = state.doc.resolve(cell);
|
|
1987
|
+
dispatch(state.tr.setSelection(TextSelection.between($cell, moveCellForward($cell))).scrollIntoView());
|
|
1988
|
+
}
|
|
1989
|
+
return true;
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
const deleteTable = (state, dispatch) => {
|
|
1993
|
+
const $pos = state.selection.$anchor;
|
|
1994
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
1995
|
+
const node = $pos.node(d);
|
|
1996
|
+
if (node.type.spec["tableRole"] == "table") {
|
|
1997
|
+
if (dispatch)
|
|
1998
|
+
dispatch(state.tr.delete($pos.before(d), $pos.after(d)).scrollIntoView());
|
|
1999
|
+
return true;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
return false;
|
|
2003
|
+
};
|
|
2004
|
+
function pastedCells(slice) {
|
|
2005
|
+
if (!slice.size)
|
|
2006
|
+
return null;
|
|
2007
|
+
let { content, openStart, openEnd } = slice;
|
|
2008
|
+
while (content.childCount == 1 && (openStart > 0 && openEnd > 0 || content.firstChild.type.spec["tableRole"] == "table")) {
|
|
2009
|
+
openStart--;
|
|
2010
|
+
openEnd--;
|
|
2011
|
+
content = content.firstChild.content;
|
|
2012
|
+
}
|
|
2013
|
+
const first = content.firstChild, role = first.type.spec["tableRole"];
|
|
2014
|
+
const schema2 = first.type.schema, rows = [];
|
|
2015
|
+
if (role == "row") {
|
|
2016
|
+
for (let i = 0; i < content.childCount; i++) {
|
|
2017
|
+
let cells = content.child(i).content;
|
|
2018
|
+
const left = i ? 0 : Math.max(0, openStart - 1);
|
|
2019
|
+
const right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
|
|
2020
|
+
if (left || right)
|
|
2021
|
+
cells = fitSlice(tableNodeTypes(schema2).row, new Slice(cells, left, right)).content;
|
|
2022
|
+
rows.push(cells);
|
|
2023
|
+
}
|
|
2024
|
+
} else if (role == "cell" || role == "header_cell") {
|
|
2025
|
+
rows.push(openStart || openEnd ? fitSlice(tableNodeTypes(schema2).row, new Slice(content, openStart, openEnd)).content : content);
|
|
2026
|
+
} else {
|
|
2027
|
+
return null;
|
|
2028
|
+
}
|
|
2029
|
+
return ensureRectangular(schema2, rows);
|
|
2030
|
+
}
|
|
2031
|
+
function ensureRectangular(schema2, rows) {
|
|
2032
|
+
const widths = [];
|
|
2033
|
+
for (let i = 0; i < rows.length; i++) {
|
|
2034
|
+
const row = rows[i];
|
|
2035
|
+
for (let j = row.childCount - 1; j >= 0; j--) {
|
|
2036
|
+
const { rowspan, colspan } = row.child(j).attrs;
|
|
2037
|
+
for (let r = i; r < i + rowspan; r++)
|
|
2038
|
+
widths[r] = (widths[r] || 0) + colspan;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
let width = 0;
|
|
2042
|
+
for (let r = 0; r < widths.length; r++)
|
|
2043
|
+
width = Math.max(width, widths[r]);
|
|
2044
|
+
for (let r = 0; r < widths.length; r++) {
|
|
2045
|
+
if (r >= rows.length)
|
|
2046
|
+
rows.push(Fragment.empty);
|
|
2047
|
+
if (widths[r] < width) {
|
|
2048
|
+
const empty = tableNodeTypes(schema2).cell.createAndFill(), cells = [];
|
|
2049
|
+
for (let i = widths[r]; i < width; i++)
|
|
2050
|
+
cells.push(empty);
|
|
2051
|
+
rows[r] = rows[r].append(Fragment.from(cells));
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
return { height: rows.length, width, rows };
|
|
2055
|
+
}
|
|
2056
|
+
function fitSlice(nodeType, slice) {
|
|
2057
|
+
const node = nodeType.createAndFill();
|
|
2058
|
+
const tr = new Transform(node).replace(0, node.content.size, slice);
|
|
2059
|
+
return tr.doc;
|
|
2060
|
+
}
|
|
2061
|
+
function clipCells({ width, height, rows }, newWidth, newHeight) {
|
|
2062
|
+
if (width != newWidth) {
|
|
2063
|
+
const added = [], newRows = [];
|
|
2064
|
+
for (let row = 0; row < rows.length; row++) {
|
|
2065
|
+
const frag = rows[row], cells = [];
|
|
2066
|
+
for (let col = added[row] || 0, i = 0; col < newWidth; i++) {
|
|
2067
|
+
let cell = frag.child(i % frag.childCount);
|
|
2068
|
+
if (col + cell.attrs["colspan"] > newWidth)
|
|
2069
|
+
cell = cell.type.create(removeColSpan(cell.attrs, cell.attrs["colspan"], col + cell.attrs["colspan"] - newWidth), cell.content);
|
|
2070
|
+
cells.push(cell);
|
|
2071
|
+
col += cell.attrs["colspan"];
|
|
2072
|
+
for (let j = 1; j < cell.attrs["rowspan"]; j++)
|
|
2073
|
+
added[row + j] = (added[row + j] || 0) + cell.attrs["colspan"];
|
|
847
2074
|
}
|
|
2075
|
+
newRows.push(Fragment.from(cells));
|
|
848
2076
|
}
|
|
2077
|
+
rows = newRows;
|
|
2078
|
+
width = newWidth;
|
|
849
2079
|
}
|
|
2080
|
+
if (height != newHeight) {
|
|
2081
|
+
const newRows = [];
|
|
2082
|
+
for (let row = 0, i = 0; row < newHeight; row++, i++) {
|
|
2083
|
+
const cells = [], source = rows[i % height];
|
|
2084
|
+
for (let j = 0; j < source.childCount; j++) {
|
|
2085
|
+
let cell = source.child(j);
|
|
2086
|
+
if (row + cell.attrs["rowspan"] > newHeight)
|
|
2087
|
+
cell = cell.type.create(setAttr(cell.attrs, "rowspan", Math.max(1, newHeight - cell.attrs["rowspan"])), cell.content);
|
|
2088
|
+
cells.push(cell);
|
|
2089
|
+
}
|
|
2090
|
+
newRows.push(Fragment.from(cells));
|
|
2091
|
+
}
|
|
2092
|
+
rows = newRows;
|
|
2093
|
+
height = newHeight;
|
|
2094
|
+
}
|
|
2095
|
+
return { width, height, rows };
|
|
2096
|
+
}
|
|
2097
|
+
function growTable(tr, map, table2, start, width, height, mapFrom) {
|
|
2098
|
+
const schema2 = tr.doc.type.schema, types = tableNodeTypes(schema2);
|
|
2099
|
+
let empty, emptyHead;
|
|
2100
|
+
if (width > map.width) {
|
|
2101
|
+
for (let row = 0, rowEnd = 0; row < map.height; row++) {
|
|
2102
|
+
const rowNode = table2.child(row);
|
|
2103
|
+
rowEnd += rowNode.nodeSize;
|
|
2104
|
+
const cells = [];
|
|
2105
|
+
let add;
|
|
2106
|
+
if (rowNode.lastChild == null || rowNode.lastChild.type == types.cell)
|
|
2107
|
+
add = empty || (empty = types.cell.createAndFill());
|
|
2108
|
+
else
|
|
2109
|
+
add = emptyHead || (emptyHead = types.header_cell.createAndFill());
|
|
2110
|
+
for (let i = map.width; i < width; i++)
|
|
2111
|
+
cells.push(add);
|
|
2112
|
+
tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
if (height > map.height) {
|
|
2116
|
+
const cells = [];
|
|
2117
|
+
for (let i = 0, start2 = (map.height - 1) * map.width; i < Math.max(map.width, width); i++) {
|
|
2118
|
+
const header = i >= map.width ? false : table2.nodeAt(map.map[start2 + i]).type == types.header_cell;
|
|
2119
|
+
cells.push(header ? emptyHead || (emptyHead = types.header_cell.createAndFill()) : empty || (empty = types.cell.createAndFill()));
|
|
2120
|
+
}
|
|
2121
|
+
const emptyRow = types.row.create(null, Fragment.from(cells)), rows = [];
|
|
2122
|
+
for (let i = map.height; i < height; i++)
|
|
2123
|
+
rows.push(emptyRow);
|
|
2124
|
+
tr.insert(tr.mapping.slice(mapFrom).map(start + table2.nodeSize - 2), rows);
|
|
2125
|
+
}
|
|
2126
|
+
return !!(empty || emptyHead);
|
|
2127
|
+
}
|
|
2128
|
+
function isolateHorizontal(tr, map, table2, start, left, right, top, mapFrom) {
|
|
2129
|
+
if (top == 0 || top == map.height)
|
|
2130
|
+
return false;
|
|
2131
|
+
let found = false;
|
|
2132
|
+
for (let col = left; col < right; col++) {
|
|
2133
|
+
const index = top * map.width + col, pos = map.map[index];
|
|
2134
|
+
if (map.map[index - map.width] == pos) {
|
|
2135
|
+
found = true;
|
|
2136
|
+
const cell = table2.nodeAt(pos);
|
|
2137
|
+
const { top: cellTop, left: cellLeft } = map.findCell(pos);
|
|
2138
|
+
tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), null, setAttr(cell.attrs, "rowspan", top - cellTop));
|
|
2139
|
+
tr.insert(tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table2)), cell.type.createAndFill(setAttr(cell.attrs, "rowspan", cellTop + cell.attrs["rowspan"] - top)));
|
|
2140
|
+
col += cell.attrs["colspan"] - 1;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
return found;
|
|
2144
|
+
}
|
|
2145
|
+
function isolateVertical(tr, map, table2, start, top, bottom, left, mapFrom) {
|
|
2146
|
+
if (left == 0 || left == map.width)
|
|
2147
|
+
return false;
|
|
2148
|
+
let found = false;
|
|
2149
|
+
for (let row = top; row < bottom; row++) {
|
|
2150
|
+
const index = row * map.width + left, pos = map.map[index];
|
|
2151
|
+
if (map.map[index - 1] == pos) {
|
|
2152
|
+
found = true;
|
|
2153
|
+
const cell = table2.nodeAt(pos), cellLeft = map.colCount(pos);
|
|
2154
|
+
const updatePos = tr.mapping.slice(mapFrom).map(pos + start);
|
|
2155
|
+
tr.setNodeMarkup(updatePos, null, removeColSpan(cell.attrs, left - cellLeft, cell.attrs["colspan"] - (left - cellLeft)));
|
|
2156
|
+
tr.insert(updatePos + cell.nodeSize, cell.type.createAndFill(removeColSpan(cell.attrs, 0, left - cellLeft)));
|
|
2157
|
+
row += cell.attrs["rowspan"] - 1;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return found;
|
|
2161
|
+
}
|
|
2162
|
+
function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
2163
|
+
let table2 = tableStart ? state.doc.nodeAt(tableStart - 1) : state.doc, map = TableMap.get(table2);
|
|
2164
|
+
const { top, left } = rect;
|
|
2165
|
+
const right = left + cells.width, bottom = top + cells.height;
|
|
2166
|
+
const tr = state.tr;
|
|
2167
|
+
let mapFrom = 0;
|
|
2168
|
+
function recomp() {
|
|
2169
|
+
table2 = tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc;
|
|
2170
|
+
map = TableMap.get(table2);
|
|
2171
|
+
mapFrom = tr.mapping.maps.length;
|
|
2172
|
+
}
|
|
2173
|
+
if (growTable(tr, map, table2, tableStart, right, bottom, mapFrom))
|
|
2174
|
+
recomp();
|
|
2175
|
+
if (isolateHorizontal(tr, map, table2, tableStart, left, right, top, mapFrom))
|
|
2176
|
+
recomp();
|
|
2177
|
+
if (isolateHorizontal(tr, map, table2, tableStart, left, right, bottom, mapFrom))
|
|
2178
|
+
recomp();
|
|
2179
|
+
if (isolateVertical(tr, map, table2, tableStart, top, bottom, left, mapFrom))
|
|
2180
|
+
recomp();
|
|
2181
|
+
if (isolateVertical(tr, map, table2, tableStart, top, bottom, right, mapFrom))
|
|
2182
|
+
recomp();
|
|
2183
|
+
for (let row = top; row < bottom; row++) {
|
|
2184
|
+
const from = map.positionAt(row, left, table2), to = map.positionAt(row, right, table2);
|
|
2185
|
+
tr.replace(tr.mapping.slice(mapFrom).map(from + tableStart), tr.mapping.slice(mapFrom).map(to + tableStart), new Slice(cells.rows[row - top], 0, 0));
|
|
2186
|
+
}
|
|
2187
|
+
recomp();
|
|
2188
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table2)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table2))));
|
|
2189
|
+
dispatch(tr);
|
|
2190
|
+
}
|
|
2191
|
+
const fixTablesKey = new PluginKey("fix-tables");
|
|
2192
|
+
function changedDescendants(old, cur, offset, f) {
|
|
2193
|
+
const oldSize = old.childCount, curSize = cur.childCount;
|
|
2194
|
+
outer:
|
|
2195
|
+
for (let i = 0, j = 0; i < curSize; i++) {
|
|
2196
|
+
const child = cur.child(i);
|
|
2197
|
+
for (let scan = j, e = Math.min(oldSize, i + 3); scan < e; scan++) {
|
|
2198
|
+
if (old.child(scan) == child) {
|
|
2199
|
+
j = scan + 1;
|
|
2200
|
+
offset += child.nodeSize;
|
|
2201
|
+
continue outer;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
f(child, offset);
|
|
2205
|
+
if (j < oldSize && old.child(j).sameMarkup(child))
|
|
2206
|
+
changedDescendants(old.child(j), child, offset + 1, f);
|
|
2207
|
+
else
|
|
2208
|
+
child.nodesBetween(0, child.content.size, f, offset + 1);
|
|
2209
|
+
offset += child.nodeSize;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
function fixTables(state, oldState) {
|
|
2213
|
+
let tr;
|
|
2214
|
+
const check = (node, pos) => {
|
|
2215
|
+
if (node.type.spec["tableRole"] == "table")
|
|
2216
|
+
tr = fixTable(state, node, pos, tr);
|
|
2217
|
+
};
|
|
2218
|
+
if (!oldState)
|
|
2219
|
+
state.doc.descendants(check);
|
|
2220
|
+
else if (oldState.doc != state.doc)
|
|
2221
|
+
changedDescendants(oldState.doc, state.doc, 0, check);
|
|
2222
|
+
return tr;
|
|
2223
|
+
}
|
|
2224
|
+
function fixTable(state, table2, tablePos, tr) {
|
|
2225
|
+
const map = TableMap.get(table2);
|
|
2226
|
+
if (!map.problems)
|
|
2227
|
+
return tr;
|
|
2228
|
+
if (!tr)
|
|
2229
|
+
tr = state.tr;
|
|
2230
|
+
const mustAdd = [];
|
|
2231
|
+
for (let i = 0; i < map.height; i++)
|
|
2232
|
+
mustAdd.push(0);
|
|
2233
|
+
for (let i = 0; i < map.problems.length; i++) {
|
|
2234
|
+
const prob = map.problems[i];
|
|
2235
|
+
if (prob.type == "collision") {
|
|
2236
|
+
const cell = table2.nodeAt(prob.pos);
|
|
2237
|
+
for (let j = 0; j < cell.attrs["rowspan"]; j++)
|
|
2238
|
+
mustAdd[prob.row + j] += prob.n;
|
|
2239
|
+
tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, removeColSpan(cell.attrs, cell.attrs["colspan"] - prob.n, prob.n));
|
|
2240
|
+
} else if (prob.type == "missing") {
|
|
2241
|
+
mustAdd[prob.row] += prob.n;
|
|
2242
|
+
} else if (prob.type == "overlong_rowspan") {
|
|
2243
|
+
const cell = table2.nodeAt(prob.pos);
|
|
2244
|
+
tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, setAttr(cell.attrs, "rowspan", cell.attrs["rowspan"] - prob.n));
|
|
2245
|
+
} else if (prob.type == "colwidth mismatch") {
|
|
2246
|
+
const cell = table2.nodeAt(prob.pos);
|
|
2247
|
+
tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, setAttr(cell.attrs, "colwidth", prob.colwidth));
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
let first, last;
|
|
2251
|
+
for (let i = 0; i < mustAdd.length; i++)
|
|
2252
|
+
if (mustAdd[i]) {
|
|
2253
|
+
if (first == null)
|
|
2254
|
+
first = i;
|
|
2255
|
+
last = i;
|
|
2256
|
+
}
|
|
2257
|
+
for (let i = 0, pos = tablePos + 1; i < map.height; i++) {
|
|
2258
|
+
const row = table2.child(i);
|
|
2259
|
+
const end = pos + row.nodeSize;
|
|
2260
|
+
const add = mustAdd[i];
|
|
2261
|
+
if (add > 0) {
|
|
2262
|
+
let tableNodeType = "cell";
|
|
2263
|
+
if (row.firstChild) {
|
|
2264
|
+
tableNodeType = row.firstChild.type.spec["tableRole"];
|
|
2265
|
+
}
|
|
2266
|
+
const nodes = [];
|
|
2267
|
+
for (let j = 0; j < add; j++)
|
|
2268
|
+
nodes.push(tableNodeTypes(state.schema)[tableNodeType].createAndFill());
|
|
2269
|
+
const side = (i == 0 || first == i - 1) && last == i ? pos + 1 : end - 1;
|
|
2270
|
+
tr.insert(tr.mapping.map(side), nodes);
|
|
2271
|
+
}
|
|
2272
|
+
pos = end;
|
|
2273
|
+
}
|
|
2274
|
+
return tr.setMeta(fixTablesKey, { fixTables: true });
|
|
2275
|
+
}
|
|
2276
|
+
const tableEditingKey = new PluginKey("selectingCells");
|
|
2277
|
+
function domInCell(view, dom) {
|
|
2278
|
+
for (; dom && dom != view.dom; dom = dom.parentNode)
|
|
2279
|
+
if (dom.nodeName == "TD" || dom.nodeName == "TH")
|
|
2280
|
+
return dom;
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
function cellUnderMouse(view, event) {
|
|
2284
|
+
const mousePos = view.posAtCoords({ left: event.clientX, top: event.clientY });
|
|
2285
|
+
if (!mousePos)
|
|
2286
|
+
return null;
|
|
2287
|
+
return mousePos ? cellAround(view.state.doc.resolve(mousePos.pos)) : null;
|
|
2288
|
+
}
|
|
2289
|
+
function handleMouseDown(view, event) {
|
|
2290
|
+
const startEvent = event;
|
|
2291
|
+
if (startEvent.ctrlKey || startEvent.metaKey)
|
|
2292
|
+
return;
|
|
2293
|
+
const startDOMCell = domInCell(view, startEvent.target);
|
|
2294
|
+
let $anchor;
|
|
2295
|
+
if (startEvent.shiftKey && view.state.selection instanceof CellSelection) {
|
|
2296
|
+
setCellSelection(view.state.selection.$anchorCell, startEvent);
|
|
2297
|
+
startEvent.preventDefault();
|
|
2298
|
+
} else if (startEvent.shiftKey && startDOMCell && ($anchor = cellAround(view.state.selection.$anchor)) != null && cellUnderMouse(view, startEvent).pos != $anchor.pos) {
|
|
2299
|
+
setCellSelection($anchor, startEvent);
|
|
2300
|
+
startEvent.preventDefault();
|
|
2301
|
+
} else if (!startDOMCell) {
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
function setCellSelection($anchor2, event2) {
|
|
2305
|
+
let $head = cellUnderMouse(view, event2);
|
|
2306
|
+
const starting = tableEditingKey.getState(view.state) == null;
|
|
2307
|
+
if (!$head || !inSameTable($anchor2, $head)) {
|
|
2308
|
+
if (starting)
|
|
2309
|
+
$head = $anchor2;
|
|
2310
|
+
else
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
const selection = new CellSelection($anchor2, $head);
|
|
2314
|
+
if (starting || !view.state.selection.eq(selection)) {
|
|
2315
|
+
const tr = view.state.tr.setSelection(selection);
|
|
2316
|
+
if (starting)
|
|
2317
|
+
tr.setMeta(tableEditingKey, $anchor2.pos);
|
|
2318
|
+
view.dispatch(tr);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
function stop() {
|
|
2322
|
+
view.root.removeEventListener("mouseup", stop);
|
|
2323
|
+
view.root.removeEventListener("dragstart", stop);
|
|
2324
|
+
view.root.removeEventListener("mousemove", move);
|
|
2325
|
+
if (tableEditingKey.getState(view.state) != null)
|
|
2326
|
+
view.dispatch(view.state.tr.setMeta(tableEditingKey, -1));
|
|
2327
|
+
}
|
|
2328
|
+
function move(event2) {
|
|
2329
|
+
const anchor = tableEditingKey.getState(view.state);
|
|
2330
|
+
let $anchor2;
|
|
2331
|
+
if (anchor != null) {
|
|
2332
|
+
$anchor2 = view.state.doc.resolve(anchor);
|
|
2333
|
+
} else if (domInCell(view, event2.target) != startDOMCell) {
|
|
2334
|
+
$anchor2 = cellUnderMouse(view, startEvent);
|
|
2335
|
+
if (!$anchor2)
|
|
2336
|
+
return stop();
|
|
2337
|
+
}
|
|
2338
|
+
if ($anchor2)
|
|
2339
|
+
setCellSelection($anchor2, event2);
|
|
2340
|
+
}
|
|
2341
|
+
view.root.addEventListener("mouseup", stop);
|
|
2342
|
+
view.root.addEventListener("dragstart", stop);
|
|
2343
|
+
view.root.addEventListener("mousemove", move);
|
|
2344
|
+
}
|
|
2345
|
+
function handleTripleClick(view, pos) {
|
|
2346
|
+
const doc2 = view.state.doc, $cell = cellAround(doc2.resolve(pos));
|
|
2347
|
+
if (!$cell)
|
|
2348
|
+
return false;
|
|
2349
|
+
view.dispatch(view.state.tr.setSelection(new CellSelection($cell)));
|
|
2350
|
+
return true;
|
|
2351
|
+
}
|
|
2352
|
+
function maybeSetSelection(state, dispatch, selection) {
|
|
2353
|
+
if (selection.eq(state.selection))
|
|
2354
|
+
return false;
|
|
2355
|
+
if (dispatch)
|
|
2356
|
+
dispatch(state.tr.setSelection(selection).scrollIntoView());
|
|
2357
|
+
return true;
|
|
2358
|
+
}
|
|
2359
|
+
function atEndOfCell(view, axis, dir) {
|
|
2360
|
+
if (!(view.state.selection instanceof TextSelection))
|
|
2361
|
+
return null;
|
|
2362
|
+
const { $head } = view.state.selection;
|
|
2363
|
+
for (let d = $head.depth - 1; d >= 0; d--) {
|
|
2364
|
+
const parent = $head.node(d), index = dir < 0 ? $head.index(d) : $head.indexAfter(d);
|
|
2365
|
+
if (index != (dir < 0 ? 0 : parent.childCount))
|
|
2366
|
+
return null;
|
|
2367
|
+
if (parent.type.spec["tableRole"] == "cell" || parent.type.spec["tableRole"] == "header_cell") {
|
|
2368
|
+
const cellPos = $head.before(d);
|
|
2369
|
+
const dirStr = axis == "vert" ? dir > 0 ? "down" : "up" : dir > 0 ? "right" : "left";
|
|
2370
|
+
return view.endOfTextblock(dirStr) ? cellPos : null;
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
return null;
|
|
2374
|
+
}
|
|
2375
|
+
function arrow(axis, dir) {
|
|
2376
|
+
return (state, dispatch, view) => {
|
|
2377
|
+
const sel = state.selection;
|
|
2378
|
+
if (sel instanceof CellSelection) {
|
|
2379
|
+
return maybeSetSelection(state, dispatch, Selection.near(sel.$headCell, dir));
|
|
2380
|
+
}
|
|
2381
|
+
if (axis != "horiz" && !sel.empty)
|
|
2382
|
+
return false;
|
|
2383
|
+
const end = atEndOfCell(view, axis, dir);
|
|
2384
|
+
if (end == null)
|
|
2385
|
+
return false;
|
|
2386
|
+
if (axis == "horiz") {
|
|
2387
|
+
return maybeSetSelection(state, dispatch, Selection.near(state.doc.resolve(sel.head + dir), dir));
|
|
2388
|
+
} else {
|
|
2389
|
+
const $cell = state.doc.resolve(end), $next = nextCell($cell, axis, dir);
|
|
2390
|
+
let newSel;
|
|
2391
|
+
if ($next)
|
|
2392
|
+
newSel = Selection.near($next, 1);
|
|
2393
|
+
else if (dir < 0)
|
|
2394
|
+
newSel = Selection.near(state.doc.resolve($cell.before(-1)), -1);
|
|
2395
|
+
else
|
|
2396
|
+
newSel = Selection.near(state.doc.resolve($cell.after(-1)), 1);
|
|
2397
|
+
return maybeSetSelection(state, dispatch, newSel);
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
function shiftArrow(axis, dir) {
|
|
2402
|
+
return (state, dispatch, view) => {
|
|
2403
|
+
let sel = state.selection;
|
|
2404
|
+
if (!(sel instanceof CellSelection)) {
|
|
2405
|
+
const end = atEndOfCell(view, axis, dir);
|
|
2406
|
+
if (end == null)
|
|
2407
|
+
return false;
|
|
2408
|
+
sel = new CellSelection(state.doc.resolve(end));
|
|
2409
|
+
}
|
|
2410
|
+
const $head = nextCell(sel.$headCell, axis, dir);
|
|
2411
|
+
if (!$head)
|
|
2412
|
+
return false;
|
|
2413
|
+
return maybeSetSelection(state, dispatch, new CellSelection(sel.$anchorCell, $head));
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
function deleteCellSelection(state, dispatch) {
|
|
2417
|
+
const sel = state.selection;
|
|
2418
|
+
if (!(sel instanceof CellSelection))
|
|
2419
|
+
return false;
|
|
2420
|
+
if (dispatch) {
|
|
2421
|
+
const tr = state.tr, baseContent = tableNodeTypes(state.schema).cell.createAndFill().content;
|
|
2422
|
+
sel.forEachCell((cell, pos) => {
|
|
2423
|
+
if (!cell.content.eq(baseContent))
|
|
2424
|
+
tr.replace(tr.mapping.map(pos + 1), tr.mapping.map(pos + cell.nodeSize - 1), new Slice(baseContent, 0, 0));
|
|
2425
|
+
});
|
|
2426
|
+
if (tr.docChanged)
|
|
2427
|
+
dispatch(tr);
|
|
2428
|
+
}
|
|
2429
|
+
return true;
|
|
2430
|
+
}
|
|
2431
|
+
const handleKeyDown = keydownHandler({
|
|
2432
|
+
ArrowLeft: arrow("horiz", -1),
|
|
2433
|
+
ArrowRight: arrow("horiz", 1),
|
|
2434
|
+
ArrowUp: arrow("vert", -1),
|
|
2435
|
+
ArrowDown: arrow("vert", 1),
|
|
2436
|
+
"Shift-ArrowLeft": shiftArrow("horiz", -1),
|
|
2437
|
+
"Shift-ArrowRight": shiftArrow("horiz", 1),
|
|
2438
|
+
"Shift-ArrowUp": shiftArrow("vert", -1),
|
|
2439
|
+
"Shift-ArrowDown": shiftArrow("vert", 1),
|
|
2440
|
+
Backspace: deleteCellSelection,
|
|
2441
|
+
"Mod-Backspace": deleteCellSelection,
|
|
2442
|
+
Delete: deleteCellSelection,
|
|
2443
|
+
"Mod-Delete": deleteCellSelection
|
|
850
2444
|
});
|
|
2445
|
+
function handlePaste(view, _, slice) {
|
|
2446
|
+
if (!isInTable(view.state))
|
|
2447
|
+
return false;
|
|
2448
|
+
let cells = pastedCells(slice);
|
|
2449
|
+
const sel = view.state.selection;
|
|
2450
|
+
if (sel instanceof CellSelection) {
|
|
2451
|
+
if (!cells)
|
|
2452
|
+
cells = {
|
|
2453
|
+
width: 1,
|
|
2454
|
+
height: 1,
|
|
2455
|
+
rows: [Fragment.from(fitSlice(tableNodeTypes(view.state.schema).cell, slice))]
|
|
2456
|
+
};
|
|
2457
|
+
const table2 = sel.$anchorCell.node(-1), start = sel.$anchorCell.start(-1);
|
|
2458
|
+
const rect = TableMap.get(table2).rectBetween(sel.$anchorCell.pos - start, sel.$headCell.pos - start);
|
|
2459
|
+
cells = clipCells(cells, rect.right - rect.left, rect.bottom - rect.top);
|
|
2460
|
+
insertCells(view.state, view.dispatch, start, rect, cells);
|
|
2461
|
+
return true;
|
|
2462
|
+
} else if (cells) {
|
|
2463
|
+
const $cell = selectionCell(view.state), start = $cell.start(-1);
|
|
2464
|
+
insertCells(view.state, view.dispatch, start, TableMap.get($cell.node(-1)).findCell($cell.pos - start), cells);
|
|
2465
|
+
return true;
|
|
2466
|
+
} else {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
function tableEditing({ allowTableNodeSelection = false } = {}) {
|
|
2471
|
+
return new Plugin({
|
|
2472
|
+
key: tableEditingKey,
|
|
2473
|
+
state: {
|
|
2474
|
+
init() {
|
|
2475
|
+
return null;
|
|
2476
|
+
},
|
|
2477
|
+
apply(tr, cur) {
|
|
2478
|
+
const set = tr.getMeta(tableEditingKey);
|
|
2479
|
+
if (set != null)
|
|
2480
|
+
return set == -1 ? null : set;
|
|
2481
|
+
if (cur == null || !tr.docChanged)
|
|
2482
|
+
return cur;
|
|
2483
|
+
const { deleted, pos } = tr.mapping.mapResult(cur);
|
|
2484
|
+
return deleted ? null : pos;
|
|
2485
|
+
}
|
|
2486
|
+
},
|
|
2487
|
+
props: {
|
|
2488
|
+
decorations: drawCellSelection,
|
|
2489
|
+
handleDOMEvents: {
|
|
2490
|
+
mousedown: handleMouseDown
|
|
2491
|
+
},
|
|
2492
|
+
createSelectionBetween(view) {
|
|
2493
|
+
if (tableEditingKey.getState(view.state) != null)
|
|
2494
|
+
return view.state.selection;
|
|
2495
|
+
return null;
|
|
2496
|
+
},
|
|
2497
|
+
handleTripleClick,
|
|
2498
|
+
handleKeyDown,
|
|
2499
|
+
handlePaste
|
|
2500
|
+
},
|
|
2501
|
+
appendTransaction(_, oldState, state) {
|
|
2502
|
+
return normalizeSelection(state, fixTables(state, oldState), allowTableNodeSelection);
|
|
2503
|
+
}
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
851
2506
|
const SupportedKeys$1 = {
|
|
852
2507
|
NextCell: "NextCell",
|
|
853
2508
|
PrevCell: "PrevCell",
|