@tiptap/extension-table 2.0.0-beta.205 → 2.0.0-beta.207

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.
@@ -3,4390 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var core = require('@tiptap/core');
6
+ var prosemirrorTables = require('@tiptap/prosemirror-tables');
6
7
  var prosemirrorState = require('prosemirror-state');
7
- var prosemirrorModel = require('prosemirror-model');
8
- var prosemirrorView = require('prosemirror-view');
9
-
10
- var base = {
11
- 8: "Backspace",
12
- 9: "Tab",
13
- 10: "Enter",
14
- 12: "NumLock",
15
- 13: "Enter",
16
- 16: "Shift",
17
- 17: "Control",
18
- 18: "Alt",
19
- 20: "CapsLock",
20
- 27: "Escape",
21
- 32: " ",
22
- 33: "PageUp",
23
- 34: "PageDown",
24
- 35: "End",
25
- 36: "Home",
26
- 37: "ArrowLeft",
27
- 38: "ArrowUp",
28
- 39: "ArrowRight",
29
- 40: "ArrowDown",
30
- 44: "PrintScreen",
31
- 45: "Insert",
32
- 46: "Delete",
33
- 59: ";",
34
- 61: "=",
35
- 91: "Meta",
36
- 92: "Meta",
37
- 106: "*",
38
- 107: "+",
39
- 108: ",",
40
- 109: "-",
41
- 110: ".",
42
- 111: "/",
43
- 144: "NumLock",
44
- 145: "ScrollLock",
45
- 160: "Shift",
46
- 161: "Shift",
47
- 162: "Control",
48
- 163: "Control",
49
- 164: "Alt",
50
- 165: "Alt",
51
- 173: "-",
52
- 186: ";",
53
- 187: "=",
54
- 188: ",",
55
- 189: "-",
56
- 190: ".",
57
- 191: "/",
58
- 192: "`",
59
- 219: "[",
60
- 220: "\\",
61
- 221: "]",
62
- 222: "'",
63
- 229: "q"
64
- };
65
-
66
- var shift = {
67
- 48: ")",
68
- 49: "!",
69
- 50: "@",
70
- 51: "#",
71
- 52: "$",
72
- 53: "%",
73
- 54: "^",
74
- 55: "&",
75
- 56: "*",
76
- 57: "(",
77
- 59: ":",
78
- 61: "+",
79
- 173: "_",
80
- 186: ":",
81
- 187: "+",
82
- 188: "<",
83
- 189: "_",
84
- 190: ">",
85
- 191: "?",
86
- 192: "~",
87
- 219: "{",
88
- 220: "|",
89
- 221: "}",
90
- 222: "\"",
91
- 229: "Q"
92
- };
93
-
94
- var chrome = typeof navigator != "undefined" && /Chrome\/(\d+)/.exec(navigator.userAgent);
95
- var safari = typeof navigator != "undefined" && /Apple Computer/.test(navigator.vendor);
96
- var gecko = typeof navigator != "undefined" && /Gecko\/\d+/.test(navigator.userAgent);
97
- var mac$1 = typeof navigator != "undefined" && /Mac/.test(navigator.platform);
98
- var ie = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
99
- var brokenModifierNames = chrome && (mac$1 || +chrome[1] < 57) || gecko && mac$1;
100
-
101
- // Fill in the digit keys
102
- for (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i);
103
-
104
- // The function keys
105
- for (var i = 1; i <= 24; i++) base[i + 111] = "F" + i;
106
-
107
- // And the alphabetic keys
108
- for (var i = 65; i <= 90; i++) {
109
- base[i] = String.fromCharCode(i + 32);
110
- shift[i] = String.fromCharCode(i);
111
- }
112
-
113
- // For each code that doesn't have a shift-equivalent, copy the base name
114
- for (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code];
115
-
116
- function keyName(event) {
117
- // Don't trust event.key in Chrome when there are modifiers until
118
- // they fix https://bugs.chromium.org/p/chromium/issues/detail?id=633838
119
- var ignoreKey = brokenModifierNames && (event.ctrlKey || event.altKey || event.metaKey) ||
120
- (safari || ie) && event.shiftKey && event.key && event.key.length == 1;
121
- var name = (!ignoreKey && event.key) ||
122
- (event.shiftKey ? shift : base)[event.keyCode] ||
123
- event.key || "Unidentified";
124
- // Edge sometimes produces wrong names (Issue #3)
125
- if (name == "Esc") name = "Escape";
126
- if (name == "Del") name = "Delete";
127
- // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
128
- if (name == "Left") name = "ArrowLeft";
129
- if (name == "Up") name = "ArrowUp";
130
- if (name == "Right") name = "ArrowRight";
131
- if (name == "Down") name = "ArrowDown";
132
- return name
133
- }
134
-
135
- const mac = typeof navigator != "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
136
- function normalizeKeyName(name) {
137
- let parts = name.split(/-(?!$)/), result = parts[parts.length - 1];
138
- if (result == "Space")
139
- result = " ";
140
- let alt, ctrl, shift, meta;
141
- for (let i = 0; i < parts.length - 1; i++) {
142
- let mod = parts[i];
143
- if (/^(cmd|meta|m)$/i.test(mod))
144
- meta = true;
145
- else if (/^a(lt)?$/i.test(mod))
146
- alt = true;
147
- else if (/^(c|ctrl|control)$/i.test(mod))
148
- ctrl = true;
149
- else if (/^s(hift)?$/i.test(mod))
150
- shift = true;
151
- else if (/^mod$/i.test(mod)) {
152
- if (mac)
153
- meta = true;
154
- else
155
- ctrl = true;
156
- }
157
- else
158
- throw new Error("Unrecognized modifier name: " + mod);
159
- }
160
- if (alt)
161
- result = "Alt-" + result;
162
- if (ctrl)
163
- result = "Ctrl-" + result;
164
- if (meta)
165
- result = "Meta-" + result;
166
- if (shift)
167
- result = "Shift-" + result;
168
- return result;
169
- }
170
- function normalize(map) {
171
- let copy = Object.create(null);
172
- for (let prop in map)
173
- copy[normalizeKeyName(prop)] = map[prop];
174
- return copy;
175
- }
176
- function modifiers(name, event, shift) {
177
- if (event.altKey)
178
- name = "Alt-" + name;
179
- if (event.ctrlKey)
180
- name = "Ctrl-" + name;
181
- if (event.metaKey)
182
- name = "Meta-" + name;
183
- if (shift !== false && event.shiftKey)
184
- name = "Shift-" + name;
185
- return name;
186
- }
187
- /**
188
- Given a set of bindings (using the same format as
189
- [`keymap`](https://prosemirror.net/docs/ref/#keymap.keymap)), return a [keydown
190
- handler](https://prosemirror.net/docs/ref/#view.EditorProps.handleKeyDown) that handles them.
191
- */
192
- function keydownHandler(bindings) {
193
- let map = normalize(bindings);
194
- return function (view, event) {
195
- let name = keyName(event), isChar = name.length == 1 && name != " ", baseName;
196
- let direct = map[modifiers(name, event, !isChar)];
197
- if (direct && direct(view.state, view.dispatch, view))
198
- return true;
199
- if (isChar && (event.shiftKey || event.altKey || event.metaKey || name.charCodeAt(0) > 127) &&
200
- (baseName = base[event.keyCode]) && baseName != name) {
201
- // Try falling back to the keyCode when there's a modifier
202
- // active or the character produced isn't ASCII, and our table
203
- // produces a different name from the the keyCode. See #668,
204
- // #1060
205
- let fromCode = map[modifiers(baseName, event, true)];
206
- if (fromCode && fromCode(view.state, view.dispatch, view))
207
- return true;
208
- }
209
- else if (isChar && event.shiftKey) {
210
- // Otherwise, if shift is active, also try the binding with the
211
- // Shift- prefix enabled. See #997
212
- let withShift = map[modifiers(name, event, true)];
213
- if (withShift && withShift(view.state, view.dispatch, view))
214
- return true;
215
- }
216
- return false;
217
- };
218
- }
219
-
220
- // Recovery values encode a range index and an offset. They are
221
- // represented as numbers, because tons of them will be created when
222
- // mapping, for example, a large number of decorations. The number's
223
- // lower 16 bits provide the index, the remaining bits the offset.
224
- //
225
- // Note: We intentionally don't use bit shift operators to en- and
226
- // decode these, since those clip to 32 bits, which we might in rare
227
- // cases want to overflow. A 64-bit float can represent 48-bit
228
- // integers precisely.
229
- const lower16 = 0xffff;
230
- const factor16 = Math.pow(2, 16);
231
- function makeRecover(index, offset) { return index + offset * factor16; }
232
- function recoverIndex(value) { return value & lower16; }
233
- function recoverOffset(value) { return (value - (value & lower16)) / factor16; }
234
- const DEL_BEFORE = 1, DEL_AFTER = 2, DEL_ACROSS = 4, DEL_SIDE = 8;
235
- /**
236
- An object representing a mapped position with extra
237
- information.
238
- */
239
- class MapResult {
240
- /**
241
- @internal
242
- */
243
- constructor(
244
- /**
245
- The mapped version of the position.
246
- */
247
- pos,
248
- /**
249
- @internal
250
- */
251
- delInfo,
252
- /**
253
- @internal
254
- */
255
- recover) {
256
- this.pos = pos;
257
- this.delInfo = delInfo;
258
- this.recover = recover;
259
- }
260
- /**
261
- Tells you whether the position was deleted, that is, whether the
262
- step removed the token on the side queried (via the `assoc`)
263
- argument from the document.
264
- */
265
- get deleted() { return (this.delInfo & DEL_SIDE) > 0; }
266
- /**
267
- Tells you whether the token before the mapped position was deleted.
268
- */
269
- get deletedBefore() { return (this.delInfo & (DEL_BEFORE | DEL_ACROSS)) > 0; }
270
- /**
271
- True when the token after the mapped position was deleted.
272
- */
273
- get deletedAfter() { return (this.delInfo & (DEL_AFTER | DEL_ACROSS)) > 0; }
274
- /**
275
- Tells whether any of the steps mapped through deletes across the
276
- position (including both the token before and after the
277
- position).
278
- */
279
- get deletedAcross() { return (this.delInfo & DEL_ACROSS) > 0; }
280
- }
281
- /**
282
- A map describing the deletions and insertions made by a step, which
283
- can be used to find the correspondence between positions in the
284
- pre-step version of a document and the same position in the
285
- post-step version.
286
- */
287
- class StepMap {
288
- /**
289
- Create a position map. The modifications to the document are
290
- represented as an array of numbers, in which each group of three
291
- represents a modified chunk as `[start, oldSize, newSize]`.
292
- */
293
- constructor(
294
- /**
295
- @internal
296
- */
297
- ranges,
298
- /**
299
- @internal
300
- */
301
- inverted = false) {
302
- this.ranges = ranges;
303
- this.inverted = inverted;
304
- if (!ranges.length && StepMap.empty)
305
- return StepMap.empty;
306
- }
307
- /**
308
- @internal
309
- */
310
- recover(value) {
311
- let diff = 0, index = recoverIndex(value);
312
- if (!this.inverted)
313
- for (let i = 0; i < index; i++)
314
- diff += this.ranges[i * 3 + 2] - this.ranges[i * 3 + 1];
315
- return this.ranges[index * 3] + diff + recoverOffset(value);
316
- }
317
- mapResult(pos, assoc = 1) { return this._map(pos, assoc, false); }
318
- map(pos, assoc = 1) { return this._map(pos, assoc, true); }
319
- /**
320
- @internal
321
- */
322
- _map(pos, assoc, simple) {
323
- let diff = 0, oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
324
- for (let i = 0; i < this.ranges.length; i += 3) {
325
- let start = this.ranges[i] - (this.inverted ? diff : 0);
326
- if (start > pos)
327
- break;
328
- let oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex], end = start + oldSize;
329
- if (pos <= end) {
330
- let side = !oldSize ? assoc : pos == start ? -1 : pos == end ? 1 : assoc;
331
- let result = start + diff + (side < 0 ? 0 : newSize);
332
- if (simple)
333
- return result;
334
- let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start);
335
- let del = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
336
- if (assoc < 0 ? pos != start : pos != end)
337
- del |= DEL_SIDE;
338
- return new MapResult(result, del, recover);
339
- }
340
- diff += newSize - oldSize;
341
- }
342
- return simple ? pos + diff : new MapResult(pos + diff, 0, null);
343
- }
344
- /**
345
- @internal
346
- */
347
- touches(pos, recover) {
348
- let diff = 0, index = recoverIndex(recover);
349
- let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
350
- for (let i = 0; i < this.ranges.length; i += 3) {
351
- let start = this.ranges[i] - (this.inverted ? diff : 0);
352
- if (start > pos)
353
- break;
354
- let oldSize = this.ranges[i + oldIndex], end = start + oldSize;
355
- if (pos <= end && i == index * 3)
356
- return true;
357
- diff += this.ranges[i + newIndex] - oldSize;
358
- }
359
- return false;
360
- }
361
- /**
362
- Calls the given function on each of the changed ranges included in
363
- this map.
364
- */
365
- forEach(f) {
366
- let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2;
367
- for (let i = 0, diff = 0; i < this.ranges.length; i += 3) {
368
- let start = this.ranges[i], oldStart = start - (this.inverted ? diff : 0), newStart = start + (this.inverted ? 0 : diff);
369
- let oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex];
370
- f(oldStart, oldStart + oldSize, newStart, newStart + newSize);
371
- diff += newSize - oldSize;
372
- }
373
- }
374
- /**
375
- Create an inverted version of this map. The result can be used to
376
- map positions in the post-step document to the pre-step document.
377
- */
378
- invert() {
379
- return new StepMap(this.ranges, !this.inverted);
380
- }
381
- /**
382
- @internal
383
- */
384
- toString() {
385
- return (this.inverted ? "-" : "") + JSON.stringify(this.ranges);
386
- }
387
- /**
388
- Create a map that moves all positions by offset `n` (which may be
389
- negative). This can be useful when applying steps meant for a
390
- sub-document to a larger document, or vice-versa.
391
- */
392
- static offset(n) {
393
- return n == 0 ? StepMap.empty : new StepMap(n < 0 ? [0, -n, 0] : [0, 0, n]);
394
- }
395
- }
396
- /**
397
- A StepMap that contains no changed ranges.
398
- */
399
- StepMap.empty = new StepMap([]);
400
- /**
401
- A mapping represents a pipeline of zero or more [step
402
- maps](https://prosemirror.net/docs/ref/#transform.StepMap). It has special provisions for losslessly
403
- handling mapping positions through a series of steps in which some
404
- steps are inverted versions of earlier steps. (This comes up when
405
- ‘[rebasing](/docs/guide/#transform.rebasing)’ steps for
406
- collaboration or history management.)
407
- */
408
- class Mapping {
409
- /**
410
- Create a new mapping with the given position maps.
411
- */
412
- constructor(
413
- /**
414
- The step maps in this mapping.
415
- */
416
- maps = [],
417
- /**
418
- @internal
419
- */
420
- mirror,
421
- /**
422
- The starting position in the `maps` array, used when `map` or
423
- `mapResult` is called.
424
- */
425
- from = 0,
426
- /**
427
- The end position in the `maps` array.
428
- */
429
- to = maps.length) {
430
- this.maps = maps;
431
- this.mirror = mirror;
432
- this.from = from;
433
- this.to = to;
434
- }
435
- /**
436
- Create a mapping that maps only through a part of this one.
437
- */
438
- slice(from = 0, to = this.maps.length) {
439
- return new Mapping(this.maps, this.mirror, from, to);
440
- }
441
- /**
442
- @internal
443
- */
444
- copy() {
445
- return new Mapping(this.maps.slice(), this.mirror && this.mirror.slice(), this.from, this.to);
446
- }
447
- /**
448
- Add a step map to the end of this mapping. If `mirrors` is
449
- given, it should be the index of the step map that is the mirror
450
- image of this one.
451
- */
452
- appendMap(map, mirrors) {
453
- this.to = this.maps.push(map);
454
- if (mirrors != null)
455
- this.setMirror(this.maps.length - 1, mirrors);
456
- }
457
- /**
458
- Add all the step maps in a given mapping to this one (preserving
459
- mirroring information).
460
- */
461
- appendMapping(mapping) {
462
- for (let i = 0, startSize = this.maps.length; i < mapping.maps.length; i++) {
463
- let mirr = mapping.getMirror(i);
464
- this.appendMap(mapping.maps[i], mirr != null && mirr < i ? startSize + mirr : undefined);
465
- }
466
- }
467
- /**
468
- Finds the offset of the step map that mirrors the map at the
469
- given offset, in this mapping (as per the second argument to
470
- `appendMap`).
471
- */
472
- getMirror(n) {
473
- if (this.mirror)
474
- for (let i = 0; i < this.mirror.length; i++)
475
- if (this.mirror[i] == n)
476
- return this.mirror[i + (i % 2 ? -1 : 1)];
477
- }
478
- /**
479
- @internal
480
- */
481
- setMirror(n, m) {
482
- if (!this.mirror)
483
- this.mirror = [];
484
- this.mirror.push(n, m);
485
- }
486
- /**
487
- Append the inverse of the given mapping to this one.
488
- */
489
- appendMappingInverted(mapping) {
490
- for (let i = mapping.maps.length - 1, totalSize = this.maps.length + mapping.maps.length; i >= 0; i--) {
491
- let mirr = mapping.getMirror(i);
492
- this.appendMap(mapping.maps[i].invert(), mirr != null && mirr > i ? totalSize - mirr - 1 : undefined);
493
- }
494
- }
495
- /**
496
- Create an inverted version of this mapping.
497
- */
498
- invert() {
499
- let inverse = new Mapping;
500
- inverse.appendMappingInverted(this);
501
- return inverse;
502
- }
503
- /**
504
- Map a position through this mapping.
505
- */
506
- map(pos, assoc = 1) {
507
- if (this.mirror)
508
- return this._map(pos, assoc, true);
509
- for (let i = this.from; i < this.to; i++)
510
- pos = this.maps[i].map(pos, assoc);
511
- return pos;
512
- }
513
- /**
514
- Map a position through this mapping, returning a mapping
515
- result.
516
- */
517
- mapResult(pos, assoc = 1) { return this._map(pos, assoc, false); }
518
- /**
519
- @internal
520
- */
521
- _map(pos, assoc, simple) {
522
- let delInfo = 0;
523
- for (let i = this.from; i < this.to; i++) {
524
- let map = this.maps[i], result = map.mapResult(pos, assoc);
525
- if (result.recover != null) {
526
- let corr = this.getMirror(i);
527
- if (corr != null && corr > i && corr < this.to) {
528
- i = corr;
529
- pos = this.maps[corr].recover(result.recover);
530
- continue;
531
- }
532
- }
533
- delInfo |= result.delInfo;
534
- pos = result.pos;
535
- }
536
- return simple ? pos : new MapResult(pos, delInfo, null);
537
- }
538
- }
539
-
540
- const stepsByID = Object.create(null);
541
- /**
542
- A step object represents an atomic change. It generally applies
543
- only to the document it was created for, since the positions
544
- stored in it will only make sense for that document.
545
-
546
- New steps are defined by creating classes that extend `Step`,
547
- overriding the `apply`, `invert`, `map`, `getMap` and `fromJSON`
548
- methods, and registering your class with a unique
549
- JSON-serialization identifier using
550
- [`Step.jsonID`](https://prosemirror.net/docs/ref/#transform.Step^jsonID).
551
- */
552
- class Step {
553
- /**
554
- Get the step map that represents the changes made by this step,
555
- and which can be used to transform between positions in the old
556
- and the new document.
557
- */
558
- getMap() { return StepMap.empty; }
559
- /**
560
- Try to merge this step with another one, to be applied directly
561
- after it. Returns the merged step when possible, null if the
562
- steps can't be merged.
563
- */
564
- merge(other) { return null; }
565
- /**
566
- Deserialize a step from its JSON representation. Will call
567
- through to the step class' own implementation of this method.
568
- */
569
- static fromJSON(schema, json) {
570
- if (!json || !json.stepType)
571
- throw new RangeError("Invalid input for Step.fromJSON");
572
- let type = stepsByID[json.stepType];
573
- if (!type)
574
- throw new RangeError(`No step type ${json.stepType} defined`);
575
- return type.fromJSON(schema, json);
576
- }
577
- /**
578
- To be able to serialize steps to JSON, each step needs a string
579
- ID to attach to its JSON representation. Use this method to
580
- register an ID for your step classes. Try to pick something
581
- that's unlikely to clash with steps from other modules.
582
- */
583
- static jsonID(id, stepClass) {
584
- if (id in stepsByID)
585
- throw new RangeError("Duplicate use of step JSON ID " + id);
586
- stepsByID[id] = stepClass;
587
- stepClass.prototype.jsonID = id;
588
- return stepClass;
589
- }
590
- }
591
- /**
592
- The result of [applying](https://prosemirror.net/docs/ref/#transform.Step.apply) a step. Contains either a
593
- new document or a failure value.
594
- */
595
- class StepResult {
596
- /**
597
- @internal
598
- */
599
- constructor(
600
- /**
601
- The transformed document, if successful.
602
- */
603
- doc,
604
- /**
605
- The failure message, if unsuccessful.
606
- */
607
- failed) {
608
- this.doc = doc;
609
- this.failed = failed;
610
- }
611
- /**
612
- Create a successful step result.
613
- */
614
- static ok(doc) { return new StepResult(doc, null); }
615
- /**
616
- Create a failed step result.
617
- */
618
- static fail(message) { return new StepResult(null, message); }
619
- /**
620
- Call [`Node.replace`](https://prosemirror.net/docs/ref/#model.Node.replace) with the given
621
- arguments. Create a successful result if it succeeds, and a
622
- failed one if it throws a `ReplaceError`.
623
- */
624
- static fromReplace(doc, from, to, slice) {
625
- try {
626
- return StepResult.ok(doc.replace(from, to, slice));
627
- }
628
- catch (e) {
629
- if (e instanceof prosemirrorModel.ReplaceError)
630
- return StepResult.fail(e.message);
631
- throw e;
632
- }
633
- }
634
- }
635
-
636
- function mapFragment(fragment, f, parent) {
637
- let mapped = [];
638
- for (let i = 0; i < fragment.childCount; i++) {
639
- let child = fragment.child(i);
640
- if (child.content.size)
641
- child = child.copy(mapFragment(child.content, f, child));
642
- if (child.isInline)
643
- child = f(child, parent, i);
644
- mapped.push(child);
645
- }
646
- return prosemirrorModel.Fragment.fromArray(mapped);
647
- }
648
- /**
649
- Add a mark to all inline content between two positions.
650
- */
651
- class AddMarkStep extends Step {
652
- /**
653
- Create a mark step.
654
- */
655
- constructor(
656
- /**
657
- The start of the marked range.
658
- */
659
- from,
660
- /**
661
- The end of the marked range.
662
- */
663
- to,
664
- /**
665
- The mark to add.
666
- */
667
- mark) {
668
- super();
669
- this.from = from;
670
- this.to = to;
671
- this.mark = mark;
672
- }
673
- apply(doc) {
674
- let oldSlice = doc.slice(this.from, this.to), $from = doc.resolve(this.from);
675
- let parent = $from.node($from.sharedDepth(this.to));
676
- let slice = new prosemirrorModel.Slice(mapFragment(oldSlice.content, (node, parent) => {
677
- if (!node.isAtom || !parent.type.allowsMarkType(this.mark.type))
678
- return node;
679
- return node.mark(this.mark.addToSet(node.marks));
680
- }, parent), oldSlice.openStart, oldSlice.openEnd);
681
- return StepResult.fromReplace(doc, this.from, this.to, slice);
682
- }
683
- invert() {
684
- return new RemoveMarkStep(this.from, this.to, this.mark);
685
- }
686
- map(mapping) {
687
- let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
688
- if (from.deleted && to.deleted || from.pos >= to.pos)
689
- return null;
690
- return new AddMarkStep(from.pos, to.pos, this.mark);
691
- }
692
- merge(other) {
693
- if (other instanceof AddMarkStep &&
694
- other.mark.eq(this.mark) &&
695
- this.from <= other.to && this.to >= other.from)
696
- return new AddMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark);
697
- return null;
698
- }
699
- toJSON() {
700
- return { stepType: "addMark", mark: this.mark.toJSON(),
701
- from: this.from, to: this.to };
702
- }
703
- /**
704
- @internal
705
- */
706
- static fromJSON(schema, json) {
707
- if (typeof json.from != "number" || typeof json.to != "number")
708
- throw new RangeError("Invalid input for AddMarkStep.fromJSON");
709
- return new AddMarkStep(json.from, json.to, schema.markFromJSON(json.mark));
710
- }
711
- }
712
- Step.jsonID("addMark", AddMarkStep);
713
- /**
714
- Remove a mark from all inline content between two positions.
715
- */
716
- class RemoveMarkStep extends Step {
717
- /**
718
- Create a mark-removing step.
719
- */
720
- constructor(
721
- /**
722
- The start of the unmarked range.
723
- */
724
- from,
725
- /**
726
- The end of the unmarked range.
727
- */
728
- to,
729
- /**
730
- The mark to remove.
731
- */
732
- mark) {
733
- super();
734
- this.from = from;
735
- this.to = to;
736
- this.mark = mark;
737
- }
738
- apply(doc) {
739
- let oldSlice = doc.slice(this.from, this.to);
740
- let slice = new prosemirrorModel.Slice(mapFragment(oldSlice.content, node => {
741
- return node.mark(this.mark.removeFromSet(node.marks));
742
- }, doc), oldSlice.openStart, oldSlice.openEnd);
743
- return StepResult.fromReplace(doc, this.from, this.to, slice);
744
- }
745
- invert() {
746
- return new AddMarkStep(this.from, this.to, this.mark);
747
- }
748
- map(mapping) {
749
- let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
750
- if (from.deleted && to.deleted || from.pos >= to.pos)
751
- return null;
752
- return new RemoveMarkStep(from.pos, to.pos, this.mark);
753
- }
754
- merge(other) {
755
- if (other instanceof RemoveMarkStep &&
756
- other.mark.eq(this.mark) &&
757
- this.from <= other.to && this.to >= other.from)
758
- return new RemoveMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark);
759
- return null;
760
- }
761
- toJSON() {
762
- return { stepType: "removeMark", mark: this.mark.toJSON(),
763
- from: this.from, to: this.to };
764
- }
765
- /**
766
- @internal
767
- */
768
- static fromJSON(schema, json) {
769
- if (typeof json.from != "number" || typeof json.to != "number")
770
- throw new RangeError("Invalid input for RemoveMarkStep.fromJSON");
771
- return new RemoveMarkStep(json.from, json.to, schema.markFromJSON(json.mark));
772
- }
773
- }
774
- Step.jsonID("removeMark", RemoveMarkStep);
775
- /**
776
- Add a mark to a specific node.
777
- */
778
- class AddNodeMarkStep extends Step {
779
- /**
780
- Create a node mark step.
781
- */
782
- constructor(
783
- /**
784
- The position of the target node.
785
- */
786
- pos,
787
- /**
788
- The mark to add.
789
- */
790
- mark) {
791
- super();
792
- this.pos = pos;
793
- this.mark = mark;
794
- }
795
- apply(doc) {
796
- let node = doc.nodeAt(this.pos);
797
- if (!node)
798
- return StepResult.fail("No node at mark step's position");
799
- let updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks));
800
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
801
- }
802
- invert(doc) {
803
- let node = doc.nodeAt(this.pos);
804
- if (node) {
805
- let newSet = this.mark.addToSet(node.marks);
806
- if (newSet.length == node.marks.length) {
807
- for (let i = 0; i < node.marks.length; i++)
808
- if (!node.marks[i].isInSet(newSet))
809
- return new AddNodeMarkStep(this.pos, node.marks[i]);
810
- return new AddNodeMarkStep(this.pos, this.mark);
811
- }
812
- }
813
- return new RemoveNodeMarkStep(this.pos, this.mark);
814
- }
815
- map(mapping) {
816
- let pos = mapping.mapResult(this.pos, 1);
817
- return pos.deletedAfter ? null : new AddNodeMarkStep(pos.pos, this.mark);
818
- }
819
- toJSON() {
820
- return { stepType: "addNodeMark", pos: this.pos, mark: this.mark.toJSON() };
821
- }
822
- /**
823
- @internal
824
- */
825
- static fromJSON(schema, json) {
826
- if (typeof json.pos != "number")
827
- throw new RangeError("Invalid input for AddNodeMarkStep.fromJSON");
828
- return new AddNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
829
- }
830
- }
831
- Step.jsonID("addNodeMark", AddNodeMarkStep);
832
- /**
833
- Remove a mark from a specific node.
834
- */
835
- class RemoveNodeMarkStep extends Step {
836
- /**
837
- Create a mark-removing step.
838
- */
839
- constructor(
840
- /**
841
- The position of the target node.
842
- */
843
- pos,
844
- /**
845
- The mark to remove.
846
- */
847
- mark) {
848
- super();
849
- this.pos = pos;
850
- this.mark = mark;
851
- }
852
- apply(doc) {
853
- let node = doc.nodeAt(this.pos);
854
- if (!node)
855
- return StepResult.fail("No node at mark step's position");
856
- let updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks));
857
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
858
- }
859
- invert(doc) {
860
- let node = doc.nodeAt(this.pos);
861
- if (!node || !this.mark.isInSet(node.marks))
862
- return this;
863
- return new AddNodeMarkStep(this.pos, this.mark);
864
- }
865
- map(mapping) {
866
- let pos = mapping.mapResult(this.pos, 1);
867
- return pos.deletedAfter ? null : new RemoveNodeMarkStep(pos.pos, this.mark);
868
- }
869
- toJSON() {
870
- return { stepType: "removeNodeMark", pos: this.pos, mark: this.mark.toJSON() };
871
- }
872
- /**
873
- @internal
874
- */
875
- static fromJSON(schema, json) {
876
- if (typeof json.pos != "number")
877
- throw new RangeError("Invalid input for RemoveNodeMarkStep.fromJSON");
878
- return new RemoveNodeMarkStep(json.pos, schema.markFromJSON(json.mark));
879
- }
880
- }
881
- Step.jsonID("removeNodeMark", RemoveNodeMarkStep);
882
-
883
- /**
884
- Replace a part of the document with a slice of new content.
885
- */
886
- class ReplaceStep extends Step {
887
- /**
888
- The given `slice` should fit the 'gap' between `from` and
889
- `to`—the depths must line up, and the surrounding nodes must be
890
- able to be joined with the open sides of the slice. When
891
- `structure` is true, the step will fail if the content between
892
- from and to is not just a sequence of closing and then opening
893
- tokens (this is to guard against rebased replace steps
894
- overwriting something they weren't supposed to).
895
- */
896
- constructor(
897
- /**
898
- The start position of the replaced range.
899
- */
900
- from,
901
- /**
902
- The end position of the replaced range.
903
- */
904
- to,
905
- /**
906
- The slice to insert.
907
- */
908
- slice,
909
- /**
910
- @internal
911
- */
912
- structure = false) {
913
- super();
914
- this.from = from;
915
- this.to = to;
916
- this.slice = slice;
917
- this.structure = structure;
918
- }
919
- apply(doc) {
920
- if (this.structure && contentBetween(doc, this.from, this.to))
921
- return StepResult.fail("Structure replace would overwrite content");
922
- return StepResult.fromReplace(doc, this.from, this.to, this.slice);
923
- }
924
- getMap() {
925
- return new StepMap([this.from, this.to - this.from, this.slice.size]);
926
- }
927
- invert(doc) {
928
- return new ReplaceStep(this.from, this.from + this.slice.size, doc.slice(this.from, this.to));
929
- }
930
- map(mapping) {
931
- let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
932
- if (from.deletedAcross && to.deletedAcross)
933
- return null;
934
- return new ReplaceStep(from.pos, Math.max(from.pos, to.pos), this.slice);
935
- }
936
- merge(other) {
937
- if (!(other instanceof ReplaceStep) || other.structure || this.structure)
938
- return null;
939
- if (this.from + this.slice.size == other.from && !this.slice.openEnd && !other.slice.openStart) {
940
- let slice = this.slice.size + other.slice.size == 0 ? prosemirrorModel.Slice.empty
941
- : new prosemirrorModel.Slice(this.slice.content.append(other.slice.content), this.slice.openStart, other.slice.openEnd);
942
- return new ReplaceStep(this.from, this.to + (other.to - other.from), slice, this.structure);
943
- }
944
- else if (other.to == this.from && !this.slice.openStart && !other.slice.openEnd) {
945
- let slice = this.slice.size + other.slice.size == 0 ? prosemirrorModel.Slice.empty
946
- : new prosemirrorModel.Slice(other.slice.content.append(this.slice.content), other.slice.openStart, this.slice.openEnd);
947
- return new ReplaceStep(other.from, this.to, slice, this.structure);
948
- }
949
- else {
950
- return null;
951
- }
952
- }
953
- toJSON() {
954
- let json = { stepType: "replace", from: this.from, to: this.to };
955
- if (this.slice.size)
956
- json.slice = this.slice.toJSON();
957
- if (this.structure)
958
- json.structure = true;
959
- return json;
960
- }
961
- /**
962
- @internal
963
- */
964
- static fromJSON(schema, json) {
965
- if (typeof json.from != "number" || typeof json.to != "number")
966
- throw new RangeError("Invalid input for ReplaceStep.fromJSON");
967
- return new ReplaceStep(json.from, json.to, prosemirrorModel.Slice.fromJSON(schema, json.slice), !!json.structure);
968
- }
969
- }
970
- Step.jsonID("replace", ReplaceStep);
971
- /**
972
- Replace a part of the document with a slice of content, but
973
- preserve a range of the replaced content by moving it into the
974
- slice.
975
- */
976
- class ReplaceAroundStep extends Step {
977
- /**
978
- Create a replace-around step with the given range and gap.
979
- `insert` should be the point in the slice into which the content
980
- of the gap should be moved. `structure` has the same meaning as
981
- it has in the [`ReplaceStep`](https://prosemirror.net/docs/ref/#transform.ReplaceStep) class.
982
- */
983
- constructor(
984
- /**
985
- The start position of the replaced range.
986
- */
987
- from,
988
- /**
989
- The end position of the replaced range.
990
- */
991
- to,
992
- /**
993
- The start of preserved range.
994
- */
995
- gapFrom,
996
- /**
997
- The end of preserved range.
998
- */
999
- gapTo,
1000
- /**
1001
- The slice to insert.
1002
- */
1003
- slice,
1004
- /**
1005
- The position in the slice where the preserved range should be
1006
- inserted.
1007
- */
1008
- insert,
1009
- /**
1010
- @internal
1011
- */
1012
- structure = false) {
1013
- super();
1014
- this.from = from;
1015
- this.to = to;
1016
- this.gapFrom = gapFrom;
1017
- this.gapTo = gapTo;
1018
- this.slice = slice;
1019
- this.insert = insert;
1020
- this.structure = structure;
1021
- }
1022
- apply(doc) {
1023
- if (this.structure && (contentBetween(doc, this.from, this.gapFrom) ||
1024
- contentBetween(doc, this.gapTo, this.to)))
1025
- return StepResult.fail("Structure gap-replace would overwrite content");
1026
- let gap = doc.slice(this.gapFrom, this.gapTo);
1027
- if (gap.openStart || gap.openEnd)
1028
- return StepResult.fail("Gap is not a flat range");
1029
- let inserted = this.slice.insertAt(this.insert, gap.content);
1030
- if (!inserted)
1031
- return StepResult.fail("Content does not fit in gap");
1032
- return StepResult.fromReplace(doc, this.from, this.to, inserted);
1033
- }
1034
- getMap() {
1035
- return new StepMap([this.from, this.gapFrom - this.from, this.insert,
1036
- this.gapTo, this.to - this.gapTo, this.slice.size - this.insert]);
1037
- }
1038
- invert(doc) {
1039
- let gap = this.gapTo - this.gapFrom;
1040
- return new ReplaceAroundStep(this.from, this.from + this.slice.size + gap, this.from + this.insert, this.from + this.insert + gap, doc.slice(this.from, this.to).removeBetween(this.gapFrom - this.from, this.gapTo - this.from), this.gapFrom - this.from, this.structure);
1041
- }
1042
- map(mapping) {
1043
- let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
1044
- let gapFrom = mapping.map(this.gapFrom, -1), gapTo = mapping.map(this.gapTo, 1);
1045
- if ((from.deletedAcross && to.deletedAcross) || gapFrom < from.pos || gapTo > to.pos)
1046
- return null;
1047
- return new ReplaceAroundStep(from.pos, to.pos, gapFrom, gapTo, this.slice, this.insert, this.structure);
1048
- }
1049
- toJSON() {
1050
- let json = { stepType: "replaceAround", from: this.from, to: this.to,
1051
- gapFrom: this.gapFrom, gapTo: this.gapTo, insert: this.insert };
1052
- if (this.slice.size)
1053
- json.slice = this.slice.toJSON();
1054
- if (this.structure)
1055
- json.structure = true;
1056
- return json;
1057
- }
1058
- /**
1059
- @internal
1060
- */
1061
- static fromJSON(schema, json) {
1062
- if (typeof json.from != "number" || typeof json.to != "number" ||
1063
- typeof json.gapFrom != "number" || typeof json.gapTo != "number" || typeof json.insert != "number")
1064
- throw new RangeError("Invalid input for ReplaceAroundStep.fromJSON");
1065
- return new ReplaceAroundStep(json.from, json.to, json.gapFrom, json.gapTo, prosemirrorModel.Slice.fromJSON(schema, json.slice), json.insert, !!json.structure);
1066
- }
1067
- }
1068
- Step.jsonID("replaceAround", ReplaceAroundStep);
1069
- function contentBetween(doc, from, to) {
1070
- let $from = doc.resolve(from), dist = to - from, depth = $from.depth;
1071
- while (dist > 0 && depth > 0 && $from.indexAfter(depth) == $from.node(depth).childCount) {
1072
- depth--;
1073
- dist--;
1074
- }
1075
- if (dist > 0) {
1076
- let next = $from.node(depth).maybeChild($from.indexAfter(depth));
1077
- while (dist > 0) {
1078
- if (!next || next.isLeaf)
1079
- return true;
1080
- next = next.firstChild;
1081
- dist--;
1082
- }
1083
- }
1084
- return false;
1085
- }
1086
-
1087
- function addMark(tr, from, to, mark) {
1088
- let removed = [], added = [];
1089
- let removing, adding;
1090
- tr.doc.nodesBetween(from, to, (node, pos, parent) => {
1091
- if (!node.isInline)
1092
- return;
1093
- let marks = node.marks;
1094
- if (!mark.isInSet(marks) && parent.type.allowsMarkType(mark.type)) {
1095
- let start = Math.max(pos, from), end = Math.min(pos + node.nodeSize, to);
1096
- let newSet = mark.addToSet(marks);
1097
- for (let i = 0; i < marks.length; i++) {
1098
- if (!marks[i].isInSet(newSet)) {
1099
- if (removing && removing.to == start && removing.mark.eq(marks[i]))
1100
- removing.to = end;
1101
- else
1102
- removed.push(removing = new RemoveMarkStep(start, end, marks[i]));
1103
- }
1104
- }
1105
- if (adding && adding.to == start)
1106
- adding.to = end;
1107
- else
1108
- added.push(adding = new AddMarkStep(start, end, mark));
1109
- }
1110
- });
1111
- removed.forEach(s => tr.step(s));
1112
- added.forEach(s => tr.step(s));
1113
- }
1114
- function removeMark(tr, from, to, mark) {
1115
- let matched = [], step = 0;
1116
- tr.doc.nodesBetween(from, to, (node, pos) => {
1117
- if (!node.isInline)
1118
- return;
1119
- step++;
1120
- let toRemove = null;
1121
- if (mark instanceof prosemirrorModel.MarkType) {
1122
- let set = node.marks, found;
1123
- while (found = mark.isInSet(set)) {
1124
- (toRemove || (toRemove = [])).push(found);
1125
- set = found.removeFromSet(set);
1126
- }
1127
- }
1128
- else if (mark) {
1129
- if (mark.isInSet(node.marks))
1130
- toRemove = [mark];
1131
- }
1132
- else {
1133
- toRemove = node.marks;
1134
- }
1135
- if (toRemove && toRemove.length) {
1136
- let end = Math.min(pos + node.nodeSize, to);
1137
- for (let i = 0; i < toRemove.length; i++) {
1138
- let style = toRemove[i], found;
1139
- for (let j = 0; j < matched.length; j++) {
1140
- let m = matched[j];
1141
- if (m.step == step - 1 && style.eq(matched[j].style))
1142
- found = m;
1143
- }
1144
- if (found) {
1145
- found.to = end;
1146
- found.step = step;
1147
- }
1148
- else {
1149
- matched.push({ style, from: Math.max(pos, from), to: end, step });
1150
- }
1151
- }
1152
- }
1153
- });
1154
- matched.forEach(m => tr.step(new RemoveMarkStep(m.from, m.to, m.style)));
1155
- }
1156
- function clearIncompatible(tr, pos, parentType, match = parentType.contentMatch) {
1157
- let node = tr.doc.nodeAt(pos);
1158
- let delSteps = [], cur = pos + 1;
1159
- for (let i = 0; i < node.childCount; i++) {
1160
- let child = node.child(i), end = cur + child.nodeSize;
1161
- let allowed = match.matchType(child.type);
1162
- if (!allowed) {
1163
- delSteps.push(new ReplaceStep(cur, end, prosemirrorModel.Slice.empty));
1164
- }
1165
- else {
1166
- match = allowed;
1167
- for (let j = 0; j < child.marks.length; j++)
1168
- if (!parentType.allowsMarkType(child.marks[j].type))
1169
- tr.step(new RemoveMarkStep(cur, end, child.marks[j]));
1170
- }
1171
- cur = end;
1172
- }
1173
- if (!match.validEnd) {
1174
- let fill = match.fillBefore(prosemirrorModel.Fragment.empty, true);
1175
- tr.replace(cur, cur, new prosemirrorModel.Slice(fill, 0, 0));
1176
- }
1177
- for (let i = delSteps.length - 1; i >= 0; i--)
1178
- tr.step(delSteps[i]);
1179
- }
1180
- function lift(tr, range, target) {
1181
- let { $from, $to, depth } = range;
1182
- let gapStart = $from.before(depth + 1), gapEnd = $to.after(depth + 1);
1183
- let start = gapStart, end = gapEnd;
1184
- let before = prosemirrorModel.Fragment.empty, openStart = 0;
1185
- for (let d = depth, splitting = false; d > target; d--)
1186
- if (splitting || $from.index(d) > 0) {
1187
- splitting = true;
1188
- before = prosemirrorModel.Fragment.from($from.node(d).copy(before));
1189
- openStart++;
1190
- }
1191
- else {
1192
- start--;
1193
- }
1194
- let after = prosemirrorModel.Fragment.empty, openEnd = 0;
1195
- for (let d = depth, splitting = false; d > target; d--)
1196
- if (splitting || $to.after(d + 1) < $to.end(d)) {
1197
- splitting = true;
1198
- after = prosemirrorModel.Fragment.from($to.node(d).copy(after));
1199
- openEnd++;
1200
- }
1201
- else {
1202
- end++;
1203
- }
1204
- tr.step(new ReplaceAroundStep(start, end, gapStart, gapEnd, new prosemirrorModel.Slice(before.append(after), openStart, openEnd), before.size - openStart, true));
1205
- }
1206
- function wrap(tr, range, wrappers) {
1207
- let content = prosemirrorModel.Fragment.empty;
1208
- for (let i = wrappers.length - 1; i >= 0; i--) {
1209
- if (content.size) {
1210
- let match = wrappers[i].type.contentMatch.matchFragment(content);
1211
- if (!match || !match.validEnd)
1212
- throw new RangeError("Wrapper type given to Transform.wrap does not form valid content of its parent wrapper");
1213
- }
1214
- content = prosemirrorModel.Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content));
1215
- }
1216
- let start = range.start, end = range.end;
1217
- tr.step(new ReplaceAroundStep(start, end, start, end, new prosemirrorModel.Slice(content, 0, 0), wrappers.length, true));
1218
- }
1219
- function setBlockType(tr, from, to, type, attrs) {
1220
- if (!type.isTextblock)
1221
- throw new RangeError("Type given to setBlockType should be a textblock");
1222
- let mapFrom = tr.steps.length;
1223
- tr.doc.nodesBetween(from, to, (node, pos) => {
1224
- if (node.isTextblock && !node.hasMarkup(type, attrs) && canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
1225
- // Ensure all markup that isn't allowed in the new node type is cleared
1226
- tr.clearIncompatible(tr.mapping.slice(mapFrom).map(pos, 1), type);
1227
- let mapping = tr.mapping.slice(mapFrom);
1228
- let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1);
1229
- tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(type.create(attrs, null, node.marks)), 0, 0), 1, true));
1230
- return false;
1231
- }
1232
- });
1233
- }
1234
- function canChangeType(doc, pos, type) {
1235
- let $pos = doc.resolve(pos), index = $pos.index();
1236
- return $pos.parent.canReplaceWith(index, index + 1, type);
1237
- }
1238
- /**
1239
- Change the type, attributes, and/or marks of the node at `pos`.
1240
- When `type` isn't given, the existing node type is preserved,
1241
- */
1242
- function setNodeMarkup(tr, pos, type, attrs, marks) {
1243
- let node = tr.doc.nodeAt(pos);
1244
- if (!node)
1245
- throw new RangeError("No node at given position");
1246
- if (!type)
1247
- type = node.type;
1248
- let newNode = type.create(attrs, null, marks || node.marks);
1249
- if (node.isLeaf)
1250
- return tr.replaceWith(pos, pos + node.nodeSize, newNode);
1251
- if (!type.validContent(node.content))
1252
- throw new RangeError("Invalid content for node type " + type.name);
1253
- tr.step(new ReplaceAroundStep(pos, pos + node.nodeSize, pos + 1, pos + node.nodeSize - 1, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(newNode), 0, 0), 1, true));
1254
- }
1255
- function split(tr, pos, depth = 1, typesAfter) {
1256
- let $pos = tr.doc.resolve(pos), before = prosemirrorModel.Fragment.empty, after = prosemirrorModel.Fragment.empty;
1257
- for (let d = $pos.depth, e = $pos.depth - depth, i = depth - 1; d > e; d--, i--) {
1258
- before = prosemirrorModel.Fragment.from($pos.node(d).copy(before));
1259
- let typeAfter = typesAfter && typesAfter[i];
1260
- after = prosemirrorModel.Fragment.from(typeAfter ? typeAfter.type.create(typeAfter.attrs, after) : $pos.node(d).copy(after));
1261
- }
1262
- tr.step(new ReplaceStep(pos, pos, new prosemirrorModel.Slice(before.append(after), depth, depth), true));
1263
- }
1264
- function join(tr, pos, depth) {
1265
- let step = new ReplaceStep(pos - depth, pos + depth, prosemirrorModel.Slice.empty, true);
1266
- tr.step(step);
1267
- }
1268
- /**
1269
- Try to find a point where a node of the given type can be inserted
1270
- near `pos`, by searching up the node hierarchy when `pos` itself
1271
- isn't a valid place but is at the start or end of a node. Return
1272
- null if no position was found.
1273
- */
1274
- function insertPoint(doc, pos, nodeType) {
1275
- let $pos = doc.resolve(pos);
1276
- if ($pos.parent.canReplaceWith($pos.index(), $pos.index(), nodeType))
1277
- return pos;
1278
- if ($pos.parentOffset == 0)
1279
- for (let d = $pos.depth - 1; d >= 0; d--) {
1280
- let index = $pos.index(d);
1281
- if ($pos.node(d).canReplaceWith(index, index, nodeType))
1282
- return $pos.before(d + 1);
1283
- if (index > 0)
1284
- return null;
1285
- }
1286
- if ($pos.parentOffset == $pos.parent.content.size)
1287
- for (let d = $pos.depth - 1; d >= 0; d--) {
1288
- let index = $pos.indexAfter(d);
1289
- if ($pos.node(d).canReplaceWith(index, index, nodeType))
1290
- return $pos.after(d + 1);
1291
- if (index < $pos.node(d).childCount)
1292
- return null;
1293
- }
1294
- return null;
1295
- }
1296
-
1297
- /**
1298
- ‘Fit’ a slice into a given position in the document, producing a
1299
- [step](https://prosemirror.net/docs/ref/#transform.Step) that inserts it. Will return null if
1300
- there's no meaningful way to insert the slice here, or inserting it
1301
- would be a no-op (an empty slice over an empty range).
1302
- */
1303
- function replaceStep(doc, from, to = from, slice = prosemirrorModel.Slice.empty) {
1304
- if (from == to && !slice.size)
1305
- return null;
1306
- let $from = doc.resolve(from), $to = doc.resolve(to);
1307
- // Optimization -- avoid work if it's obvious that it's not needed.
1308
- if (fitsTrivially($from, $to, slice))
1309
- return new ReplaceStep(from, to, slice);
1310
- return new Fitter($from, $to, slice).fit();
1311
- }
1312
- function fitsTrivially($from, $to, slice) {
1313
- return !slice.openStart && !slice.openEnd && $from.start() == $to.start() &&
1314
- $from.parent.canReplace($from.index(), $to.index(), slice.content);
1315
- }
1316
- // Algorithm for 'placing' the elements of a slice into a gap:
1317
- //
1318
- // We consider the content of each node that is open to the left to be
1319
- // independently placeable. I.e. in <p("foo"), p("bar")>, when the
1320
- // paragraph on the left is open, "foo" can be placed (somewhere on
1321
- // the left side of the replacement gap) independently from p("bar").
1322
- //
1323
- // This class tracks the state of the placement progress in the
1324
- // following properties:
1325
- //
1326
- // - `frontier` holds a stack of `{type, match}` objects that
1327
- // represent the open side of the replacement. It starts at
1328
- // `$from`, then moves forward as content is placed, and is finally
1329
- // reconciled with `$to`.
1330
- //
1331
- // - `unplaced` is a slice that represents the content that hasn't
1332
- // been placed yet.
1333
- //
1334
- // - `placed` is a fragment of placed content. Its open-start value
1335
- // is implicit in `$from`, and its open-end value in `frontier`.
1336
- class Fitter {
1337
- constructor($from, $to, unplaced) {
1338
- this.$from = $from;
1339
- this.$to = $to;
1340
- this.unplaced = unplaced;
1341
- this.frontier = [];
1342
- this.placed = prosemirrorModel.Fragment.empty;
1343
- for (let i = 0; i <= $from.depth; i++) {
1344
- let node = $from.node(i);
1345
- this.frontier.push({
1346
- type: node.type,
1347
- match: node.contentMatchAt($from.indexAfter(i))
1348
- });
1349
- }
1350
- for (let i = $from.depth; i > 0; i--)
1351
- this.placed = prosemirrorModel.Fragment.from($from.node(i).copy(this.placed));
1352
- }
1353
- get depth() { return this.frontier.length - 1; }
1354
- fit() {
1355
- // As long as there's unplaced content, try to place some of it.
1356
- // If that fails, either increase the open score of the unplaced
1357
- // slice, or drop nodes from it, and then try again.
1358
- while (this.unplaced.size) {
1359
- let fit = this.findFittable();
1360
- if (fit)
1361
- this.placeNodes(fit);
1362
- else
1363
- this.openMore() || this.dropNode();
1364
- }
1365
- // When there's inline content directly after the frontier _and_
1366
- // directly after `this.$to`, we must generate a `ReplaceAround`
1367
- // step that pulls that content into the node after the frontier.
1368
- // That means the fitting must be done to the end of the textblock
1369
- // node after `this.$to`, not `this.$to` itself.
1370
- let moveInline = this.mustMoveInline(), placedSize = this.placed.size - this.depth - this.$from.depth;
1371
- let $from = this.$from, $to = this.close(moveInline < 0 ? this.$to : $from.doc.resolve(moveInline));
1372
- if (!$to)
1373
- return null;
1374
- // If closing to `$to` succeeded, create a step
1375
- let content = this.placed, openStart = $from.depth, openEnd = $to.depth;
1376
- while (openStart && openEnd && content.childCount == 1) { // Normalize by dropping open parent nodes
1377
- content = content.firstChild.content;
1378
- openStart--;
1379
- openEnd--;
1380
- }
1381
- let slice = new prosemirrorModel.Slice(content, openStart, openEnd);
1382
- if (moveInline > -1)
1383
- return new ReplaceAroundStep($from.pos, moveInline, this.$to.pos, this.$to.end(), slice, placedSize);
1384
- if (slice.size || $from.pos != this.$to.pos) // Don't generate no-op steps
1385
- return new ReplaceStep($from.pos, $to.pos, slice);
1386
- return null;
1387
- }
1388
- // Find a position on the start spine of `this.unplaced` that has
1389
- // content that can be moved somewhere on the frontier. Returns two
1390
- // depths, one for the slice and one for the frontier.
1391
- findFittable() {
1392
- // Only try wrapping nodes (pass 2) after finding a place without
1393
- // wrapping failed.
1394
- for (let pass = 1; pass <= 2; pass++) {
1395
- for (let sliceDepth = this.unplaced.openStart; sliceDepth >= 0; sliceDepth--) {
1396
- let fragment, parent = null;
1397
- if (sliceDepth) {
1398
- parent = contentAt(this.unplaced.content, sliceDepth - 1).firstChild;
1399
- fragment = parent.content;
1400
- }
1401
- else {
1402
- fragment = this.unplaced.content;
1403
- }
1404
- let first = fragment.firstChild;
1405
- for (let frontierDepth = this.depth; frontierDepth >= 0; frontierDepth--) {
1406
- let { type, match } = this.frontier[frontierDepth], wrap, inject = null;
1407
- // In pass 1, if the next node matches, or there is no next
1408
- // node but the parents look compatible, we've found a
1409
- // place.
1410
- if (pass == 1 && (first ? match.matchType(first.type) || (inject = match.fillBefore(prosemirrorModel.Fragment.from(first), false))
1411
- : parent && type.compatibleContent(parent.type)))
1412
- return { sliceDepth, frontierDepth, parent, inject };
1413
- // In pass 2, look for a set of wrapping nodes that make
1414
- // `first` fit here.
1415
- else if (pass == 2 && first && (wrap = match.findWrapping(first.type)))
1416
- return { sliceDepth, frontierDepth, parent, wrap };
1417
- // Don't continue looking further up if the parent node
1418
- // would fit here.
1419
- if (parent && match.matchType(parent.type))
1420
- break;
1421
- }
1422
- }
1423
- }
1424
- }
1425
- openMore() {
1426
- let { content, openStart, openEnd } = this.unplaced;
1427
- let inner = contentAt(content, openStart);
1428
- if (!inner.childCount || inner.firstChild.isLeaf)
1429
- return false;
1430
- this.unplaced = new prosemirrorModel.Slice(content, openStart + 1, Math.max(openEnd, inner.size + openStart >= content.size - openEnd ? openStart + 1 : 0));
1431
- return true;
1432
- }
1433
- dropNode() {
1434
- let { content, openStart, openEnd } = this.unplaced;
1435
- let inner = contentAt(content, openStart);
1436
- if (inner.childCount <= 1 && openStart > 0) {
1437
- let openAtEnd = content.size - openStart <= openStart + inner.size;
1438
- this.unplaced = new prosemirrorModel.Slice(dropFromFragment(content, openStart - 1, 1), openStart - 1, openAtEnd ? openStart - 1 : openEnd);
1439
- }
1440
- else {
1441
- this.unplaced = new prosemirrorModel.Slice(dropFromFragment(content, openStart, 1), openStart, openEnd);
1442
- }
1443
- }
1444
- // Move content from the unplaced slice at `sliceDepth` to the
1445
- // frontier node at `frontierDepth`. Close that frontier node when
1446
- // applicable.
1447
- placeNodes({ sliceDepth, frontierDepth, parent, inject, wrap }) {
1448
- while (this.depth > frontierDepth)
1449
- this.closeFrontierNode();
1450
- if (wrap)
1451
- for (let i = 0; i < wrap.length; i++)
1452
- this.openFrontierNode(wrap[i]);
1453
- let slice = this.unplaced, fragment = parent ? parent.content : slice.content;
1454
- let openStart = slice.openStart - sliceDepth;
1455
- let taken = 0, add = [];
1456
- let { match, type } = this.frontier[frontierDepth];
1457
- if (inject) {
1458
- for (let i = 0; i < inject.childCount; i++)
1459
- add.push(inject.child(i));
1460
- match = match.matchFragment(inject);
1461
- }
1462
- // Computes the amount of (end) open nodes at the end of the
1463
- // fragment. When 0, the parent is open, but no more. When
1464
- // negative, nothing is open.
1465
- let openEndCount = (fragment.size + sliceDepth) - (slice.content.size - slice.openEnd);
1466
- // Scan over the fragment, fitting as many child nodes as
1467
- // possible.
1468
- while (taken < fragment.childCount) {
1469
- let next = fragment.child(taken), matches = match.matchType(next.type);
1470
- if (!matches)
1471
- break;
1472
- taken++;
1473
- if (taken > 1 || openStart == 0 || next.content.size) { // Drop empty open nodes
1474
- match = matches;
1475
- add.push(closeNodeStart(next.mark(type.allowedMarks(next.marks)), taken == 1 ? openStart : 0, taken == fragment.childCount ? openEndCount : -1));
1476
- }
1477
- }
1478
- let toEnd = taken == fragment.childCount;
1479
- if (!toEnd)
1480
- openEndCount = -1;
1481
- this.placed = addToFragment(this.placed, frontierDepth, prosemirrorModel.Fragment.from(add));
1482
- this.frontier[frontierDepth].match = match;
1483
- // If the parent types match, and the entire node was moved, and
1484
- // it's not open, close this frontier node right away.
1485
- if (toEnd && openEndCount < 0 && parent && parent.type == this.frontier[this.depth].type && this.frontier.length > 1)
1486
- this.closeFrontierNode();
1487
- // Add new frontier nodes for any open nodes at the end.
1488
- for (let i = 0, cur = fragment; i < openEndCount; i++) {
1489
- let node = cur.lastChild;
1490
- this.frontier.push({ type: node.type, match: node.contentMatchAt(node.childCount) });
1491
- cur = node.content;
1492
- }
1493
- // Update `this.unplaced`. Drop the entire node from which we
1494
- // placed it we got to its end, otherwise just drop the placed
1495
- // nodes.
1496
- this.unplaced = !toEnd ? new prosemirrorModel.Slice(dropFromFragment(slice.content, sliceDepth, taken), slice.openStart, slice.openEnd)
1497
- : sliceDepth == 0 ? prosemirrorModel.Slice.empty
1498
- : new prosemirrorModel.Slice(dropFromFragment(slice.content, sliceDepth - 1, 1), sliceDepth - 1, openEndCount < 0 ? slice.openEnd : sliceDepth - 1);
1499
- }
1500
- mustMoveInline() {
1501
- if (!this.$to.parent.isTextblock)
1502
- return -1;
1503
- let top = this.frontier[this.depth], level;
1504
- if (!top.type.isTextblock || !contentAfterFits(this.$to, this.$to.depth, top.type, top.match, false) ||
1505
- (this.$to.depth == this.depth && (level = this.findCloseLevel(this.$to)) && level.depth == this.depth))
1506
- return -1;
1507
- let { depth } = this.$to, after = this.$to.after(depth);
1508
- while (depth > 1 && after == this.$to.end(--depth))
1509
- ++after;
1510
- return after;
1511
- }
1512
- findCloseLevel($to) {
1513
- scan: for (let i = Math.min(this.depth, $to.depth); i >= 0; i--) {
1514
- let { match, type } = this.frontier[i];
1515
- let dropInner = i < $to.depth && $to.end(i + 1) == $to.pos + ($to.depth - (i + 1));
1516
- let fit = contentAfterFits($to, i, type, match, dropInner);
1517
- if (!fit)
1518
- continue;
1519
- for (let d = i - 1; d >= 0; d--) {
1520
- let { match, type } = this.frontier[d];
1521
- let matches = contentAfterFits($to, d, type, match, true);
1522
- if (!matches || matches.childCount)
1523
- continue scan;
1524
- }
1525
- return { depth: i, fit, move: dropInner ? $to.doc.resolve($to.after(i + 1)) : $to };
1526
- }
1527
- }
1528
- close($to) {
1529
- let close = this.findCloseLevel($to);
1530
- if (!close)
1531
- return null;
1532
- while (this.depth > close.depth)
1533
- this.closeFrontierNode();
1534
- if (close.fit.childCount)
1535
- this.placed = addToFragment(this.placed, close.depth, close.fit);
1536
- $to = close.move;
1537
- for (let d = close.depth + 1; d <= $to.depth; d++) {
1538
- let node = $to.node(d), add = node.type.contentMatch.fillBefore(node.content, true, $to.index(d));
1539
- this.openFrontierNode(node.type, node.attrs, add);
1540
- }
1541
- return $to;
1542
- }
1543
- openFrontierNode(type, attrs = null, content) {
1544
- let top = this.frontier[this.depth];
1545
- top.match = top.match.matchType(type);
1546
- this.placed = addToFragment(this.placed, this.depth, prosemirrorModel.Fragment.from(type.create(attrs, content)));
1547
- this.frontier.push({ type, match: type.contentMatch });
1548
- }
1549
- closeFrontierNode() {
1550
- let open = this.frontier.pop();
1551
- let add = open.match.fillBefore(prosemirrorModel.Fragment.empty, true);
1552
- if (add.childCount)
1553
- this.placed = addToFragment(this.placed, this.frontier.length, add);
1554
- }
1555
- }
1556
- function dropFromFragment(fragment, depth, count) {
1557
- if (depth == 0)
1558
- return fragment.cutByIndex(count, fragment.childCount);
1559
- return fragment.replaceChild(0, fragment.firstChild.copy(dropFromFragment(fragment.firstChild.content, depth - 1, count)));
1560
- }
1561
- function addToFragment(fragment, depth, content) {
1562
- if (depth == 0)
1563
- return fragment.append(content);
1564
- return fragment.replaceChild(fragment.childCount - 1, fragment.lastChild.copy(addToFragment(fragment.lastChild.content, depth - 1, content)));
1565
- }
1566
- function contentAt(fragment, depth) {
1567
- for (let i = 0; i < depth; i++)
1568
- fragment = fragment.firstChild.content;
1569
- return fragment;
1570
- }
1571
- function closeNodeStart(node, openStart, openEnd) {
1572
- if (openStart <= 0)
1573
- return node;
1574
- let frag = node.content;
1575
- if (openStart > 1)
1576
- frag = frag.replaceChild(0, closeNodeStart(frag.firstChild, openStart - 1, frag.childCount == 1 ? openEnd - 1 : 0));
1577
- if (openStart > 0) {
1578
- frag = node.type.contentMatch.fillBefore(frag).append(frag);
1579
- if (openEnd <= 0)
1580
- frag = frag.append(node.type.contentMatch.matchFragment(frag).fillBefore(prosemirrorModel.Fragment.empty, true));
1581
- }
1582
- return node.copy(frag);
1583
- }
1584
- function contentAfterFits($to, depth, type, match, open) {
1585
- let node = $to.node(depth), index = open ? $to.indexAfter(depth) : $to.index(depth);
1586
- if (index == node.childCount && !type.compatibleContent(node.type))
1587
- return null;
1588
- let fit = match.fillBefore(node.content, true, index);
1589
- return fit && !invalidMarks(type, node.content, index) ? fit : null;
1590
- }
1591
- function invalidMarks(type, fragment, start) {
1592
- for (let i = start; i < fragment.childCount; i++)
1593
- if (!type.allowsMarks(fragment.child(i).marks))
1594
- return true;
1595
- return false;
1596
- }
1597
- function definesContent(type) {
1598
- return type.spec.defining || type.spec.definingForContent;
1599
- }
1600
- function replaceRange(tr, from, to, slice) {
1601
- if (!slice.size)
1602
- return tr.deleteRange(from, to);
1603
- let $from = tr.doc.resolve(from), $to = tr.doc.resolve(to);
1604
- if (fitsTrivially($from, $to, slice))
1605
- return tr.step(new ReplaceStep(from, to, slice));
1606
- let targetDepths = coveredDepths($from, tr.doc.resolve(to));
1607
- // Can't replace the whole document, so remove 0 if it's present
1608
- if (targetDepths[targetDepths.length - 1] == 0)
1609
- targetDepths.pop();
1610
- // Negative numbers represent not expansion over the whole node at
1611
- // that depth, but replacing from $from.before(-D) to $to.pos.
1612
- let preferredTarget = -($from.depth + 1);
1613
- targetDepths.unshift(preferredTarget);
1614
- // This loop picks a preferred target depth, if one of the covering
1615
- // depths is not outside of a defining node, and adds negative
1616
- // depths for any depth that has $from at its start and does not
1617
- // cross a defining node.
1618
- for (let d = $from.depth, pos = $from.pos - 1; d > 0; d--, pos--) {
1619
- let spec = $from.node(d).type.spec;
1620
- if (spec.defining || spec.definingAsContext || spec.isolating)
1621
- break;
1622
- if (targetDepths.indexOf(d) > -1)
1623
- preferredTarget = d;
1624
- else if ($from.before(d) == pos)
1625
- targetDepths.splice(1, 0, -d);
1626
- }
1627
- // Try to fit each possible depth of the slice into each possible
1628
- // target depth, starting with the preferred depths.
1629
- let preferredTargetIndex = targetDepths.indexOf(preferredTarget);
1630
- let leftNodes = [], preferredDepth = slice.openStart;
1631
- for (let content = slice.content, i = 0;; i++) {
1632
- let node = content.firstChild;
1633
- leftNodes.push(node);
1634
- if (i == slice.openStart)
1635
- break;
1636
- content = node.content;
1637
- }
1638
- // Back up preferredDepth to cover defining textblocks directly
1639
- // above it, possibly skipping a non-defining textblock.
1640
- for (let d = preferredDepth - 1; d >= 0; d--) {
1641
- let type = leftNodes[d].type, def = definesContent(type);
1642
- if (def && $from.node(preferredTargetIndex).type != type)
1643
- preferredDepth = d;
1644
- else if (def || !type.isTextblock)
1645
- break;
1646
- }
1647
- for (let j = slice.openStart; j >= 0; j--) {
1648
- let openDepth = (j + preferredDepth + 1) % (slice.openStart + 1);
1649
- let insert = leftNodes[openDepth];
1650
- if (!insert)
1651
- continue;
1652
- for (let i = 0; i < targetDepths.length; i++) {
1653
- // Loop over possible expansion levels, starting with the
1654
- // preferred one
1655
- let targetDepth = targetDepths[(i + preferredTargetIndex) % targetDepths.length], expand = true;
1656
- if (targetDepth < 0) {
1657
- expand = false;
1658
- targetDepth = -targetDepth;
1659
- }
1660
- let parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1);
1661
- if (parent.canReplaceWith(index, index, insert.type, insert.marks))
1662
- return tr.replace($from.before(targetDepth), expand ? $to.after(targetDepth) : to, new prosemirrorModel.Slice(closeFragment(slice.content, 0, slice.openStart, openDepth), openDepth, slice.openEnd));
1663
- }
1664
- }
1665
- let startSteps = tr.steps.length;
1666
- for (let i = targetDepths.length - 1; i >= 0; i--) {
1667
- tr.replace(from, to, slice);
1668
- if (tr.steps.length > startSteps)
1669
- break;
1670
- let depth = targetDepths[i];
1671
- if (depth < 0)
1672
- continue;
1673
- from = $from.before(depth);
1674
- to = $to.after(depth);
1675
- }
1676
- }
1677
- function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
1678
- if (depth < oldOpen) {
1679
- let first = fragment.firstChild;
1680
- fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)));
1681
- }
1682
- if (depth > newOpen) {
1683
- let match = parent.contentMatchAt(0);
1684
- let start = match.fillBefore(fragment).append(fragment);
1685
- fragment = start.append(match.matchFragment(start).fillBefore(prosemirrorModel.Fragment.empty, true));
1686
- }
1687
- return fragment;
1688
- }
1689
- function replaceRangeWith(tr, from, to, node) {
1690
- if (!node.isInline && from == to && tr.doc.resolve(from).parent.content.size) {
1691
- let point = insertPoint(tr.doc, from, node.type);
1692
- if (point != null)
1693
- from = to = point;
1694
- }
1695
- tr.replaceRange(from, to, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(node), 0, 0));
1696
- }
1697
- function deleteRange(tr, from, to) {
1698
- let $from = tr.doc.resolve(from), $to = tr.doc.resolve(to);
1699
- let covered = coveredDepths($from, $to);
1700
- for (let i = 0; i < covered.length; i++) {
1701
- let depth = covered[i], last = i == covered.length - 1;
1702
- if ((last && depth == 0) || $from.node(depth).type.contentMatch.validEnd)
1703
- return tr.delete($from.start(depth), $to.end(depth));
1704
- if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1))))
1705
- return tr.delete($from.before(depth), $to.after(depth));
1706
- }
1707
- for (let d = 1; d <= $from.depth && d <= $to.depth; d++) {
1708
- if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d)
1709
- return tr.delete($from.before(d), to);
1710
- }
1711
- tr.delete(from, to);
1712
- }
1713
- // Returns an array of all depths for which $from - $to spans the
1714
- // whole content of the nodes at that depth.
1715
- function coveredDepths($from, $to) {
1716
- let result = [], minDepth = Math.min($from.depth, $to.depth);
1717
- for (let d = minDepth; d >= 0; d--) {
1718
- let start = $from.start(d);
1719
- if (start < $from.pos - ($from.depth - d) ||
1720
- $to.end(d) > $to.pos + ($to.depth - d) ||
1721
- $from.node(d).type.spec.isolating ||
1722
- $to.node(d).type.spec.isolating)
1723
- break;
1724
- if (start == $to.start(d) ||
1725
- (d == $from.depth && d == $to.depth && $from.parent.inlineContent && $to.parent.inlineContent &&
1726
- d && $to.start(d - 1) == start - 1))
1727
- result.push(d);
1728
- }
1729
- return result;
1730
- }
1731
-
1732
- /**
1733
- Update an attribute in a specific node.
1734
- */
1735
- class AttrStep extends Step {
1736
- /**
1737
- Construct an attribute step.
1738
- */
1739
- constructor(
1740
- /**
1741
- The position of the target node.
1742
- */
1743
- pos,
1744
- /**
1745
- The attribute to set.
1746
- */
1747
- attr,
1748
- // The attribute's new value.
1749
- value) {
1750
- super();
1751
- this.pos = pos;
1752
- this.attr = attr;
1753
- this.value = value;
1754
- }
1755
- apply(doc) {
1756
- let node = doc.nodeAt(this.pos);
1757
- if (!node)
1758
- return StepResult.fail("No node at attribute step's position");
1759
- let attrs = Object.create(null);
1760
- for (let name in node.attrs)
1761
- attrs[name] = node.attrs[name];
1762
- attrs[this.attr] = this.value;
1763
- let updated = node.type.create(attrs, null, node.marks);
1764
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
1765
- }
1766
- getMap() {
1767
- return StepMap.empty;
1768
- }
1769
- invert(doc) {
1770
- return new AttrStep(this.pos, this.attr, doc.nodeAt(this.pos).attrs[this.attr]);
1771
- }
1772
- map(mapping) {
1773
- let pos = mapping.mapResult(this.pos, 1);
1774
- return pos.deletedAfter ? null : new AttrStep(pos.pos, this.attr, this.value);
1775
- }
1776
- toJSON() {
1777
- return { stepType: "attr", pos: this.pos, attr: this.attr, value: this.value };
1778
- }
1779
- static fromJSON(schema, json) {
1780
- if (typeof json.pos != "number" || typeof json.attr != "string")
1781
- throw new RangeError("Invalid input for AttrStep.fromJSON");
1782
- return new AttrStep(json.pos, json.attr, json.value);
1783
- }
1784
- }
1785
- Step.jsonID("attr", AttrStep);
1786
-
1787
- /**
1788
- @internal
1789
- */
1790
- let TransformError = class extends Error {
1791
- };
1792
- TransformError = function TransformError(message) {
1793
- let err = Error.call(this, message);
1794
- err.__proto__ = TransformError.prototype;
1795
- return err;
1796
- };
1797
- TransformError.prototype = Object.create(Error.prototype);
1798
- TransformError.prototype.constructor = TransformError;
1799
- TransformError.prototype.name = "TransformError";
1800
- /**
1801
- Abstraction to build up and track an array of
1802
- [steps](https://prosemirror.net/docs/ref/#transform.Step) representing a document transformation.
1803
-
1804
- Most transforming methods return the `Transform` object itself, so
1805
- that they can be chained.
1806
- */
1807
- class Transform {
1808
- /**
1809
- Create a transform that starts with the given document.
1810
- */
1811
- constructor(
1812
- /**
1813
- The current document (the result of applying the steps in the
1814
- transform).
1815
- */
1816
- doc) {
1817
- this.doc = doc;
1818
- /**
1819
- The steps in this transform.
1820
- */
1821
- this.steps = [];
1822
- /**
1823
- The documents before each of the steps.
1824
- */
1825
- this.docs = [];
1826
- /**
1827
- A mapping with the maps for each of the steps in this transform.
1828
- */
1829
- this.mapping = new Mapping;
1830
- }
1831
- /**
1832
- The starting document.
1833
- */
1834
- get before() { return this.docs.length ? this.docs[0] : this.doc; }
1835
- /**
1836
- Apply a new step in this transform, saving the result. Throws an
1837
- error when the step fails.
1838
- */
1839
- step(step) {
1840
- let result = this.maybeStep(step);
1841
- if (result.failed)
1842
- throw new TransformError(result.failed);
1843
- return this;
1844
- }
1845
- /**
1846
- Try to apply a step in this transformation, ignoring it if it
1847
- fails. Returns the step result.
1848
- */
1849
- maybeStep(step) {
1850
- let result = step.apply(this.doc);
1851
- if (!result.failed)
1852
- this.addStep(step, result.doc);
1853
- return result;
1854
- }
1855
- /**
1856
- True when the document has been changed (when there are any
1857
- steps).
1858
- */
1859
- get docChanged() {
1860
- return this.steps.length > 0;
1861
- }
1862
- /**
1863
- @internal
1864
- */
1865
- addStep(step, doc) {
1866
- this.docs.push(this.doc);
1867
- this.steps.push(step);
1868
- this.mapping.appendMap(step.getMap());
1869
- this.doc = doc;
1870
- }
1871
- /**
1872
- Replace the part of the document between `from` and `to` with the
1873
- given `slice`.
1874
- */
1875
- replace(from, to = from, slice = prosemirrorModel.Slice.empty) {
1876
- let step = replaceStep(this.doc, from, to, slice);
1877
- if (step)
1878
- this.step(step);
1879
- return this;
1880
- }
1881
- /**
1882
- Replace the given range with the given content, which may be a
1883
- fragment, node, or array of nodes.
1884
- */
1885
- replaceWith(from, to, content) {
1886
- return this.replace(from, to, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(content), 0, 0));
1887
- }
1888
- /**
1889
- Delete the content between the given positions.
1890
- */
1891
- delete(from, to) {
1892
- return this.replace(from, to, prosemirrorModel.Slice.empty);
1893
- }
1894
- /**
1895
- Insert the given content at the given position.
1896
- */
1897
- insert(pos, content) {
1898
- return this.replaceWith(pos, pos, content);
1899
- }
1900
- /**
1901
- Replace a range of the document with a given slice, using
1902
- `from`, `to`, and the slice's
1903
- [`openStart`](https://prosemirror.net/docs/ref/#model.Slice.openStart) property as hints, rather
1904
- than fixed start and end points. This method may grow the
1905
- replaced area or close open nodes in the slice in order to get a
1906
- fit that is more in line with WYSIWYG expectations, by dropping
1907
- fully covered parent nodes of the replaced region when they are
1908
- marked [non-defining as
1909
- context](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext), or including an
1910
- open parent node from the slice that _is_ marked as [defining
1911
- its content](https://prosemirror.net/docs/ref/#model.NodeSpec.definingForContent).
1912
-
1913
- This is the method, for example, to handle paste. The similar
1914
- [`replace`](https://prosemirror.net/docs/ref/#transform.Transform.replace) method is a more
1915
- primitive tool which will _not_ move the start and end of its given
1916
- range, and is useful in situations where you need more precise
1917
- control over what happens.
1918
- */
1919
- replaceRange(from, to, slice) {
1920
- replaceRange(this, from, to, slice);
1921
- return this;
1922
- }
1923
- /**
1924
- Replace the given range with a node, but use `from` and `to` as
1925
- hints, rather than precise positions. When from and to are the same
1926
- and are at the start or end of a parent node in which the given
1927
- node doesn't fit, this method may _move_ them out towards a parent
1928
- that does allow the given node to be placed. When the given range
1929
- completely covers a parent node, this method may completely replace
1930
- that parent node.
1931
- */
1932
- replaceRangeWith(from, to, node) {
1933
- replaceRangeWith(this, from, to, node);
1934
- return this;
1935
- }
1936
- /**
1937
- Delete the given range, expanding it to cover fully covered
1938
- parent nodes until a valid replace is found.
1939
- */
1940
- deleteRange(from, to) {
1941
- deleteRange(this, from, to);
1942
- return this;
1943
- }
1944
- /**
1945
- Split the content in the given range off from its parent, if there
1946
- is sibling content before or after it, and move it up the tree to
1947
- the depth specified by `target`. You'll probably want to use
1948
- [`liftTarget`](https://prosemirror.net/docs/ref/#transform.liftTarget) to compute `target`, to make
1949
- sure the lift is valid.
1950
- */
1951
- lift(range, target) {
1952
- lift(this, range, target);
1953
- return this;
1954
- }
1955
- /**
1956
- Join the blocks around the given position. If depth is 2, their
1957
- last and first siblings are also joined, and so on.
1958
- */
1959
- join(pos, depth = 1) {
1960
- join(this, pos, depth);
1961
- return this;
1962
- }
1963
- /**
1964
- Wrap the given [range](https://prosemirror.net/docs/ref/#model.NodeRange) in the given set of wrappers.
1965
- The wrappers are assumed to be valid in this position, and should
1966
- probably be computed with [`findWrapping`](https://prosemirror.net/docs/ref/#transform.findWrapping).
1967
- */
1968
- wrap(range, wrappers) {
1969
- wrap(this, range, wrappers);
1970
- return this;
1971
- }
1972
- /**
1973
- Set the type of all textblocks (partly) between `from` and `to` to
1974
- the given node type with the given attributes.
1975
- */
1976
- setBlockType(from, to = from, type, attrs = null) {
1977
- setBlockType(this, from, to, type, attrs);
1978
- return this;
1979
- }
1980
- /**
1981
- Change the type, attributes, and/or marks of the node at `pos`.
1982
- When `type` isn't given, the existing node type is preserved,
1983
- */
1984
- setNodeMarkup(pos, type, attrs = null, marks = []) {
1985
- setNodeMarkup(this, pos, type, attrs, marks);
1986
- return this;
1987
- }
1988
- /**
1989
- Set a single attribute on a given node to a new value.
1990
- */
1991
- setNodeAttribute(pos, attr, value) {
1992
- this.step(new AttrStep(pos, attr, value));
1993
- return this;
1994
- }
1995
- /**
1996
- Add a mark to the node at position `pos`.
1997
- */
1998
- addNodeMark(pos, mark) {
1999
- this.step(new AddNodeMarkStep(pos, mark));
2000
- return this;
2001
- }
2002
- /**
2003
- Remove a mark (or a mark of the given type) from the node at
2004
- position `pos`.
2005
- */
2006
- removeNodeMark(pos, mark) {
2007
- if (!(mark instanceof prosemirrorModel.Mark)) {
2008
- let node = this.doc.nodeAt(pos);
2009
- if (!node)
2010
- throw new RangeError("No node at position " + pos);
2011
- mark = mark.isInSet(node.marks);
2012
- if (!mark)
2013
- return this;
2014
- }
2015
- this.step(new RemoveNodeMarkStep(pos, mark));
2016
- return this;
2017
- }
2018
- /**
2019
- Split the node at the given position, and optionally, if `depth` is
2020
- greater than one, any number of nodes above that. By default, the
2021
- parts split off will inherit the node type of the original node.
2022
- This can be changed by passing an array of types and attributes to
2023
- use after the split.
2024
- */
2025
- split(pos, depth = 1, typesAfter) {
2026
- split(this, pos, depth, typesAfter);
2027
- return this;
2028
- }
2029
- /**
2030
- Add the given mark to the inline content between `from` and `to`.
2031
- */
2032
- addMark(from, to, mark) {
2033
- addMark(this, from, to, mark);
2034
- return this;
2035
- }
2036
- /**
2037
- Remove marks from inline nodes between `from` and `to`. When
2038
- `mark` is a single mark, remove precisely that mark. When it is
2039
- a mark type, remove all marks of that type. When it is null,
2040
- remove all marks of any type.
2041
- */
2042
- removeMark(from, to, mark) {
2043
- removeMark(this, from, to, mark);
2044
- return this;
2045
- }
2046
- /**
2047
- Removes all marks and nodes from the content of the node at
2048
- `pos` that don't match the given new parent node type. Accepts
2049
- an optional starting [content match](https://prosemirror.net/docs/ref/#model.ContentMatch) as
2050
- third argument.
2051
- */
2052
- clearIncompatible(pos, parentType, match) {
2053
- clearIncompatible(this, pos, parentType, match);
2054
- return this;
2055
- }
2056
- }
2057
-
2058
- // Because working with row and column-spanning cells is not quite
2059
- // trivial, this code builds up a descriptive structure for a given
2060
- // table node. The structures are cached with the (persistent) table
2061
- // nodes as key, so that they only have to be recomputed when the
2062
- // content of the table changes.
2063
- //
2064
- // This does mean that they have to store table-relative, not
2065
- // document-relative positions. So code that uses them will typically
2066
- // compute the start position of the table and offset positions passed
2067
- // to or gotten from this structure by that amount.
2068
- let readFromCache, addToCache; // Prefer using a weak map to cache table maps. Fall back on a
2069
- // fixed-size cache if that's not supported.
2070
-
2071
- if (typeof WeakMap != 'undefined') {
2072
- // eslint-disable-next-line
2073
- let cache = new WeakMap();
2074
-
2075
- readFromCache = key => cache.get(key);
2076
-
2077
- addToCache = (key, value) => {
2078
- cache.set(key, value);
2079
- return value;
2080
- };
2081
- } else {
2082
- let cache = [],
2083
- cacheSize = 10,
2084
- cachePos = 0;
2085
-
2086
- readFromCache = key => {
2087
- for (let i = 0; i < cache.length; i += 2) if (cache[i] == key) return cache[i + 1];
2088
- };
2089
-
2090
- addToCache = (key, value) => {
2091
- if (cachePos == cacheSize) cachePos = 0;
2092
- cache[cachePos++] = key;
2093
- return cache[cachePos++] = value;
2094
- };
2095
- }
2096
-
2097
- class Rect {
2098
- constructor(left, top, right, bottom) {
2099
- this.left = left;
2100
- this.top = top;
2101
- this.right = right;
2102
- this.bottom = bottom;
2103
- }
2104
-
2105
- } // ::- A table map describes the structore of a given table. To avoid
2106
- // recomputing them all the time, they are cached per table node. To
2107
- // be able to do that, positions saved in the map are relative to the
2108
- // start of the table, rather than the start of the document.
2109
-
2110
- class TableMap {
2111
- constructor(width, height, map, problems) {
2112
- // :: number The width of the table
2113
- this.width = width; // :: number The table's height
2114
-
2115
- this.height = height; // :: [number] A width * height array with the start position of
2116
- // the cell covering that part of the table in each slot
2117
-
2118
- this.map = map; // An optional array of problems (cell overlap or non-rectangular
2119
- // shape) for the table, used by the table normalizer.
2120
-
2121
- this.problems = problems;
2122
- } // :: (number) → Rect
2123
- // Find the dimensions of the cell at the given position.
2124
-
2125
-
2126
- findCell(pos) {
2127
- for (let i = 0; i < this.map.length; i++) {
2128
- let curPos = this.map[i];
2129
- if (curPos != pos) continue;
2130
- let left = i % this.width,
2131
- top = i / this.width | 0;
2132
- let right = left + 1,
2133
- bottom = top + 1;
2134
-
2135
- for (let j = 1; right < this.width && this.map[i + j] == curPos; j++) right++;
2136
-
2137
- for (let j = 1; bottom < this.height && this.map[i + this.width * j] == curPos; j++) bottom++;
2138
-
2139
- return new Rect(left, top, right, bottom);
2140
- }
2141
-
2142
- throw new RangeError('No cell with offset ' + pos + ' found');
2143
- } // :: (number) → number
2144
- // Find the left side of the cell at the given position.
2145
-
2146
-
2147
- colCount(pos) {
2148
- for (let i = 0; i < this.map.length; i++) if (this.map[i] == pos) return i % this.width;
2149
-
2150
- throw new RangeError('No cell with offset ' + pos + ' found');
2151
- } // :: (number, string, number) → ?number
2152
- // Find the next cell in the given direction, starting from the cell
2153
- // at `pos`, if any.
2154
-
2155
-
2156
- nextCell(pos, axis, dir) {
2157
- let {
2158
- left,
2159
- right,
2160
- top,
2161
- bottom
2162
- } = this.findCell(pos);
2163
-
2164
- if (axis == 'horiz') {
2165
- if (dir < 0 ? left == 0 : right == this.width) return null;
2166
- return this.map[top * this.width + (dir < 0 ? left - 1 : right)];
2167
- } else {
2168
- if (dir < 0 ? top == 0 : bottom == this.height) return null;
2169
- return this.map[left + this.width * (dir < 0 ? top - 1 : bottom)];
2170
- }
2171
- } // :: (number, number) → Rect
2172
- // Get the rectangle spanning the two given cells.
2173
-
2174
-
2175
- rectBetween(a, b) {
2176
- let {
2177
- left: leftA,
2178
- right: rightA,
2179
- top: topA,
2180
- bottom: bottomA
2181
- } = this.findCell(a);
2182
- let {
2183
- left: leftB,
2184
- right: rightB,
2185
- top: topB,
2186
- bottom: bottomB
2187
- } = this.findCell(b);
2188
- return new Rect(Math.min(leftA, leftB), Math.min(topA, topB), Math.max(rightA, rightB), Math.max(bottomA, bottomB));
2189
- } // :: (Rect) → [number]
2190
- // Return the position of all cells that have the top left corner in
2191
- // the given rectangle.
2192
-
2193
-
2194
- cellsInRect(rect) {
2195
- let result = [],
2196
- seen = {};
2197
-
2198
- for (let row = rect.top; row < rect.bottom; row++) {
2199
- for (let col = rect.left; col < rect.right; col++) {
2200
- let index = row * this.width + col,
2201
- pos = this.map[index];
2202
- if (seen[pos]) continue;
2203
- seen[pos] = true;
2204
- if ((col != rect.left || !col || this.map[index - 1] != pos) && (row != rect.top || !row || this.map[index - this.width] != pos)) result.push(pos);
2205
- }
2206
- }
2207
-
2208
- return result;
2209
- } // :: (number, number, Node) → number
2210
- // Return the position at which the cell at the given row and column
2211
- // starts, or would start, if a cell started there.
2212
-
2213
-
2214
- positionAt(row, col, table) {
2215
- for (let i = 0, rowStart = 0;; i++) {
2216
- let rowEnd = rowStart + table.child(i).nodeSize;
2217
-
2218
- if (i == row) {
2219
- let index = col + row * this.width,
2220
- rowEndIndex = (row + 1) * this.width; // Skip past cells from previous rows (via rowspan)
2221
-
2222
- while (index < rowEndIndex && this.map[index] < rowStart) index++;
2223
-
2224
- return index == rowEndIndex ? rowEnd - 1 : this.map[index];
2225
- }
2226
-
2227
- rowStart = rowEnd;
2228
- }
2229
- } // :: (Node) → TableMap
2230
- // Find the table map for the given table node.
2231
-
2232
-
2233
- static get(table) {
2234
- return readFromCache(table) || addToCache(table, computeMap(table));
2235
- }
2236
-
2237
- } // Compute a table map.
2238
-
2239
- function computeMap(table) {
2240
- if (table.type.spec.tableRole != 'table') throw new RangeError('Not a table node: ' + table.type.name);
2241
- let width = findWidth(table),
2242
- height = table.childCount;
2243
- let map = [],
2244
- mapPos = 0,
2245
- problems = null,
2246
- colWidths = [];
2247
-
2248
- for (let i = 0, e = width * height; i < e; i++) map[i] = 0;
2249
-
2250
- for (let row = 0, pos = 0; row < height; row++) {
2251
- let rowNode = table.child(row);
2252
- pos++;
2253
-
2254
- for (let i = 0;; i++) {
2255
- while (mapPos < map.length && map[mapPos] != 0) mapPos++;
2256
-
2257
- if (i == rowNode.childCount) break;
2258
- let cellNode = rowNode.child(i),
2259
- {
2260
- colspan,
2261
- rowspan,
2262
- colwidth
2263
- } = cellNode.attrs;
2264
-
2265
- for (let h = 0; h < rowspan; h++) {
2266
- if (h + row >= height) {
2267
- (problems || (problems = [])).push({
2268
- type: 'overlong_rowspan',
2269
- pos,
2270
- n: rowspan - h
2271
- });
2272
- break;
2273
- }
2274
-
2275
- let start = mapPos + h * width;
2276
-
2277
- for (let w = 0; w < colspan; w++) {
2278
- if (map[start + w] == 0) map[start + w] = pos;else (problems || (problems = [])).push({
2279
- type: 'collision',
2280
- row,
2281
- pos,
2282
- n: colspan - w
2283
- });
2284
- let colW = colwidth && colwidth[w];
2285
-
2286
- if (colW) {
2287
- let widthIndex = (start + w) % width * 2,
2288
- prev = colWidths[widthIndex];
2289
-
2290
- if (prev == null || prev != colW && colWidths[widthIndex + 1] == 1) {
2291
- colWidths[widthIndex] = colW;
2292
- colWidths[widthIndex + 1] = 1;
2293
- } else if (prev == colW) {
2294
- colWidths[widthIndex + 1]++;
2295
- }
2296
- }
2297
- }
2298
- }
2299
-
2300
- mapPos += colspan;
2301
- pos += cellNode.nodeSize;
2302
- }
2303
-
2304
- let expectedPos = (row + 1) * width,
2305
- missing = 0;
2306
-
2307
- while (mapPos < expectedPos) if (map[mapPos++] == 0) missing++;
2308
-
2309
- if (missing) (problems || (problems = [])).push({
2310
- type: 'missing',
2311
- row,
2312
- n: missing
2313
- });
2314
- pos++;
2315
- }
2316
-
2317
- let tableMap = new TableMap(width, height, map, problems),
2318
- badWidths = false; // For columns that have defined widths, but whose widths disagree
2319
- // between rows, fix up the cells whose width doesn't match the
2320
- // computed one.
2321
-
2322
- for (let i = 0; !badWidths && i < colWidths.length; i += 2) if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
2323
-
2324
- if (badWidths) findBadColWidths(tableMap, colWidths, table);
2325
- return tableMap;
2326
- }
2327
-
2328
- function findWidth(table) {
2329
- let width = -1,
2330
- hasRowSpan = false;
2331
-
2332
- for (let row = 0; row < table.childCount; row++) {
2333
- let rowNode = table.child(row),
2334
- rowWidth = 0;
2335
- if (hasRowSpan) for (let j = 0; j < row; j++) {
2336
- let prevRow = table.child(j);
2337
-
2338
- for (let i = 0; i < prevRow.childCount; i++) {
2339
- let cell = prevRow.child(i);
2340
- if (j + cell.attrs.rowspan > row) rowWidth += cell.attrs.colspan;
2341
- }
2342
- }
2343
-
2344
- for (let i = 0; i < rowNode.childCount; i++) {
2345
- let cell = rowNode.child(i);
2346
- rowWidth += cell.attrs.colspan;
2347
- if (cell.attrs.rowspan > 1) hasRowSpan = true;
2348
- }
2349
-
2350
- if (width == -1) width = rowWidth;else if (width != rowWidth) width = Math.max(width, rowWidth);
2351
- }
2352
-
2353
- return width;
2354
- }
2355
-
2356
- function findBadColWidths(map, colWidths, table) {
2357
- if (!map.problems) map.problems = [];
2358
-
2359
- for (let i = 0, seen = {}; i < map.map.length; i++) {
2360
- let pos = map.map[i];
2361
- if (seen[pos]) continue;
2362
- seen[pos] = true;
2363
- let node = table.nodeAt(pos),
2364
- updated = null;
2365
-
2366
- for (let j = 0; j < node.attrs.colspan; j++) {
2367
- let col = (i + j) % map.width,
2368
- colWidth = colWidths[col * 2];
2369
- if (colWidth != null && (!node.attrs.colwidth || node.attrs.colwidth[j] != colWidth)) (updated || (updated = freshColWidth(node.attrs)))[j] = colWidth;
2370
- }
2371
-
2372
- if (updated) map.problems.unshift({
2373
- type: 'colwidth mismatch',
2374
- pos,
2375
- colwidth: updated
2376
- });
2377
- }
2378
- }
2379
-
2380
- function freshColWidth(attrs) {
2381
- if (attrs.colwidth) return attrs.colwidth.slice();
2382
- let result = [];
2383
-
2384
- for (let i = 0; i < attrs.colspan; i++) result.push(0);
2385
-
2386
- return result;
2387
- }
2388
- function tableNodeTypes(schema) {
2389
- let result = schema.cached.tableNodeTypes;
2390
-
2391
- if (!result) {
2392
- result = schema.cached.tableNodeTypes = {};
2393
-
2394
- for (let name in schema.nodes) {
2395
- let type = schema.nodes[name],
2396
- role = type.spec.tableRole;
2397
- if (role) result[role] = type;
2398
- }
2399
- }
2400
-
2401
- return result;
2402
- }
2403
-
2404
- // Various helper function for working with tables
2405
- const key$1 = new prosemirrorState.PluginKey('selectingCells');
2406
- function cellAround($pos) {
2407
- for (let d = $pos.depth - 1; d > 0; d--) if ($pos.node(d).type.spec.tableRole == 'row') return $pos.node(0).resolve($pos.before(d + 1));
2408
-
2409
- return null;
2410
- }
2411
- function cellWrapping($pos) {
2412
- for (let d = $pos.depth; d > 0; d--) {
2413
- // Sometimes the cell can be in the same depth.
2414
- const role = $pos.node(d).type.spec.tableRole;
2415
- if (role === 'cell' || role === 'header_cell') return $pos.node(d);
2416
- }
2417
-
2418
- return null;
2419
- }
2420
- function isInTable(state) {
2421
- let $head = state.selection.$head;
2422
-
2423
- for (let d = $head.depth; d > 0; d--) if ($head.node(d).type.spec.tableRole == 'row') return true;
2424
-
2425
- return false;
2426
- }
2427
- function selectionCell(state) {
2428
- let sel = state.selection;
2429
-
2430
- if (sel.$anchorCell) {
2431
- return sel.$anchorCell.pos > sel.$headCell.pos ? sel.$anchorCell : sel.$headCell;
2432
- } else if (sel.node && sel.node.type.spec.tableRole == 'cell') {
2433
- return sel.$anchor;
2434
- }
2435
-
2436
- return cellAround(sel.$head) || cellNear(sel.$head);
2437
- }
2438
-
2439
- function cellNear($pos) {
2440
- for (let after = $pos.nodeAfter, pos = $pos.pos; after; after = after.firstChild, pos++) {
2441
- let role = after.type.spec.tableRole;
2442
- if (role == 'cell' || role == 'header_cell') return $pos.doc.resolve(pos);
2443
- }
2444
-
2445
- for (let before = $pos.nodeBefore, pos = $pos.pos; before; before = before.lastChild, pos--) {
2446
- let role = before.type.spec.tableRole;
2447
- if (role == 'cell' || role == 'header_cell') return $pos.doc.resolve(pos - before.nodeSize);
2448
- }
2449
- }
2450
-
2451
- function pointsAtCell($pos) {
2452
- return $pos.parent.type.spec.tableRole == 'row' && $pos.nodeAfter;
2453
- }
2454
- function moveCellForward($pos) {
2455
- return $pos.node(0).resolve($pos.pos + $pos.nodeAfter.nodeSize);
2456
- }
2457
- function inSameTable($a, $b) {
2458
- return $a.depth == $b.depth && $a.pos >= $b.start(-1) && $a.pos <= $b.end(-1);
2459
- }
2460
- function nextCell($pos, axis, dir) {
2461
- let start = $pos.start(-1),
2462
- map = TableMap.get($pos.node(-1));
2463
- let moved = map.nextCell($pos.pos - start, axis, dir);
2464
- return moved == null ? null : $pos.node(0).resolve(start + moved);
2465
- }
2466
- function setAttr(attrs, name, value) {
2467
- let result = {};
2468
-
2469
- for (let prop in attrs) result[prop] = attrs[prop];
2470
-
2471
- result[name] = value;
2472
- return result;
2473
- }
2474
- function removeColSpan(attrs, pos, n = 1) {
2475
- let result = setAttr(attrs, 'colspan', attrs.colspan - n);
2476
-
2477
- if (result.colwidth) {
2478
- result.colwidth = result.colwidth.slice();
2479
- result.colwidth.splice(pos, n);
2480
- if (!result.colwidth.some(w => w > 0)) result.colwidth = null;
2481
- }
2482
-
2483
- return result;
2484
- }
2485
- function addColSpan(attrs, pos, n = 1) {
2486
- let result = setAttr(attrs, 'colspan', attrs.colspan + n);
2487
-
2488
- if (result.colwidth) {
2489
- result.colwidth = result.colwidth.slice();
2490
-
2491
- for (let i = 0; i < n; i++) result.colwidth.splice(pos, 0, 0);
2492
- }
2493
-
2494
- return result;
2495
- }
2496
- function columnIsHeader(map, table, col) {
2497
- let headerCell = tableNodeTypes(table.type.schema).header_cell;
2498
-
2499
- for (let row = 0; row < map.height; row++) if (table.nodeAt(map.map[col + row * map.width]).type != headerCell) return false;
2500
-
2501
- return true;
2502
- }
2503
-
2504
- // This file defines a ProseMirror selection subclass that models
2505
- // subclass that represents a cell selection spanning part of a table.
2506
- // With the plugin enabled, these will be created when the user
2507
- // selects across cells, and will be drawn by giving selected cells a
2508
- // `selectedCell` CSS class.
2509
-
2510
- class CellSelection extends prosemirrorState.Selection {
2511
- // :: (ResolvedPos, ?ResolvedPos)
2512
- // A table selection is identified by its anchor and head cells. The
2513
- // positions given to this constructor should point _before_ two
2514
- // cells in the same table. They may be the same, to select a single
2515
- // cell.
2516
- constructor($anchorCell, $headCell = $anchorCell) {
2517
- let table = $anchorCell.node(-1),
2518
- map = TableMap.get(table),
2519
- start = $anchorCell.start(-1);
2520
- let rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
2521
- let doc = $anchorCell.node(0);
2522
- let cells = map.cellsInRect(rect).filter(p => p != $headCell.pos - start); // Make the head cell the first range, so that it counts as the
2523
- // primary part of the selection
2524
-
2525
- cells.unshift($headCell.pos - start);
2526
- let ranges = cells.map(pos => {
2527
- let cell = table.nodeAt(pos),
2528
- from = pos + start + 1;
2529
- return new prosemirrorState.SelectionRange(doc.resolve(from), doc.resolve(from + cell.content.size));
2530
- });
2531
- super(ranges[0].$from, ranges[0].$to, ranges); // :: ResolvedPos
2532
- // A resolved position pointing _in front of_ the anchor cell (the one
2533
- // that doesn't move when extending the selection).
2534
-
2535
- this.$anchorCell = $anchorCell; // :: ResolvedPos
2536
- // A resolved position pointing in front of the head cell (the one
2537
- // moves when extending the selection).
2538
-
2539
- this.$headCell = $headCell;
2540
- }
2541
-
2542
- map(doc, mapping) {
2543
- let $anchorCell = doc.resolve(mapping.map(this.$anchorCell.pos));
2544
- let $headCell = doc.resolve(mapping.map(this.$headCell.pos));
2545
-
2546
- if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
2547
- let tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1);
2548
- if (tableChanged && this.isRowSelection()) return CellSelection.rowSelection($anchorCell, $headCell);else if (tableChanged && this.isColSelection()) return CellSelection.colSelection($anchorCell, $headCell);else return new CellSelection($anchorCell, $headCell);
2549
- }
2550
-
2551
- return prosemirrorState.TextSelection.between($anchorCell, $headCell);
2552
- } // :: () → Slice
2553
- // Returns a rectangular slice of table rows containing the selected
2554
- // cells.
2555
-
2556
-
2557
- content() {
2558
- let table = this.$anchorCell.node(-1),
2559
- map = TableMap.get(table),
2560
- start = this.$anchorCell.start(-1);
2561
- let rect = map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start);
2562
- let seen = {},
2563
- rows = [];
2564
-
2565
- for (let row = rect.top; row < rect.bottom; row++) {
2566
- let rowContent = [];
2567
-
2568
- for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
2569
- let pos = map.map[index];
2570
-
2571
- if (!seen[pos]) {
2572
- seen[pos] = true;
2573
- let cellRect = map.findCell(pos),
2574
- cell = table.nodeAt(pos);
2575
- let extraLeft = rect.left - cellRect.left,
2576
- extraRight = cellRect.right - rect.right;
2577
-
2578
- if (extraLeft > 0 || extraRight > 0) {
2579
- let attrs = cell.attrs;
2580
- if (extraLeft > 0) attrs = removeColSpan(attrs, 0, extraLeft);
2581
- if (extraRight > 0) attrs = removeColSpan(attrs, attrs.colspan - extraRight, extraRight);
2582
- if (cellRect.left < rect.left) cell = cell.type.createAndFill(attrs);else cell = cell.type.create(attrs, cell.content);
2583
- }
2584
-
2585
- if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
2586
- let attrs = setAttr(cell.attrs, 'rowspan', Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top));
2587
- if (cellRect.top < rect.top) cell = cell.type.createAndFill(attrs);else cell = cell.type.create(attrs, cell.content);
2588
- }
2589
-
2590
- rowContent.push(cell);
2591
- }
2592
- }
2593
-
2594
- rows.push(table.child(row).copy(prosemirrorModel.Fragment.from(rowContent)));
2595
- }
2596
-
2597
- const fragment = this.isColSelection() && this.isRowSelection() ? table : rows;
2598
- return new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(fragment), 1, 1);
2599
- }
2600
-
2601
- replace(tr, content = prosemirrorModel.Slice.empty) {
2602
- let mapFrom = tr.steps.length,
2603
- ranges = this.ranges;
2604
-
2605
- for (let i = 0; i < ranges.length; i++) {
2606
- let {
2607
- $from,
2608
- $to
2609
- } = ranges[i],
2610
- mapping = tr.mapping.slice(mapFrom);
2611
- tr.replace(mapping.map($from.pos), mapping.map($to.pos), i ? prosemirrorModel.Slice.empty : content);
2612
- }
2613
-
2614
- let sel = prosemirrorState.Selection.findFrom(tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)), -1);
2615
- if (sel) tr.setSelection(sel);
2616
- }
2617
-
2618
- replaceWith(tr, node) {
2619
- this.replace(tr, new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(node), 0, 0));
2620
- }
2621
-
2622
- forEachCell(f) {
2623
- let table = this.$anchorCell.node(-1),
2624
- map = TableMap.get(table),
2625
- start = this.$anchorCell.start(-1);
2626
- let cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start));
2627
-
2628
- for (let i = 0; i < cells.length; i++) f(table.nodeAt(cells[i]), start + cells[i]);
2629
- } // :: () → bool
2630
- // True if this selection goes all the way from the top to the
2631
- // bottom of the table.
2632
-
2633
-
2634
- isColSelection() {
2635
- let anchorTop = this.$anchorCell.index(-1),
2636
- headTop = this.$headCell.index(-1);
2637
- if (Math.min(anchorTop, headTop) > 0) return false;
2638
- let anchorBot = anchorTop + this.$anchorCell.nodeAfter.attrs.rowspan,
2639
- headBot = headTop + this.$headCell.nodeAfter.attrs.rowspan;
2640
- return Math.max(anchorBot, headBot) == this.$headCell.node(-1).childCount;
2641
- } // :: (ResolvedPos, ?ResolvedPos) → CellSelection
2642
- // Returns the smallest column selection that covers the given anchor
2643
- // and head cell.
2644
-
2645
-
2646
- static colSelection($anchorCell, $headCell = $anchorCell) {
2647
- let map = TableMap.get($anchorCell.node(-1)),
2648
- start = $anchorCell.start(-1);
2649
- let anchorRect = map.findCell($anchorCell.pos - start),
2650
- headRect = map.findCell($headCell.pos - start);
2651
- let doc = $anchorCell.node(0);
2652
-
2653
- if (anchorRect.top <= headRect.top) {
2654
- if (anchorRect.top > 0) $anchorCell = doc.resolve(start + map.map[anchorRect.left]);
2655
- if (headRect.bottom < map.height) $headCell = doc.resolve(start + map.map[map.width * (map.height - 1) + headRect.right - 1]);
2656
- } else {
2657
- if (headRect.top > 0) $headCell = doc.resolve(start + map.map[headRect.left]);
2658
- if (anchorRect.bottom < map.height) $anchorCell = doc.resolve(start + map.map[map.width * (map.height - 1) + anchorRect.right - 1]);
2659
- }
2660
-
2661
- return new CellSelection($anchorCell, $headCell);
2662
- } // :: () → bool
2663
- // True if this selection goes all the way from the left to the
2664
- // right of the table.
2665
-
2666
-
2667
- isRowSelection() {
2668
- let map = TableMap.get(this.$anchorCell.node(-1)),
2669
- start = this.$anchorCell.start(-1);
2670
- let anchorLeft = map.colCount(this.$anchorCell.pos - start),
2671
- headLeft = map.colCount(this.$headCell.pos - start);
2672
- if (Math.min(anchorLeft, headLeft) > 0) return false;
2673
- let anchorRight = anchorLeft + this.$anchorCell.nodeAfter.attrs.colspan,
2674
- headRight = headLeft + this.$headCell.nodeAfter.attrs.colspan;
2675
- return Math.max(anchorRight, headRight) == map.width;
2676
- }
2677
-
2678
- eq(other) {
2679
- return other instanceof CellSelection && other.$anchorCell.pos == this.$anchorCell.pos && other.$headCell.pos == this.$headCell.pos;
2680
- } // :: (ResolvedPos, ?ResolvedPos) → CellSelection
2681
- // Returns the smallest row selection that covers the given anchor
2682
- // and head cell.
2683
-
2684
-
2685
- static rowSelection($anchorCell, $headCell = $anchorCell) {
2686
- let map = TableMap.get($anchorCell.node(-1)),
2687
- start = $anchorCell.start(-1);
2688
- let anchorRect = map.findCell($anchorCell.pos - start),
2689
- headRect = map.findCell($headCell.pos - start);
2690
- let doc = $anchorCell.node(0);
2691
-
2692
- if (anchorRect.left <= headRect.left) {
2693
- if (anchorRect.left > 0) $anchorCell = doc.resolve(start + map.map[anchorRect.top * map.width]);
2694
- if (headRect.right < map.width) $headCell = doc.resolve(start + map.map[map.width * (headRect.top + 1) - 1]);
2695
- } else {
2696
- if (headRect.left > 0) $headCell = doc.resolve(start + map.map[headRect.top * map.width]);
2697
- if (anchorRect.right < map.width) $anchorCell = doc.resolve(start + map.map[map.width * (anchorRect.top + 1) - 1]);
2698
- }
2699
-
2700
- return new CellSelection($anchorCell, $headCell);
2701
- }
2702
-
2703
- toJSON() {
2704
- return {
2705
- type: 'cell',
2706
- anchor: this.$anchorCell.pos,
2707
- head: this.$headCell.pos
2708
- };
2709
- }
2710
-
2711
- static fromJSON(doc, json) {
2712
- return new CellSelection(doc.resolve(json.anchor), doc.resolve(json.head));
2713
- } // :: (Node, number, ?number) → CellSelection
2714
-
2715
-
2716
- static create(doc, anchorCell, headCell = anchorCell) {
2717
- return new CellSelection(doc.resolve(anchorCell), doc.resolve(headCell));
2718
- }
2719
-
2720
- getBookmark() {
2721
- return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos);
2722
- }
2723
-
2724
- }
2725
- CellSelection.prototype.visible = false;
2726
- prosemirrorState.Selection.jsonID('cell', CellSelection);
2727
-
2728
- class CellBookmark {
2729
- constructor(anchor, head) {
2730
- this.anchor = anchor;
2731
- this.head = head;
2732
- }
2733
-
2734
- map(mapping) {
2735
- return new CellBookmark(mapping.map(this.anchor), mapping.map(this.head));
2736
- }
2737
-
2738
- resolve(doc) {
2739
- let $anchorCell = doc.resolve(this.anchor),
2740
- $headCell = doc.resolve(this.head);
2741
- 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)) return new CellSelection($anchorCell, $headCell);else return prosemirrorState.Selection.near($headCell, 1);
2742
- }
2743
-
2744
- }
2745
-
2746
- function drawCellSelection(state) {
2747
- if (!(state.selection instanceof CellSelection)) return null;
2748
- let cells = [];
2749
- state.selection.forEachCell((node, pos) => {
2750
- cells.push(prosemirrorView.Decoration.node(pos, pos + node.nodeSize, {
2751
- class: 'selectedCell'
2752
- }));
2753
- });
2754
- return prosemirrorView.DecorationSet.create(state.doc, cells);
2755
- }
2756
-
2757
- function isCellBoundarySelection({
2758
- $from,
2759
- $to
2760
- }) {
2761
- if ($from.pos == $to.pos || $from.pos < $from.pos - 6) return false; // Cheap elimination
2762
-
2763
- let afterFrom = $from.pos,
2764
- beforeTo = $to.pos,
2765
- depth = $from.depth;
2766
-
2767
- for (; depth >= 0; depth--, afterFrom++) if ($from.after(depth + 1) < $from.end(depth)) break;
2768
-
2769
- for (let d = $to.depth; d >= 0; d--, beforeTo--) if ($to.before(d + 1) > $to.start(d)) break;
2770
-
2771
- return afterFrom == beforeTo && /row|table/.test($from.node(depth).type.spec.tableRole);
2772
- }
2773
-
2774
- function isTextSelectionAcrossCells({
2775
- $from,
2776
- $to
2777
- }) {
2778
- let fromCellBoundaryNode;
2779
- let toCellBoundaryNode;
2780
-
2781
- for (let i = $from.depth; i > 0; i--) {
2782
- let node = $from.node(i);
2783
-
2784
- if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
2785
- fromCellBoundaryNode = node;
2786
- break;
2787
- }
2788
- }
2789
-
2790
- for (let i = $to.depth; i > 0; i--) {
2791
- let node = $to.node(i);
2792
-
2793
- if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
2794
- toCellBoundaryNode = node;
2795
- break;
2796
- }
2797
- }
2798
-
2799
- return fromCellBoundaryNode !== toCellBoundaryNode && $to.parentOffset === 0;
2800
- }
2801
-
2802
- function normalizeSelection(state, tr, allowTableNodeSelection) {
2803
- let sel = (tr || state).selection,
2804
- doc = (tr || state).doc,
2805
- normalize,
2806
- role;
2807
-
2808
- if (sel instanceof prosemirrorState.NodeSelection && (role = sel.node.type.spec.tableRole)) {
2809
- if (role == 'cell' || role == 'header_cell') {
2810
- normalize = CellSelection.create(doc, sel.from);
2811
- } else if (role == 'row') {
2812
- let $cell = doc.resolve(sel.from + 1);
2813
- normalize = CellSelection.rowSelection($cell, $cell);
2814
- } else if (!allowTableNodeSelection) {
2815
- let map = TableMap.get(sel.node),
2816
- start = sel.from + 1;
2817
- let lastCell = start + map.map[map.width * map.height - 1];
2818
- normalize = CellSelection.create(doc, start + 1, lastCell);
2819
- }
2820
- } else if (sel instanceof prosemirrorState.TextSelection && isCellBoundarySelection(sel)) {
2821
- normalize = prosemirrorState.TextSelection.create(doc, sel.from);
2822
- } else if (sel instanceof prosemirrorState.TextSelection && isTextSelectionAcrossCells(sel)) {
2823
- normalize = prosemirrorState.TextSelection.create(doc, sel.$from.start(), sel.$from.end());
2824
- }
2825
-
2826
- if (normalize) (tr || (tr = state.tr)).setSelection(normalize);
2827
- return tr;
2828
- }
2829
-
2830
- // Utilities used for copy/paste handling.
2831
- // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
2832
- // Get a rectangular area of cells from a slice, or null if the outer
2833
- // nodes of the slice aren't table cells or rows.
2834
-
2835
- function pastedCells(slice) {
2836
- if (!slice.size) return null;
2837
- let {
2838
- content,
2839
- openStart,
2840
- openEnd
2841
- } = slice;
2842
-
2843
- while (content.childCount == 1 && (openStart > 0 && openEnd > 0 || content.firstChild.type.spec.tableRole == 'table')) {
2844
- openStart--;
2845
- openEnd--;
2846
- content = content.firstChild.content;
2847
- }
2848
-
2849
- let first = content.firstChild,
2850
- role = first.type.spec.tableRole;
2851
- let schema = first.type.schema,
2852
- rows = [];
2853
-
2854
- if (role == 'row') {
2855
- for (let i = 0; i < content.childCount; i++) {
2856
- let cells = content.child(i).content;
2857
- let left = i ? 0 : Math.max(0, openStart - 1);
2858
- let right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
2859
- if (left || right) cells = fitSlice(tableNodeTypes(schema).row, new prosemirrorModel.Slice(cells, left, right)).content;
2860
- rows.push(cells);
2861
- }
2862
- } else if (role == 'cell' || role == 'header_cell') {
2863
- rows.push(openStart || openEnd ? fitSlice(tableNodeTypes(schema).row, new prosemirrorModel.Slice(content, openStart, openEnd)).content : content);
2864
- } else {
2865
- return null;
2866
- }
2867
-
2868
- return ensureRectangular(schema, rows);
2869
- } // : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
2870
- // Compute the width and height of a set of cells, and make sure each
2871
- // row has the same number of cells.
2872
-
2873
- function ensureRectangular(schema, rows) {
2874
- let widths = [];
2875
-
2876
- for (let i = 0; i < rows.length; i++) {
2877
- let row = rows[i];
2878
-
2879
- for (let j = row.childCount - 1; j >= 0; j--) {
2880
- let {
2881
- rowspan,
2882
- colspan
2883
- } = row.child(j).attrs;
2884
-
2885
- for (let r = i; r < i + rowspan; r++) widths[r] = (widths[r] || 0) + colspan;
2886
- }
2887
- }
2888
-
2889
- let width = 0;
2890
-
2891
- for (let r = 0; r < widths.length; r++) width = Math.max(width, widths[r]);
2892
-
2893
- for (let r = 0; r < widths.length; r++) {
2894
- if (r >= rows.length) rows.push(prosemirrorModel.Fragment.empty);
2895
-
2896
- if (widths[r] < width) {
2897
- let empty = tableNodeTypes(schema).cell.createAndFill(),
2898
- cells = [];
2899
-
2900
- for (let i = widths[r]; i < width; i++) cells.push(empty);
2901
-
2902
- rows[r] = rows[r].append(prosemirrorModel.Fragment.from(cells));
2903
- }
2904
- }
2905
-
2906
- return {
2907
- height: rows.length,
2908
- width,
2909
- rows
2910
- };
2911
- }
2912
-
2913
- function fitSlice(nodeType, slice) {
2914
- let node = nodeType.createAndFill();
2915
- let tr = new Transform(node).replace(0, node.content.size, slice);
2916
- return tr.doc;
2917
- } // : ({width: number, height: number, rows: [Fragment]}, number, number) → {width: number, height: number, rows: [Fragment]}
2918
- // Clip or extend (repeat) the given set of cells to cover the given
2919
- // width and height. Will clip rowspan/colspan cells at the edges when
2920
- // they stick out.
2921
-
2922
- function clipCells({
2923
- width,
2924
- height,
2925
- rows
2926
- }, newWidth, newHeight) {
2927
- if (width != newWidth) {
2928
- let added = [],
2929
- newRows = [];
2930
-
2931
- for (let row = 0; row < rows.length; row++) {
2932
- let frag = rows[row],
2933
- cells = [];
2934
-
2935
- for (let col = added[row] || 0, i = 0; col < newWidth; i++) {
2936
- let cell = frag.child(i % frag.childCount);
2937
- if (col + cell.attrs.colspan > newWidth) cell = cell.type.create(removeColSpan(cell.attrs, cell.attrs.colspan, col + cell.attrs.colspan - newWidth), cell.content);
2938
- cells.push(cell);
2939
- col += cell.attrs.colspan;
2940
-
2941
- for (let j = 1; j < cell.attrs.rowspan; j++) added[row + j] = (added[row + j] || 0) + cell.attrs.colspan;
2942
- }
2943
-
2944
- newRows.push(prosemirrorModel.Fragment.from(cells));
2945
- }
2946
-
2947
- rows = newRows;
2948
- width = newWidth;
2949
- }
2950
-
2951
- if (height != newHeight) {
2952
- let newRows = [];
2953
-
2954
- for (let row = 0, i = 0; row < newHeight; row++, i++) {
2955
- let cells = [],
2956
- source = rows[i % height];
2957
-
2958
- for (let j = 0; j < source.childCount; j++) {
2959
- let cell = source.child(j);
2960
- if (row + cell.attrs.rowspan > newHeight) cell = cell.type.create(setAttr(cell.attrs, 'rowspan', Math.max(1, newHeight - cell.attrs.rowspan)), cell.content);
2961
- cells.push(cell);
2962
- }
2963
-
2964
- newRows.push(prosemirrorModel.Fragment.from(cells));
2965
- }
2966
-
2967
- rows = newRows;
2968
- height = newHeight;
2969
- }
2970
-
2971
- return {
2972
- width,
2973
- height,
2974
- rows
2975
- };
2976
- } // Make sure a table has at least the given width and height. Return
2977
- // true if something was changed.
2978
-
2979
- function growTable(tr, map, table, start, width, height, mapFrom) {
2980
- let schema = tr.doc.type.schema,
2981
- types = tableNodeTypes(schema),
2982
- empty,
2983
- emptyHead;
2984
-
2985
- if (width > map.width) {
2986
- for (let row = 0, rowEnd = 0; row < map.height; row++) {
2987
- let rowNode = table.child(row);
2988
- rowEnd += rowNode.nodeSize;
2989
- let cells = [],
2990
- add;
2991
- if (rowNode.lastChild == null || rowNode.lastChild.type == types.cell) add = empty || (empty = types.cell.createAndFill());else add = emptyHead || (emptyHead = types.header_cell.createAndFill());
2992
-
2993
- for (let i = map.width; i < width; i++) cells.push(add);
2994
-
2995
- tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells);
2996
- }
2997
- }
2998
-
2999
- if (height > map.height) {
3000
- let cells = [];
3001
-
3002
- for (let i = 0, start = (map.height - 1) * map.width; i < Math.max(map.width, width); i++) {
3003
- let header = i >= map.width ? false : table.nodeAt(map.map[start + i]).type == types.header_cell;
3004
- cells.push(header ? emptyHead || (emptyHead = types.header_cell.createAndFill()) : empty || (empty = types.cell.createAndFill()));
3005
- }
3006
-
3007
- let emptyRow = types.row.create(null, prosemirrorModel.Fragment.from(cells)),
3008
- rows = [];
3009
-
3010
- for (let i = map.height; i < height; i++) rows.push(emptyRow);
3011
-
3012
- tr.insert(tr.mapping.slice(mapFrom).map(start + table.nodeSize - 2), rows);
3013
- }
3014
-
3015
- return !!(empty || emptyHead);
3016
- } // Make sure the given line (left, top) to (right, top) doesn't cross
3017
- // any rowspan cells by splitting cells that cross it. Return true if
3018
- // something changed.
3019
-
3020
-
3021
- function isolateHorizontal(tr, map, table, start, left, right, top, mapFrom) {
3022
- if (top == 0 || top == map.height) return false;
3023
- let found = false;
3024
-
3025
- for (let col = left; col < right; col++) {
3026
- let index = top * map.width + col,
3027
- pos = map.map[index];
3028
-
3029
- if (map.map[index - map.width] == pos) {
3030
- found = true;
3031
- let cell = table.nodeAt(pos);
3032
- let {
3033
- top: cellTop,
3034
- left: cellLeft
3035
- } = map.findCell(pos);
3036
- tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), null, setAttr(cell.attrs, 'rowspan', top - cellTop));
3037
- tr.insert(tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table)), cell.type.createAndFill(setAttr(cell.attrs, 'rowspan', cellTop + cell.attrs.rowspan - top)));
3038
- col += cell.attrs.colspan - 1;
3039
- }
3040
- }
3041
-
3042
- return found;
3043
- } // Make sure the given line (left, top) to (left, bottom) doesn't
3044
- // cross any colspan cells by splitting cells that cross it. Return
3045
- // true if something changed.
3046
-
3047
-
3048
- function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
3049
- if (left == 0 || left == map.width) return false;
3050
- let found = false;
3051
-
3052
- for (let row = top; row < bottom; row++) {
3053
- let index = row * map.width + left,
3054
- pos = map.map[index];
3055
-
3056
- if (map.map[index - 1] == pos) {
3057
- found = true;
3058
- let cell = table.nodeAt(pos),
3059
- cellLeft = map.colCount(pos);
3060
- let updatePos = tr.mapping.slice(mapFrom).map(pos + start);
3061
- tr.setNodeMarkup(updatePos, null, removeColSpan(cell.attrs, left - cellLeft, cell.attrs.colspan - (left - cellLeft)));
3062
- tr.insert(updatePos + cell.nodeSize, cell.type.createAndFill(removeColSpan(cell.attrs, 0, left - cellLeft)));
3063
- row += cell.attrs.rowspan - 1;
3064
- }
3065
- }
3066
-
3067
- return found;
3068
- } // Insert the given set of cells (as returned by `pastedCells`) into a
3069
- // table, at the position pointed at by rect.
3070
-
3071
-
3072
- function insertCells(state, dispatch, tableStart, rect, cells) {
3073
- let table = tableStart ? state.doc.nodeAt(tableStart - 1) : state.doc,
3074
- map = TableMap.get(table);
3075
- let {
3076
- top,
3077
- left
3078
- } = rect;
3079
- let right = left + cells.width,
3080
- bottom = top + cells.height;
3081
- let tr = state.tr,
3082
- mapFrom = 0;
3083
-
3084
- function recomp() {
3085
- table = tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc;
3086
- map = TableMap.get(table);
3087
- mapFrom = tr.mapping.maps.length;
3088
- } // Prepare the table to be large enough and not have any cells
3089
- // crossing the boundaries of the rectangle that we want to
3090
- // insert into. If anything about it changes, recompute the table
3091
- // map so that subsequent operations can see the current shape.
3092
-
3093
-
3094
- if (growTable(tr, map, table, tableStart, right, bottom, mapFrom)) recomp();
3095
- if (isolateHorizontal(tr, map, table, tableStart, left, right, top, mapFrom)) recomp();
3096
- if (isolateHorizontal(tr, map, table, tableStart, left, right, bottom, mapFrom)) recomp();
3097
- if (isolateVertical(tr, map, table, tableStart, top, bottom, left, mapFrom)) recomp();
3098
- if (isolateVertical(tr, map, table, tableStart, top, bottom, right, mapFrom)) recomp();
3099
-
3100
- for (let row = top; row < bottom; row++) {
3101
- let from = map.positionAt(row, left, table),
3102
- to = map.positionAt(row, right, table);
3103
- tr.replace(tr.mapping.slice(mapFrom).map(from + tableStart), tr.mapping.slice(mapFrom).map(to + tableStart), new prosemirrorModel.Slice(cells.rows[row - top], 0, 0));
3104
- }
3105
-
3106
- recomp();
3107
- tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
3108
- dispatch(tr);
3109
- }
3110
-
3111
- // This file defines a number of helpers for wiring up user input to
3112
- const handleKeyDown = keydownHandler({
3113
- ArrowLeft: arrow('horiz', -1),
3114
- ArrowRight: arrow('horiz', 1),
3115
- ArrowUp: arrow('vert', -1),
3116
- ArrowDown: arrow('vert', 1),
3117
- 'Shift-ArrowLeft': shiftArrow('horiz', -1),
3118
- 'Shift-ArrowRight': shiftArrow('horiz', 1),
3119
- 'Shift-ArrowUp': shiftArrow('vert', -1),
3120
- 'Shift-ArrowDown': shiftArrow('vert', 1),
3121
- Backspace: deleteCellSelection,
3122
- 'Mod-Backspace': deleteCellSelection,
3123
- Delete: deleteCellSelection,
3124
- 'Mod-Delete': deleteCellSelection
3125
- });
3126
-
3127
- function maybeSetSelection(state, dispatch, selection) {
3128
- if (selection.eq(state.selection)) return false;
3129
- if (dispatch) dispatch(state.tr.setSelection(selection).scrollIntoView());
3130
- return true;
3131
- }
3132
-
3133
- function arrow(axis, dir) {
3134
- return (state, dispatch, view) => {
3135
- let sel = state.selection;
3136
-
3137
- if (sel instanceof CellSelection) {
3138
- return maybeSetSelection(state, dispatch, prosemirrorState.Selection.near(sel.$headCell, dir));
3139
- }
3140
-
3141
- if (axis != 'horiz' && !sel.empty) return false;
3142
- let end = atEndOfCell(view, axis, dir);
3143
- if (end == null) return false;
3144
-
3145
- if (axis == 'horiz') {
3146
- return maybeSetSelection(state, dispatch, prosemirrorState.Selection.near(state.doc.resolve(sel.head + dir), dir));
3147
- } else {
3148
- let $cell = state.doc.resolve(end),
3149
- $next = nextCell($cell, axis, dir),
3150
- newSel;
3151
- if ($next) newSel = prosemirrorState.Selection.near($next, 1);else if (dir < 0) newSel = prosemirrorState.Selection.near(state.doc.resolve($cell.before(-1)), -1);else newSel = prosemirrorState.Selection.near(state.doc.resolve($cell.after(-1)), 1);
3152
- return maybeSetSelection(state, dispatch, newSel);
3153
- }
3154
- };
3155
- }
3156
-
3157
- function shiftArrow(axis, dir) {
3158
- return (state, dispatch, view) => {
3159
- let sel = state.selection;
3160
-
3161
- if (!(sel instanceof CellSelection)) {
3162
- let end = atEndOfCell(view, axis, dir);
3163
- if (end == null) return false;
3164
- sel = new CellSelection(state.doc.resolve(end));
3165
- }
3166
-
3167
- let $head = nextCell(sel.$headCell, axis, dir);
3168
- if (!$head) return false;
3169
- return maybeSetSelection(state, dispatch, new CellSelection(sel.$anchorCell, $head));
3170
- };
3171
- }
3172
-
3173
- function deleteCellSelection(state, dispatch) {
3174
- let sel = state.selection;
3175
- if (!(sel instanceof CellSelection)) return false;
3176
-
3177
- if (dispatch) {
3178
- let tr = state.tr,
3179
- baseContent = tableNodeTypes(state.schema).cell.createAndFill().content;
3180
- sel.forEachCell((cell, pos) => {
3181
- if (!cell.content.eq(baseContent)) tr.replace(tr.mapping.map(pos + 1), tr.mapping.map(pos + cell.nodeSize - 1), new prosemirrorModel.Slice(baseContent, 0, 0));
3182
- });
3183
- if (tr.docChanged) dispatch(tr);
3184
- }
3185
-
3186
- return true;
3187
- }
3188
-
3189
- function handleTripleClick(view, pos) {
3190
- let doc = view.state.doc,
3191
- $cell = cellAround(doc.resolve(pos));
3192
- if (!$cell) return false;
3193
- view.dispatch(view.state.tr.setSelection(new CellSelection($cell)));
3194
- return true;
3195
- }
3196
- function handlePaste(view, _, slice) {
3197
- if (!isInTable(view.state)) return false;
3198
- let cells = pastedCells(slice),
3199
- sel = view.state.selection;
3200
-
3201
- if (sel instanceof CellSelection) {
3202
- if (!cells) cells = {
3203
- width: 1,
3204
- height: 1,
3205
- rows: [prosemirrorModel.Fragment.from(fitSlice(tableNodeTypes(view.state.schema).cell, slice))]
3206
- };
3207
- let table = sel.$anchorCell.node(-1),
3208
- start = sel.$anchorCell.start(-1);
3209
- let rect = TableMap.get(table).rectBetween(sel.$anchorCell.pos - start, sel.$headCell.pos - start);
3210
- cells = clipCells(cells, rect.right - rect.left, rect.bottom - rect.top);
3211
- insertCells(view.state, view.dispatch, start, rect, cells);
3212
- return true;
3213
- } else if (cells) {
3214
- let $cell = selectionCell(view.state),
3215
- start = $cell.start(-1);
3216
- insertCells(view.state, view.dispatch, start, TableMap.get($cell.node(-1)).findCell($cell.pos - start), cells);
3217
- return true;
3218
- } else {
3219
- return false;
3220
- }
3221
- }
3222
- function handleMouseDown$1(view, startEvent) {
3223
- if (startEvent.ctrlKey || startEvent.metaKey) return;
3224
- let startDOMCell = domInCell(view, startEvent.target),
3225
- $anchor;
3226
-
3227
- if (startEvent.shiftKey && view.state.selection instanceof CellSelection) {
3228
- // Adding to an existing cell selection
3229
- setCellSelection(view.state.selection.$anchorCell, startEvent);
3230
- startEvent.preventDefault();
3231
- } else if (startEvent.shiftKey && startDOMCell && ($anchor = cellAround(view.state.selection.$anchor)) != null && cellUnderMouse(view, startEvent).pos != $anchor.pos) {
3232
- // Adding to a selection that starts in another cell (causing a
3233
- // cell selection to be created).
3234
- setCellSelection($anchor, startEvent);
3235
- startEvent.preventDefault();
3236
- } else if (!startDOMCell) {
3237
- // Not in a cell, let the default behavior happen.
3238
- return;
3239
- } // Create and dispatch a cell selection between the given anchor and
3240
- // the position under the mouse.
3241
-
3242
-
3243
- function setCellSelection($anchor, event) {
3244
- let $head = cellUnderMouse(view, event);
3245
- let starting = key$1.getState(view.state) == null;
3246
-
3247
- if (!$head || !inSameTable($anchor, $head)) {
3248
- if (starting) $head = $anchor;else return;
3249
- }
3250
-
3251
- let selection = new CellSelection($anchor, $head);
3252
-
3253
- if (starting || !view.state.selection.eq(selection)) {
3254
- let tr = view.state.tr.setSelection(selection);
3255
- if (starting) tr.setMeta(key$1, $anchor.pos);
3256
- view.dispatch(tr);
3257
- }
3258
- } // Stop listening to mouse motion events.
3259
-
3260
-
3261
- function stop() {
3262
- view.root.removeEventListener('mouseup', stop);
3263
- view.root.removeEventListener('dragstart', stop);
3264
- view.root.removeEventListener('mousemove', move);
3265
- if (key$1.getState(view.state) != null) view.dispatch(view.state.tr.setMeta(key$1, -1));
3266
- }
3267
-
3268
- function move(event) {
3269
- let anchor = key$1.getState(view.state),
3270
- $anchor;
3271
-
3272
- if (anchor != null) {
3273
- // Continuing an existing cross-cell selection
3274
- $anchor = view.state.doc.resolve(anchor);
3275
- } else if (domInCell(view, event.target) != startDOMCell) {
3276
- // Moving out of the initial cell -- start a new cell selection
3277
- $anchor = cellUnderMouse(view, startEvent);
3278
- if (!$anchor) return stop();
3279
- }
3280
-
3281
- if ($anchor) setCellSelection($anchor, event);
3282
- }
3283
-
3284
- view.root.addEventListener('mouseup', stop);
3285
- view.root.addEventListener('dragstart', stop);
3286
- view.root.addEventListener('mousemove', move);
3287
- } // Check whether the cursor is at the end of a cell (so that further
3288
- // motion would move out of the cell)
3289
-
3290
- function atEndOfCell(view, axis, dir) {
3291
- if (!(view.state.selection instanceof prosemirrorState.TextSelection)) return null;
3292
- let {
3293
- $head
3294
- } = view.state.selection;
3295
-
3296
- for (let d = $head.depth - 1; d >= 0; d--) {
3297
- let parent = $head.node(d),
3298
- index = dir < 0 ? $head.index(d) : $head.indexAfter(d);
3299
- if (index != (dir < 0 ? 0 : parent.childCount)) return null;
3300
-
3301
- if (parent.type.spec.tableRole == 'cell' || parent.type.spec.tableRole == 'header_cell') {
3302
- let cellPos = $head.before(d);
3303
- let dirStr = axis == 'vert' ? dir > 0 ? 'down' : 'up' : dir > 0 ? 'right' : 'left';
3304
- return view.endOfTextblock(dirStr) ? cellPos : null;
3305
- }
3306
- }
3307
-
3308
- return null;
3309
- }
3310
-
3311
- function domInCell(view, dom) {
3312
- for (; dom && dom != view.dom; dom = dom.parentNode) if (dom.nodeName == 'TD' || dom.nodeName == 'TH') return dom;
3313
- }
3314
-
3315
- function cellUnderMouse(view, event) {
3316
- let mousePos = view.posAtCoords({
3317
- left: event.clientX,
3318
- top: event.clientY
3319
- });
3320
- if (!mousePos) return null;
3321
- return mousePos ? cellAround(view.state.doc.resolve(mousePos.pos)) : null;
3322
- }
3323
-
3324
- // This file defines helpers for normalizing tables, making sure no
3325
- const fixTablesKey = new prosemirrorState.PluginKey('fix-tables'); // Helper for iterating through the nodes in a document that changed
3326
- // compared to the given previous document. Useful for avoiding
3327
- // duplicate work on each transaction.
3328
-
3329
- function changedDescendants(old, cur, offset, f) {
3330
- let oldSize = old.childCount,
3331
- curSize = cur.childCount;
3332
-
3333
- outer: for (let i = 0, j = 0; i < curSize; i++) {
3334
- let child = cur.child(i);
3335
-
3336
- for (let scan = j, e = Math.min(oldSize, i + 3); scan < e; scan++) {
3337
- if (old.child(scan) == child) {
3338
- j = scan + 1;
3339
- offset += child.nodeSize;
3340
- continue outer;
3341
- }
3342
- }
3343
-
3344
- f(child, offset);
3345
- if (j < oldSize && old.child(j).sameMarkup(child)) changedDescendants(old.child(j), child, offset + 1, f);else child.nodesBetween(0, child.content.size, f, offset + 1);
3346
- offset += child.nodeSize;
3347
- }
3348
- } // :: (EditorState, ?EditorState) → ?Transaction
3349
- // Inspect all tables in the given state's document and return a
3350
- // transaction that fixes them, if necessary. If `oldState` was
3351
- // provided, that is assumed to hold a previous, known-good state,
3352
- // which will be used to avoid re-scanning unchanged parts of the
3353
- // document.
3354
-
3355
-
3356
- function fixTables(state, oldState) {
3357
- let tr,
3358
- check = (node, pos) => {
3359
- if (node.type.spec.tableRole == 'table') tr = fixTable(state, node, pos, tr);
3360
- };
3361
-
3362
- if (!oldState) state.doc.descendants(check);else if (oldState.doc != state.doc) changedDescendants(oldState.doc, state.doc, 0, check);
3363
- return tr;
3364
- } // : (EditorState, Node, number, ?Transaction) → ?Transaction
3365
- // Fix the given table, if necessary. Will append to the transaction
3366
- // it was given, if non-null, or create a new one if necessary.
3367
-
3368
- function fixTable(state, table, tablePos, tr) {
3369
- let map = TableMap.get(table);
3370
- if (!map.problems) return tr;
3371
- if (!tr) tr = state.tr; // Track which rows we must add cells to, so that we can adjust that
3372
- // when fixing collisions.
3373
-
3374
- let mustAdd = [];
3375
-
3376
- for (let i = 0; i < map.height; i++) mustAdd.push(0);
3377
-
3378
- for (let i = 0; i < map.problems.length; i++) {
3379
- let prob = map.problems[i];
3380
-
3381
- if (prob.type == 'collision') {
3382
- let cell = table.nodeAt(prob.pos);
3383
-
3384
- for (let j = 0; j < cell.attrs.rowspan; j++) mustAdd[prob.row + j] += prob.n;
3385
-
3386
- tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, removeColSpan(cell.attrs, cell.attrs.colspan - prob.n, prob.n));
3387
- } else if (prob.type == 'missing') {
3388
- mustAdd[prob.row] += prob.n;
3389
- } else if (prob.type == 'overlong_rowspan') {
3390
- let cell = table.nodeAt(prob.pos);
3391
- tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, setAttr(cell.attrs, 'rowspan', cell.attrs.rowspan - prob.n));
3392
- } else if (prob.type == 'colwidth mismatch') {
3393
- let cell = table.nodeAt(prob.pos);
3394
- tr.setNodeMarkup(tr.mapping.map(tablePos + 1 + prob.pos), null, setAttr(cell.attrs, 'colwidth', prob.colwidth));
3395
- }
3396
- }
3397
-
3398
- let first, last;
3399
-
3400
- for (let i = 0; i < mustAdd.length; i++) if (mustAdd[i]) {
3401
- if (first == null) first = i;
3402
- last = i;
3403
- } // Add the necessary cells, using a heuristic for whether to add the
3404
- // cells at the start or end of the rows (if it looks like a 'bite'
3405
- // was taken out of the table, add cells at the start of the row
3406
- // after the bite. Otherwise add them at the end).
3407
-
3408
-
3409
- for (let i = 0, pos = tablePos + 1; i < map.height; i++) {
3410
- let row = table.child(i);
3411
- let end = pos + row.nodeSize;
3412
- let add = mustAdd[i];
3413
-
3414
- if (add > 0) {
3415
- let tableNodeType = 'cell';
3416
-
3417
- if (row.firstChild) {
3418
- tableNodeType = row.firstChild.type.spec.tableRole;
3419
- }
3420
-
3421
- let nodes = [];
3422
-
3423
- for (let j = 0; j < add; j++) nodes.push(tableNodeTypes(state.schema)[tableNodeType].createAndFill());
3424
-
3425
- let side = (i == 0 || first == i - 1) && last == i ? pos + 1 : end - 1;
3426
- tr.insert(tr.mapping.map(side), nodes);
3427
- }
3428
-
3429
- pos = end;
3430
- }
3431
-
3432
- return tr.setMeta(fixTablesKey, {
3433
- fixTables: true
3434
- });
3435
- }
3436
-
3437
- // This file defines a number of table-related commands.
3438
- // map, table node, and table start offset to the object for
3439
- // convenience.
3440
-
3441
- function selectedRect(state) {
3442
- let sel = state.selection,
3443
- $pos = selectionCell(state);
3444
- let table = $pos.node(-1),
3445
- tableStart = $pos.start(-1),
3446
- map = TableMap.get(table);
3447
- let rect;
3448
- if (sel instanceof CellSelection) rect = map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart);else rect = map.findCell($pos.pos - tableStart);
3449
- rect.tableStart = tableStart;
3450
- rect.map = map;
3451
- rect.table = table;
3452
- return rect;
3453
- } // Add a column at the given position in a table.
3454
-
3455
- function addColumn(tr, {
3456
- map,
3457
- tableStart,
3458
- table
3459
- }, col) {
3460
- let refColumn = col > 0 ? -1 : 0;
3461
- if (columnIsHeader(map, table, col + refColumn)) refColumn = col == 0 || col == map.width ? null : 0;
3462
-
3463
- for (let row = 0; row < map.height; row++) {
3464
- let index = row * map.width + col; // If this position falls inside a col-spanning cell
3465
-
3466
- if (col > 0 && col < map.width && map.map[index - 1] == map.map[index]) {
3467
- let pos = map.map[index],
3468
- cell = table.nodeAt(pos);
3469
- tr.setNodeMarkup(tr.mapping.map(tableStart + pos), null, addColSpan(cell.attrs, col - map.colCount(pos))); // Skip ahead if rowspan > 1
3470
-
3471
- row += cell.attrs.rowspan - 1;
3472
- } else {
3473
- let type = refColumn == null ? tableNodeTypes(table.type.schema).cell : table.nodeAt(map.map[index + refColumn]).type;
3474
- let pos = map.positionAt(row, col, table);
3475
- tr.insert(tr.mapping.map(tableStart + pos), type.createAndFill());
3476
- }
3477
- }
3478
-
3479
- return tr;
3480
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3481
- // Command to add a column before the column with the selection.
3482
-
3483
- function addColumnBefore(state, dispatch) {
3484
- if (!isInTable(state)) return false;
3485
-
3486
- if (dispatch) {
3487
- let rect = selectedRect(state);
3488
- dispatch(addColumn(state.tr, rect, rect.left));
3489
- }
3490
-
3491
- return true;
3492
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3493
- // Command to add a column after the column with the selection.
3494
-
3495
- function addColumnAfter(state, dispatch) {
3496
- if (!isInTable(state)) return false;
3497
-
3498
- if (dispatch) {
3499
- let rect = selectedRect(state);
3500
- dispatch(addColumn(state.tr, rect, rect.right));
3501
- }
3502
-
3503
- return true;
3504
- }
3505
- function removeColumn(tr, {
3506
- map,
3507
- table,
3508
- tableStart
3509
- }, col) {
3510
- let mapStart = tr.mapping.maps.length;
3511
-
3512
- for (let row = 0; row < map.height;) {
3513
- let index = row * map.width + col,
3514
- pos = map.map[index],
3515
- cell = table.nodeAt(pos); // If this is part of a col-spanning cell
3516
-
3517
- if (col > 0 && map.map[index - 1] == pos || col < map.width - 1 && map.map[index + 1] == pos) {
3518
- tr.setNodeMarkup(tr.mapping.slice(mapStart).map(tableStart + pos), null, removeColSpan(cell.attrs, col - map.colCount(pos)));
3519
- } else {
3520
- let start = tr.mapping.slice(mapStart).map(tableStart + pos);
3521
- tr.delete(start, start + cell.nodeSize);
3522
- }
3523
-
3524
- row += cell.attrs.rowspan;
3525
- }
3526
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3527
- // Command function that removes the selected columns from a table.
3528
-
3529
- function deleteColumn(state, dispatch) {
3530
- if (!isInTable(state)) return false;
3531
-
3532
- if (dispatch) {
3533
- let rect = selectedRect(state),
3534
- tr = state.tr;
3535
- if (rect.left == 0 && rect.right == rect.map.width) return false;
3536
-
3537
- for (let i = rect.right - 1;; i--) {
3538
- removeColumn(tr, rect, i);
3539
- if (i == rect.left) break;
3540
- rect.table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
3541
- rect.map = TableMap.get(rect.table);
3542
- }
3543
-
3544
- dispatch(tr);
3545
- }
3546
-
3547
- return true;
3548
- }
3549
- function rowIsHeader(map, table, row) {
3550
- let headerCell = tableNodeTypes(table.type.schema).header_cell;
3551
-
3552
- for (let col = 0; col < map.width; col++) if (table.nodeAt(map.map[col + row * map.width]).type != headerCell) return false;
3553
-
3554
- return true;
3555
- }
3556
- function addRow(tr, {
3557
- map,
3558
- tableStart,
3559
- table
3560
- }, row) {
3561
- let rowPos = tableStart;
3562
-
3563
- for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize;
3564
-
3565
- let cells = [],
3566
- refRow = row > 0 ? -1 : 0;
3567
- if (rowIsHeader(map, table, row + refRow)) refRow = row == 0 || row == map.height ? null : 0;
3568
-
3569
- for (let col = 0, index = map.width * row; col < map.width; col++, index++) {
3570
- // Covered by a rowspan cell
3571
- if (row > 0 && row < map.height && map.map[index] == map.map[index - map.width]) {
3572
- let pos = map.map[index],
3573
- attrs = table.nodeAt(pos).attrs;
3574
- tr.setNodeMarkup(tableStart + pos, null, setAttr(attrs, 'rowspan', attrs.rowspan + 1));
3575
- col += attrs.colspan - 1;
3576
- } else {
3577
- let type = refRow == null ? tableNodeTypes(table.type.schema).cell : table.nodeAt(map.map[index + refRow * map.width]).type;
3578
- cells.push(type.createAndFill());
3579
- }
3580
- }
3581
-
3582
- tr.insert(rowPos, tableNodeTypes(table.type.schema).row.create(null, cells));
3583
- return tr;
3584
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3585
- // Add a table row before the selection.
3586
-
3587
- function addRowBefore(state, dispatch) {
3588
- if (!isInTable(state)) return false;
3589
-
3590
- if (dispatch) {
3591
- let rect = selectedRect(state);
3592
- dispatch(addRow(state.tr, rect, rect.top));
3593
- }
3594
-
3595
- return true;
3596
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3597
- // Add a table row after the selection.
3598
-
3599
- function addRowAfter(state, dispatch) {
3600
- if (!isInTable(state)) return false;
3601
-
3602
- if (dispatch) {
3603
- let rect = selectedRect(state);
3604
- dispatch(addRow(state.tr, rect, rect.bottom));
3605
- }
3606
-
3607
- return true;
3608
- }
3609
- function removeRow(tr, {
3610
- map,
3611
- table,
3612
- tableStart
3613
- }, row) {
3614
- let rowPos = 0;
3615
-
3616
- for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize;
3617
-
3618
- let nextRow = rowPos + table.child(row).nodeSize;
3619
- let mapFrom = tr.mapping.maps.length;
3620
- tr.delete(rowPos + tableStart, nextRow + tableStart);
3621
-
3622
- for (let col = 0, index = row * map.width; col < map.width; col++, index++) {
3623
- let pos = map.map[index];
3624
-
3625
- if (row > 0 && pos == map.map[index - map.width]) {
3626
- // If this cell starts in the row above, simply reduce its rowspan
3627
- let attrs = table.nodeAt(pos).attrs;
3628
- tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + tableStart), null, setAttr(attrs, 'rowspan', attrs.rowspan - 1));
3629
- col += attrs.colspan - 1;
3630
- } else if (row < map.width && pos == map.map[index + map.width]) {
3631
- // Else, if it continues in the row below, it has to be moved down
3632
- let cell = table.nodeAt(pos);
3633
- let copy = cell.type.create(setAttr(cell.attrs, 'rowspan', cell.attrs.rowspan - 1), cell.content);
3634
- let newPos = map.positionAt(row + 1, col, table);
3635
- tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy);
3636
- col += cell.attrs.colspan - 1;
3637
- }
3638
- }
3639
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3640
- // Remove the selected rows from a table.
3641
-
3642
- function deleteRow(state, dispatch) {
3643
- if (!isInTable(state)) return false;
3644
-
3645
- if (dispatch) {
3646
- let rect = selectedRect(state),
3647
- tr = state.tr;
3648
- if (rect.top == 0 && rect.bottom == rect.map.height) return false;
3649
-
3650
- for (let i = rect.bottom - 1;; i--) {
3651
- removeRow(tr, rect, i);
3652
- if (i == rect.top) break;
3653
- rect.table = rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc;
3654
- rect.map = TableMap.get(rect.table);
3655
- }
3656
-
3657
- dispatch(tr);
3658
- }
3659
-
3660
- return true;
3661
- }
3662
-
3663
- function isEmpty(cell) {
3664
- let c = cell.content;
3665
- return c.childCount == 1 && c.firstChild.isTextblock && c.firstChild.childCount == 0;
3666
- }
3667
-
3668
- function cellsOverlapRectangle({
3669
- width,
3670
- height,
3671
- map
3672
- }, rect) {
3673
- let indexTop = rect.top * width + rect.left,
3674
- indexLeft = indexTop;
3675
- let indexBottom = (rect.bottom - 1) * width + rect.left,
3676
- indexRight = indexTop + (rect.right - rect.left - 1);
3677
-
3678
- for (let i = rect.top; i < rect.bottom; i++) {
3679
- if (rect.left > 0 && map[indexLeft] == map[indexLeft - 1] || rect.right < width && map[indexRight] == map[indexRight + 1]) return true;
3680
- indexLeft += width;
3681
- indexRight += width;
3682
- }
3683
-
3684
- for (let i = rect.left; i < rect.right; i++) {
3685
- if (rect.top > 0 && map[indexTop] == map[indexTop - width] || rect.bottom < height && map[indexBottom] == map[indexBottom + width]) return true;
3686
- indexTop++;
3687
- indexBottom++;
3688
- }
3689
-
3690
- return false;
3691
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3692
- // Merge the selected cells into a single cell. Only available when
3693
- // the selected cells' outline forms a rectangle.
3694
-
3695
-
3696
- function mergeCells(state, dispatch) {
3697
- let sel = state.selection;
3698
- if (!(sel instanceof CellSelection) || sel.$anchorCell.pos == sel.$headCell.pos) return false;
3699
- let rect = selectedRect(state),
3700
- {
3701
- map
3702
- } = rect;
3703
- if (cellsOverlapRectangle(map, rect)) return false;
3704
-
3705
- if (dispatch) {
3706
- let tr = state.tr,
3707
- seen = {},
3708
- content = prosemirrorModel.Fragment.empty,
3709
- mergedPos,
3710
- mergedCell;
3711
-
3712
- for (let row = rect.top; row < rect.bottom; row++) {
3713
- for (let col = rect.left; col < rect.right; col++) {
3714
- let cellPos = map.map[row * map.width + col],
3715
- cell = rect.table.nodeAt(cellPos);
3716
- if (seen[cellPos]) continue;
3717
- seen[cellPos] = true;
3718
-
3719
- if (mergedPos == null) {
3720
- mergedPos = cellPos;
3721
- mergedCell = cell;
3722
- } else {
3723
- if (!isEmpty(cell)) content = content.append(cell.content);
3724
- let mapped = tr.mapping.map(cellPos + rect.tableStart);
3725
- tr.delete(mapped, mapped + cell.nodeSize);
3726
- }
3727
- }
3728
- }
3729
-
3730
- tr.setNodeMarkup(mergedPos + rect.tableStart, null, setAttr(addColSpan(mergedCell.attrs, mergedCell.attrs.colspan, rect.right - rect.left - mergedCell.attrs.colspan), 'rowspan', rect.bottom - rect.top));
3731
-
3732
- if (content.size) {
3733
- let end = mergedPos + 1 + mergedCell.content.size;
3734
- let start = isEmpty(mergedCell) ? mergedPos + 1 : end;
3735
- tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content);
3736
- }
3737
-
3738
- tr.setSelection(new CellSelection(tr.doc.resolve(mergedPos + rect.tableStart)));
3739
- dispatch(tr);
3740
- }
3741
-
3742
- return true;
3743
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3744
- // Split a selected cell, whose rowpan or colspan is greater than one,
3745
- // into smaller cells. Use the first cell type for the new cells.
3746
-
3747
- function splitCell(state, dispatch) {
3748
- const nodeTypes = tableNodeTypes(state.schema);
3749
- return splitCellWithType(({
3750
- node
3751
- }) => {
3752
- return nodeTypes[node.type.spec.tableRole];
3753
- })(state, dispatch);
3754
- } // :: (getCellType: ({ row: number, col: number, node: Node}) → NodeType) → (EditorState, dispatch: ?(tr: Transaction)) → bool
3755
- // Split a selected cell, whose rowpan or colspan is greater than one,
3756
- // into smaller cells with the cell type (th, td) returned by getType function.
3757
-
3758
- function splitCellWithType(getCellType) {
3759
- return (state, dispatch) => {
3760
- let sel = state.selection;
3761
- let cellNode, cellPos;
3762
-
3763
- if (!(sel instanceof CellSelection)) {
3764
- cellNode = cellWrapping(sel.$from);
3765
- if (!cellNode) return false;
3766
- cellPos = cellAround(sel.$from).pos;
3767
- } else {
3768
- if (sel.$anchorCell.pos != sel.$headCell.pos) return false;
3769
- cellNode = sel.$anchorCell.nodeAfter;
3770
- cellPos = sel.$anchorCell.pos;
3771
- }
3772
-
3773
- if (cellNode.attrs.colspan == 1 && cellNode.attrs.rowspan == 1) {
3774
- return false;
3775
- }
3776
-
3777
- if (dispatch) {
3778
- let baseAttrs = cellNode.attrs,
3779
- attrs = [],
3780
- colwidth = baseAttrs.colwidth;
3781
- if (baseAttrs.rowspan > 1) baseAttrs = setAttr(baseAttrs, 'rowspan', 1);
3782
- if (baseAttrs.colspan > 1) baseAttrs = setAttr(baseAttrs, 'colspan', 1);
3783
- let rect = selectedRect(state),
3784
- tr = state.tr;
3785
-
3786
- for (let i = 0; i < rect.right - rect.left; i++) attrs.push(colwidth ? setAttr(baseAttrs, 'colwidth', colwidth && colwidth[i] ? [colwidth[i]] : null) : baseAttrs);
3787
-
3788
- let lastCell;
3789
-
3790
- for (let row = rect.top; row < rect.bottom; row++) {
3791
- let pos = rect.map.positionAt(row, rect.left, rect.table);
3792
- if (row == rect.top) pos += cellNode.nodeSize;
3793
-
3794
- for (let col = rect.left, i = 0; col < rect.right; col++, i++) {
3795
- if (col == rect.left && row == rect.top) continue;
3796
- tr.insert(lastCell = tr.mapping.map(pos + rect.tableStart, 1), getCellType({
3797
- node: cellNode,
3798
- row,
3799
- col
3800
- }).createAndFill(attrs[i]));
3801
- }
3802
- }
3803
-
3804
- tr.setNodeMarkup(cellPos, getCellType({
3805
- node: cellNode,
3806
- row: rect.top,
3807
- col: rect.left
3808
- }), attrs[0]);
3809
- if (sel instanceof CellSelection) tr.setSelection(new CellSelection(tr.doc.resolve(sel.$anchorCell.pos), lastCell && tr.doc.resolve(lastCell)));
3810
- dispatch(tr);
3811
- }
3812
-
3813
- return true;
3814
- };
3815
- } // :: (string, any) → (EditorState, dispatch: ?(tr: Transaction)) → bool
3816
- // Returns a command that sets the given attribute to the given value,
3817
- // and is only available when the currently selected cell doesn't
3818
- // already have that attribute set to that value.
3819
-
3820
- function setCellAttr(name, value) {
3821
- return function (state, dispatch) {
3822
- if (!isInTable(state)) return false;
3823
- let $cell = selectionCell(state);
3824
- if ($cell.nodeAfter.attrs[name] === value) return false;
3825
-
3826
- if (dispatch) {
3827
- let tr = state.tr;
3828
- if (state.selection instanceof CellSelection) state.selection.forEachCell((node, pos) => {
3829
- if (node.attrs[name] !== value) tr.setNodeMarkup(pos, null, setAttr(node.attrs, name, value));
3830
- });else tr.setNodeMarkup($cell.pos, null, setAttr($cell.nodeAfter.attrs, name, value));
3831
- dispatch(tr);
3832
- }
3833
-
3834
- return true;
3835
- };
3836
- }
3837
-
3838
- function deprecated_toggleHeader(type) {
3839
- return function (state, dispatch) {
3840
- if (!isInTable(state)) return false;
3841
-
3842
- if (dispatch) {
3843
- let types = tableNodeTypes(state.schema);
3844
- let rect = selectedRect(state),
3845
- tr = state.tr;
3846
- let cells = rect.map.cellsInRect(type == 'column' ? new Rect(rect.left, 0, rect.right, rect.map.height) : type == 'row' ? new Rect(0, rect.top, rect.map.width, rect.bottom) : rect);
3847
- let nodes = cells.map(pos => rect.table.nodeAt(pos));
3848
-
3849
- for (let i = 0; i < cells.length; i++ // Remove headers, if any
3850
- ) if (nodes[i].type == types.header_cell) tr.setNodeMarkup(rect.tableStart + cells[i], types.cell, nodes[i].attrs);
3851
-
3852
- if (tr.steps.length == 0) for (let i = 0; i < cells.length; i++ // No headers removed, add instead
3853
- ) tr.setNodeMarkup(rect.tableStart + cells[i], types.header_cell, nodes[i].attrs);
3854
- dispatch(tr);
3855
- }
3856
-
3857
- return true;
3858
- };
3859
- }
3860
-
3861
- function isHeaderEnabledByType(type, rect, types) {
3862
- // Get cell positions for first row or first column
3863
- const cellPositions = rect.map.cellsInRect({
3864
- left: 0,
3865
- top: 0,
3866
- right: type == 'row' ? rect.map.width : 1,
3867
- bottom: type == 'column' ? rect.map.height : 1
3868
- });
3869
-
3870
- for (let i = 0; i < cellPositions.length; i++) {
3871
- const cell = rect.table.nodeAt(cellPositions[i]);
3872
-
3873
- if (cell && cell.type !== types.header_cell) {
3874
- return false;
3875
- }
3876
- }
3877
-
3878
- return true;
3879
- } // :: (string, ?{ useDeprecatedLogic: bool }) → (EditorState, dispatch: ?(tr: Transaction)) → bool
3880
- // Toggles between row/column header and normal cells (Only applies to first row/column).
3881
- // For deprecated behavior pass `useDeprecatedLogic` in options with true.
3882
-
3883
-
3884
- function toggleHeader(type, options) {
3885
- options = options || {
3886
- useDeprecatedLogic: false
3887
- };
3888
- if (options.useDeprecatedLogic) return deprecated_toggleHeader(type);
3889
- return function (state, dispatch) {
3890
- if (!isInTable(state)) return false;
3891
-
3892
- if (dispatch) {
3893
- let types = tableNodeTypes(state.schema);
3894
- let rect = selectedRect(state),
3895
- tr = state.tr;
3896
- let isHeaderRowEnabled = isHeaderEnabledByType('row', rect, types);
3897
- let isHeaderColumnEnabled = isHeaderEnabledByType('column', rect, types);
3898
- let isHeaderEnabled = type === 'column' ? isHeaderRowEnabled : type === 'row' ? isHeaderColumnEnabled : false;
3899
- let selectionStartsAt = isHeaderEnabled ? 1 : 0;
3900
- let cellsRect = type == 'column' ? new Rect(0, selectionStartsAt, 1, rect.map.height) : type == 'row' ? new Rect(selectionStartsAt, 0, rect.map.width, 1) : rect;
3901
- let newType = type == 'column' ? isHeaderColumnEnabled ? types.cell : types.header_cell : type == 'row' ? isHeaderRowEnabled ? types.cell : types.header_cell : types.cell;
3902
- rect.map.cellsInRect(cellsRect).forEach(relativeCellPos => {
3903
- const cellPos = relativeCellPos + rect.tableStart;
3904
- const cell = tr.doc.nodeAt(cellPos);
3905
-
3906
- if (cell) {
3907
- tr.setNodeMarkup(cellPos, newType, cell.attrs);
3908
- }
3909
- });
3910
- dispatch(tr);
3911
- }
3912
-
3913
- return true;
3914
- };
3915
- } // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3916
- // Toggles whether the selected row contains header cells.
3917
-
3918
- toggleHeader('row', {
3919
- useDeprecatedLogic: true
3920
- }); // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3921
- // Toggles whether the selected column contains header cells.
3922
-
3923
- toggleHeader('column', {
3924
- useDeprecatedLogic: true
3925
- }); // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
3926
- // Toggles whether the selected cells are header cells.
3927
-
3928
- let toggleHeaderCell = toggleHeader('cell', {
3929
- useDeprecatedLogic: true
3930
- });
3931
-
3932
- function findNextCell($cell, dir) {
3933
- if (dir < 0) {
3934
- let before = $cell.nodeBefore;
3935
- if (before) return $cell.pos - before.nodeSize;
3936
-
3937
- for (let row = $cell.index(-1) - 1, rowEnd = $cell.before(); row >= 0; row--) {
3938
- let rowNode = $cell.node(-1).child(row);
3939
- if (rowNode.childCount) return rowEnd - 1 - rowNode.lastChild.nodeSize;
3940
- rowEnd -= rowNode.nodeSize;
3941
- }
3942
- } else {
3943
- if ($cell.index() < $cell.parent.childCount - 1) return $cell.pos + $cell.nodeAfter.nodeSize;
3944
- let table = $cell.node(-1);
3945
-
3946
- for (let row = $cell.indexAfter(-1), rowStart = $cell.after(); row < table.childCount; row++) {
3947
- let rowNode = table.child(row);
3948
- if (rowNode.childCount) return rowStart + 1;
3949
- rowStart += rowNode.nodeSize;
3950
- }
3951
- }
3952
- } // :: (number) → (EditorState, dispatch: ?(tr: Transaction)) → bool
3953
- // Returns a command for selecting the next (direction=1) or previous
3954
- // (direction=-1) cell in a table.
3955
-
3956
-
3957
- function goToNextCell(direction) {
3958
- return function (state, dispatch) {
3959
- if (!isInTable(state)) return false;
3960
- let cell = findNextCell(selectionCell(state), direction);
3961
- if (cell == null) return;
3962
-
3963
- if (dispatch) {
3964
- let $cell = state.doc.resolve(cell);
3965
- dispatch(state.tr.setSelection(prosemirrorState.TextSelection.between($cell, moveCellForward($cell))).scrollIntoView());
3966
- }
3967
-
3968
- return true;
3969
- };
3970
- } // :: (EditorState, ?(tr: Transaction)) → bool
3971
- // Deletes the table around the selection, if any.
3972
-
3973
- function deleteTable(state, dispatch) {
3974
- let $pos = state.selection.$anchor;
3975
-
3976
- for (let d = $pos.depth; d > 0; d--) {
3977
- let node = $pos.node(d);
3978
-
3979
- if (node.type.spec.tableRole == 'table') {
3980
- if (dispatch) dispatch(state.tr.delete($pos.before(d), $pos.after(d)).scrollIntoView());
3981
- return true;
3982
- }
3983
- }
3984
-
3985
- return false;
3986
- }
3987
-
3988
- class TableView$1 {
3989
- constructor(node, cellMinWidth) {
3990
- this.node = node;
3991
- this.cellMinWidth = cellMinWidth;
3992
- this.dom = document.createElement('div');
3993
- this.dom.className = 'tableWrapper';
3994
- this.table = this.dom.appendChild(document.createElement('table'));
3995
- this.colgroup = this.table.appendChild(document.createElement('colgroup'));
3996
- updateColumns$1(node, this.colgroup, this.table, cellMinWidth);
3997
- this.contentDOM = this.table.appendChild(document.createElement('tbody'));
3998
- }
3999
-
4000
- update(node) {
4001
- if (node.type != this.node.type) return false;
4002
- this.node = node;
4003
- updateColumns$1(node, this.colgroup, this.table, this.cellMinWidth);
4004
- return true;
4005
- }
4006
-
4007
- ignoreMutation(record) {
4008
- return record.type == 'attributes' && (record.target == this.table || this.colgroup.contains(record.target));
4009
- }
4010
-
4011
- }
4012
- function updateColumns$1(node, colgroup, table, cellMinWidth, overrideCol, overrideValue) {
4013
- let totalWidth = 0,
4014
- fixedWidth = true;
4015
- let nextDOM = colgroup.firstChild,
4016
- row = node.firstChild;
4017
-
4018
- for (let i = 0, col = 0; i < row.childCount; i++) {
4019
- let {
4020
- colspan,
4021
- colwidth
4022
- } = row.child(i).attrs;
4023
-
4024
- for (let j = 0; j < colspan; j++, col++) {
4025
- let hasWidth = overrideCol == col ? overrideValue : colwidth && colwidth[j];
4026
- let cssWidth = hasWidth ? hasWidth + 'px' : '';
4027
- totalWidth += hasWidth || cellMinWidth;
4028
- if (!hasWidth) fixedWidth = false;
4029
-
4030
- if (!nextDOM) {
4031
- colgroup.appendChild(document.createElement('col')).style.width = cssWidth;
4032
- } else {
4033
- if (nextDOM.style.width != cssWidth) nextDOM.style.width = cssWidth;
4034
- nextDOM = nextDOM.nextSibling;
4035
- }
4036
- }
4037
- }
4038
-
4039
- while (nextDOM) {
4040
- let after = nextDOM.nextSibling;
4041
- nextDOM.parentNode.removeChild(nextDOM);
4042
- nextDOM = after;
4043
- }
4044
-
4045
- if (fixedWidth) {
4046
- table.style.width = totalWidth + 'px';
4047
- table.style.minWidth = '';
4048
- } else {
4049
- table.style.width = '';
4050
- table.style.minWidth = totalWidth + 'px';
4051
- }
4052
- }
4053
-
4054
- const key = new prosemirrorState.PluginKey('tableColumnResizing');
4055
- function columnResizing({
4056
- handleWidth = 5,
4057
- cellMinWidth = 25,
4058
- View = TableView$1,
4059
- lastColumnResizable = true
4060
- } = {}) {
4061
- let plugin = new prosemirrorState.Plugin({
4062
- key,
4063
- state: {
4064
- init(_, state) {
4065
- this.spec.props.nodeViews[tableNodeTypes(state.schema).table.name] = (node, view) => new View(node, cellMinWidth, view);
4066
-
4067
- return new ResizeState(-1, false);
4068
- },
4069
-
4070
- apply(tr, prev) {
4071
- return prev.apply(tr);
4072
- }
4073
-
4074
- },
4075
- props: {
4076
- attributes(state) {
4077
- let pluginState = key.getState(state);
4078
- return pluginState.activeHandle > -1 ? {
4079
- class: 'resize-cursor'
4080
- } : null;
4081
- },
4082
-
4083
- handleDOMEvents: {
4084
- mousemove(view, event) {
4085
- handleMouseMove(view, event, handleWidth, cellMinWidth, lastColumnResizable);
4086
- },
4087
-
4088
- mouseleave(view) {
4089
- handleMouseLeave(view);
4090
- },
4091
-
4092
- mousedown(view, event) {
4093
- handleMouseDown(view, event, cellMinWidth);
4094
- }
4095
-
4096
- },
4097
-
4098
- decorations(state) {
4099
- let pluginState = key.getState(state);
4100
- if (pluginState.activeHandle > -1) return handleDecorations(state, pluginState.activeHandle);
4101
- },
4102
-
4103
- nodeViews: {}
4104
- }
4105
- });
4106
- return plugin;
4107
- }
4108
-
4109
- class ResizeState {
4110
- constructor(activeHandle, dragging) {
4111
- this.activeHandle = activeHandle;
4112
- this.dragging = dragging;
4113
- }
4114
-
4115
- apply(tr) {
4116
- let state = this,
4117
- action = tr.getMeta(key);
4118
- if (action && action.setHandle != null) return new ResizeState(action.setHandle, null);
4119
- if (action && action.setDragging !== undefined) return new ResizeState(state.activeHandle, action.setDragging);
4120
-
4121
- if (state.activeHandle > -1 && tr.docChanged) {
4122
- let handle = tr.mapping.map(state.activeHandle, -1);
4123
- if (!pointsAtCell(tr.doc.resolve(handle))) handle = null;
4124
- state = new ResizeState(handle, state.dragging);
4125
- }
4126
-
4127
- return state;
4128
- }
4129
-
4130
- }
4131
-
4132
- function handleMouseMove(view, event, handleWidth, cellMinWidth, lastColumnResizable) {
4133
- let pluginState = key.getState(view.state);
4134
-
4135
- if (!pluginState.dragging) {
4136
- let target = domCellAround(event.target),
4137
- cell = -1;
4138
-
4139
- if (target) {
4140
- let {
4141
- left,
4142
- right
4143
- } = target.getBoundingClientRect();
4144
- if (event.clientX - left <= handleWidth) cell = edgeCell(view, event, 'left');else if (right - event.clientX <= handleWidth) cell = edgeCell(view, event, 'right');
4145
- }
4146
-
4147
- if (cell != pluginState.activeHandle) {
4148
- if (!lastColumnResizable && cell !== -1) {
4149
- let $cell = view.state.doc.resolve(cell);
4150
- let table = $cell.node(-1),
4151
- map = TableMap.get(table),
4152
- start = $cell.start(-1);
4153
- let col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs.colspan - 1;
4154
-
4155
- if (col == map.width - 1) {
4156
- return;
4157
- }
4158
- }
4159
-
4160
- updateHandle(view, cell);
4161
- }
4162
- }
4163
- }
4164
-
4165
- function handleMouseLeave(view) {
4166
- let pluginState = key.getState(view.state);
4167
- if (pluginState.activeHandle > -1 && !pluginState.dragging) updateHandle(view, -1);
4168
- }
4169
-
4170
- function handleMouseDown(view, event, cellMinWidth) {
4171
- let pluginState = key.getState(view.state);
4172
- if (pluginState.activeHandle == -1 || pluginState.dragging) return false;
4173
- let cell = view.state.doc.nodeAt(pluginState.activeHandle);
4174
- let width = currentColWidth(view, pluginState.activeHandle, cell.attrs);
4175
- view.dispatch(view.state.tr.setMeta(key, {
4176
- setDragging: {
4177
- startX: event.clientX,
4178
- startWidth: width
4179
- }
4180
- }));
4181
-
4182
- function finish(event) {
4183
- window.removeEventListener('mouseup', finish);
4184
- window.removeEventListener('mousemove', move);
4185
- let pluginState = key.getState(view.state);
4186
-
4187
- if (pluginState.dragging) {
4188
- updateColumnWidth(view, pluginState.activeHandle, draggedWidth(pluginState.dragging, event, cellMinWidth));
4189
- view.dispatch(view.state.tr.setMeta(key, {
4190
- setDragging: null
4191
- }));
4192
- }
4193
- }
4194
-
4195
- function move(event) {
4196
- if (!event.which) return finish(event);
4197
- let pluginState = key.getState(view.state);
4198
- let dragged = draggedWidth(pluginState.dragging, event, cellMinWidth);
4199
- displayColumnWidth(view, pluginState.activeHandle, dragged, cellMinWidth);
4200
- }
4201
-
4202
- window.addEventListener('mouseup', finish);
4203
- window.addEventListener('mousemove', move);
4204
- event.preventDefault();
4205
- return true;
4206
- }
4207
-
4208
- function currentColWidth(view, cellPos, {
4209
- colspan,
4210
- colwidth
4211
- }) {
4212
- let width = colwidth && colwidth[colwidth.length - 1];
4213
- if (width) return width;
4214
- let dom = view.domAtPos(cellPos);
4215
- let node = dom.node.childNodes[dom.offset];
4216
- let domWidth = node.offsetWidth,
4217
- parts = colspan;
4218
- if (colwidth) for (let i = 0; i < colspan; i++) if (colwidth[i]) {
4219
- domWidth -= colwidth[i];
4220
- parts--;
4221
- }
4222
- return domWidth / parts;
4223
- }
4224
-
4225
- function domCellAround(target) {
4226
- while (target && target.nodeName != 'TD' && target.nodeName != 'TH') target = target.classList.contains('ProseMirror') ? null : target.parentNode;
4227
-
4228
- return target;
4229
- }
4230
-
4231
- function edgeCell(view, event, side) {
4232
- let found = view.posAtCoords({
4233
- left: event.clientX,
4234
- top: event.clientY
4235
- });
4236
- if (!found) return -1;
4237
- let {
4238
- pos
4239
- } = found;
4240
- let $cell = cellAround(view.state.doc.resolve(pos));
4241
- if (!$cell) return -1;
4242
- if (side == 'right') return $cell.pos;
4243
- let map = TableMap.get($cell.node(-1)),
4244
- start = $cell.start(-1);
4245
- let index = map.map.indexOf($cell.pos - start);
4246
- return index % map.width == 0 ? -1 : start + map.map[index - 1];
4247
- }
4248
-
4249
- function draggedWidth(dragging, event, cellMinWidth) {
4250
- let offset = event.clientX - dragging.startX;
4251
- return Math.max(cellMinWidth, dragging.startWidth + offset);
4252
- }
4253
-
4254
- function updateHandle(view, value) {
4255
- view.dispatch(view.state.tr.setMeta(key, {
4256
- setHandle: value
4257
- }));
4258
- }
4259
-
4260
- function updateColumnWidth(view, cell, width) {
4261
- let $cell = view.state.doc.resolve(cell);
4262
- let table = $cell.node(-1),
4263
- map = TableMap.get(table),
4264
- start = $cell.start(-1);
4265
- let col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs.colspan - 1;
4266
- let tr = view.state.tr;
4267
-
4268
- for (let row = 0; row < map.height; row++) {
4269
- let mapIndex = row * map.width + col; // Rowspanning cell that has already been handled
4270
-
4271
- if (row && map.map[mapIndex] == map.map[mapIndex - map.width]) continue;
4272
- let pos = map.map[mapIndex],
4273
- {
4274
- attrs
4275
- } = table.nodeAt(pos);
4276
- let index = attrs.colspan == 1 ? 0 : col - map.colCount(pos);
4277
- if (attrs.colwidth && attrs.colwidth[index] == width) continue;
4278
- let colwidth = attrs.colwidth ? attrs.colwidth.slice() : zeroes(attrs.colspan);
4279
- colwidth[index] = width;
4280
- tr.setNodeMarkup(start + pos, null, setAttr(attrs, 'colwidth', colwidth));
4281
- }
4282
-
4283
- if (tr.docChanged) view.dispatch(tr);
4284
- }
4285
-
4286
- function displayColumnWidth(view, cell, width, cellMinWidth) {
4287
- let $cell = view.state.doc.resolve(cell);
4288
- let table = $cell.node(-1),
4289
- start = $cell.start(-1);
4290
- let col = TableMap.get(table).colCount($cell.pos - start) + $cell.nodeAfter.attrs.colspan - 1;
4291
- let dom = view.domAtPos($cell.start(-1)).node;
4292
-
4293
- while (dom.nodeName != 'TABLE') dom = dom.parentNode;
4294
-
4295
- updateColumns$1(table, dom.firstChild, dom, cellMinWidth, col, width);
4296
- }
4297
-
4298
- function zeroes(n) {
4299
- let result = [];
4300
-
4301
- for (let i = 0; i < n; i++) result.push(0);
4302
-
4303
- return result;
4304
- }
4305
-
4306
- function handleDecorations(state, cell) {
4307
- let decorations = [];
4308
- let $cell = state.doc.resolve(cell);
4309
- let table = $cell.node(-1),
4310
- map = TableMap.get(table),
4311
- start = $cell.start(-1);
4312
- let col = map.colCount($cell.pos - start) + $cell.nodeAfter.attrs.colspan;
4313
-
4314
- for (let row = 0; row < map.height; row++) {
4315
- let index = col + row * map.width - 1; // For positions that are have either a different cell or the end
4316
- // of the table to their right, and either the top of the table or
4317
- // a different cell above them, add a decoration
4318
-
4319
- if ((col == map.width || map.map[index] != map.map[index + 1]) && (row == 0 || map.map[index - 1] != map.map[index - 1 - map.width])) {
4320
- let cellPos = map.map[index];
4321
- let pos = start + cellPos + table.nodeAt(cellPos).nodeSize - 1;
4322
- let dom = document.createElement('div');
4323
- dom.className = 'column-resize-handle';
4324
- decorations.push(prosemirrorView.Decoration.widget(pos, dom));
4325
- }
4326
- }
4327
-
4328
- return prosemirrorView.DecorationSet.create(state.doc, decorations);
4329
- }
4330
-
4331
- // This file defines a plugin that handles the drawing of cell
4332
- //
4333
- // Creates a [plugin](http://prosemirror.net/docs/ref/#state.Plugin)
4334
- // that, when added to an editor, enables cell-selection, handles
4335
- // cell-based copy/paste, and makes sure tables stay well-formed (each
4336
- // row has the same width, and cells don't overlap).
4337
- //
4338
- // You should probably put this plugin near the end of your array of
4339
- // plugins, since it handles mouse and arrow key events in tables
4340
- // rather broadly, and other plugins, like the gap cursor or the
4341
- // column-width dragging plugin, might want to get a turn first to
4342
- // perform more specific behavior.
4343
-
4344
- function tableEditing({
4345
- allowTableNodeSelection = false
4346
- } = {}) {
4347
- return new prosemirrorState.Plugin({
4348
- key: key$1,
4349
- // This piece of state is used to remember when a mouse-drag
4350
- // cell-selection is happening, so that it can continue even as
4351
- // transactions (which might move its anchor cell) come in.
4352
- state: {
4353
- init() {
4354
- return null;
4355
- },
4356
-
4357
- apply(tr, cur) {
4358
- let set = tr.getMeta(key$1);
4359
- if (set != null) return set == -1 ? null : set;
4360
- if (cur == null || !tr.docChanged) return cur;
4361
- let {
4362
- deleted,
4363
- pos
4364
- } = tr.mapping.mapResult(cur);
4365
- return deleted ? null : pos;
4366
- }
4367
-
4368
- },
4369
- props: {
4370
- decorations: drawCellSelection,
4371
- handleDOMEvents: {
4372
- mousedown: handleMouseDown$1
4373
- },
4374
-
4375
- createSelectionBetween(view) {
4376
- if (key$1.getState(view.state) != null) return view.state.selection;
4377
- },
4378
-
4379
- handleTripleClick,
4380
- handleKeyDown,
4381
- handlePaste
4382
- },
4383
-
4384
- appendTransaction(_, oldState, state) {
4385
- return normalizeSelection(state, fixTables(state, oldState), allowTableNodeSelection);
4386
- }
4387
-
4388
- });
4389
- }
4390
8
 
4391
9
  function updateColumns(node, colgroup, table, cellMinWidth, overrideCol, overrideValue) {
4392
10
  let totalWidth = 0;
@@ -4497,7 +115,7 @@ function createTable(schema, rowsCount, colsCount, withHeaderRow, cellContent) {
4497
115
  }
4498
116
 
4499
117
  function isCellSelection(value) {
4500
- return value instanceof CellSelection;
118
+ return value instanceof prosemirrorTables.CellSelection;
4501
119
  }
4502
120
 
4503
121
  const deleteTableWhenAllCellsSelected = ({ editor }) => {
@@ -4565,65 +183,65 @@ const Table = core.Node.create({
4565
183
  return true;
4566
184
  },
4567
185
  addColumnBefore: () => ({ state, dispatch }) => {
4568
- return addColumnBefore(state, dispatch);
186
+ return prosemirrorTables.addColumnBefore(state, dispatch);
4569
187
  },
4570
188
  addColumnAfter: () => ({ state, dispatch }) => {
4571
- return addColumnAfter(state, dispatch);
189
+ return prosemirrorTables.addColumnAfter(state, dispatch);
4572
190
  },
4573
191
  deleteColumn: () => ({ state, dispatch }) => {
4574
- return deleteColumn(state, dispatch);
192
+ return prosemirrorTables.deleteColumn(state, dispatch);
4575
193
  },
4576
194
  addRowBefore: () => ({ state, dispatch }) => {
4577
- return addRowBefore(state, dispatch);
195
+ return prosemirrorTables.addRowBefore(state, dispatch);
4578
196
  },
4579
197
  addRowAfter: () => ({ state, dispatch }) => {
4580
- return addRowAfter(state, dispatch);
198
+ return prosemirrorTables.addRowAfter(state, dispatch);
4581
199
  },
4582
200
  deleteRow: () => ({ state, dispatch }) => {
4583
- return deleteRow(state, dispatch);
201
+ return prosemirrorTables.deleteRow(state, dispatch);
4584
202
  },
4585
203
  deleteTable: () => ({ state, dispatch }) => {
4586
- return deleteTable(state, dispatch);
204
+ return prosemirrorTables.deleteTable(state, dispatch);
4587
205
  },
4588
206
  mergeCells: () => ({ state, dispatch }) => {
4589
- return mergeCells(state, dispatch);
207
+ return prosemirrorTables.mergeCells(state, dispatch);
4590
208
  },
4591
209
  splitCell: () => ({ state, dispatch }) => {
4592
- return splitCell(state, dispatch);
210
+ return prosemirrorTables.splitCell(state, dispatch);
4593
211
  },
4594
212
  toggleHeaderColumn: () => ({ state, dispatch }) => {
4595
- return toggleHeader('column')(state, dispatch);
213
+ return prosemirrorTables.toggleHeader('column')(state, dispatch);
4596
214
  },
4597
215
  toggleHeaderRow: () => ({ state, dispatch }) => {
4598
- return toggleHeader('row')(state, dispatch);
216
+ return prosemirrorTables.toggleHeader('row')(state, dispatch);
4599
217
  },
4600
218
  toggleHeaderCell: () => ({ state, dispatch }) => {
4601
- return toggleHeaderCell(state, dispatch);
219
+ return prosemirrorTables.toggleHeaderCell(state, dispatch);
4602
220
  },
4603
221
  mergeOrSplit: () => ({ state, dispatch }) => {
4604
- if (mergeCells(state, dispatch)) {
222
+ if (prosemirrorTables.mergeCells(state, dispatch)) {
4605
223
  return true;
4606
224
  }
4607
- return splitCell(state, dispatch);
225
+ return prosemirrorTables.splitCell(state, dispatch);
4608
226
  },
4609
227
  setCellAttribute: (name, value) => ({ state, dispatch }) => {
4610
- return setCellAttr(name, value)(state, dispatch);
228
+ return prosemirrorTables.setCellAttr(name, value)(state, dispatch);
4611
229
  },
4612
230
  goToNextCell: () => ({ state, dispatch }) => {
4613
- return goToNextCell(1)(state, dispatch);
231
+ return prosemirrorTables.goToNextCell(1)(state, dispatch);
4614
232
  },
4615
233
  goToPreviousCell: () => ({ state, dispatch }) => {
4616
- return goToNextCell(-1)(state, dispatch);
234
+ return prosemirrorTables.goToNextCell(-1)(state, dispatch);
4617
235
  },
4618
236
  fixTables: () => ({ state, dispatch }) => {
4619
237
  if (dispatch) {
4620
- fixTables(state);
238
+ prosemirrorTables.fixTables(state);
4621
239
  }
4622
240
  return true;
4623
241
  },
4624
242
  setCellSelection: position => ({ tr, dispatch }) => {
4625
243
  if (dispatch) {
4626
- const selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell);
244
+ const selection = prosemirrorTables.CellSelection.create(tr.doc, position.anchorCell, position.headCell);
4627
245
  // @ts-ignore
4628
246
  tr.setSelection(selection);
4629
247
  }
@@ -4656,7 +274,7 @@ const Table = core.Node.create({
4656
274
  addProseMirrorPlugins() {
4657
275
  const isResizable = this.options.resizable && this.editor.isEditable;
4658
276
  return [
4659
- ...(isResizable ? [columnResizing({
277
+ ...(isResizable ? [prosemirrorTables.columnResizing({
4660
278
  handleWidth: this.options.handleWidth,
4661
279
  cellMinWidth: this.options.cellMinWidth,
4662
280
  View: this.options.View,
@@ -4664,7 +282,7 @@ const Table = core.Node.create({
4664
282
  // @ts-ignore (incorrect type)
4665
283
  lastColumnResizable: this.options.lastColumnResizable,
4666
284
  })] : []),
4667
- tableEditing({
285
+ prosemirrorTables.tableEditing({
4668
286
  allowTableNodeSelection: this.options.allowTableNodeSelection,
4669
287
  }),
4670
288
  ];