Skip to content

Commit 3a56a16

Browse files
committed
fix: moving tables/blockQuote
1 parent e6c2f72 commit 3a56a16

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

packages/ckeditor5/src/plugins/move_block_updown.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
* https://github.com/TriliumNext/Notes/issues/1002
33
*/
44

5-
import { Command, DocumentSelection, Element, Node, Plugin } from 'ckeditor5';
6-
5+
import { Command, DocumentSelection, Element, Node, Plugin, Range } from 'ckeditor5';
76
export default class MoveBlockUpDownPlugin extends Plugin {
87

98
init() {
@@ -81,36 +80,54 @@ abstract class MoveBlockUpDownCommand extends Command {
8180
}
8281
}
8382

84-
// Restore selection to all items if many have been moved
85-
if (
86-
startOffset <= (firstBlock.maxOffset ?? Infinity) &&
87-
endOffset <= (lastBlock.maxOffset ?? Infinity)
88-
) {
89-
writer.setSelection(
90-
writer.createRange(
91-
writer.createPositionAt(firstBlock, startOffset),
92-
writer.createPositionAt(lastBlock, endOffset)
93-
)
83+
// Restore selection
84+
let range: Range;
85+
const maxStart = firstBlock.maxOffset ?? startOffset;
86+
const maxEnd = lastBlock.maxOffset ?? endOffset;
87+
// If original offsets valid within bounds, restore partial selection
88+
if (startOffset <= maxStart && endOffset <= maxEnd) {
89+
const clampedStart = Math.min(startOffset, maxStart);
90+
const clampedEnd = Math.min(endOffset, maxEnd);
91+
range = writer.createRange(
92+
writer.createPositionAt(firstBlock, clampedStart),
93+
writer.createPositionAt(lastBlock, clampedEnd)
94+
);
95+
} else { // Fallback: select entire moved blocks (handles tables)
96+
range = writer.createRange(
97+
writer.createPositionBefore(firstBlock),
98+
writer.createPositionAfter(lastBlock)
9499
);
95100
}
101+
writer.setSelection(range);
102+
this.editor.editing.view.focus();
96103

97104
this.scrollToSelection();
98-
});
105+
});
99106
}
100107

101108
getSelectedBlocks(selection: DocumentSelection) {
102109
const blocks = [...selection.getSelectedBlocks()];
110+
const resolved: Element[] = [];
111+
112+
// Selects elements (such as Mermaid) when there are no blocks
113+
if (!blocks.length) {
114+
const selectedObj = selection.getSelectedElement();
115+
if (selectedObj) {
116+
return [selectedObj];
117+
}
118+
}
103119

104-
// If the selected block is an object, such as a block quote or admonition, return the entire block.
105-
if (blocks.length === 1) {
106-
const block = blocks[0];
107-
const parent = block.parent;
108-
if (!parent?.name?.startsWith('$')) {
109-
return [parent as Element];
120+
for (const block of blocks) {
121+
let el: Element = block;
122+
// Traverse up until the parent is the root ($root) or there is no parent
123+
while (el.parent && el.parent.name !== '$root') {
124+
el = el.parent as Element;
110125
}
126+
resolved.push(el);
111127
}
112128

113-
return blocks;
129+
// Deduplicate adjacent duplicates (e.g., nested selections resolving to same block)
130+
return resolved.filter((blk, idx) => idx === 0 || blk !== resolved[idx - 1]);
114131
}
115132

116133
scrollToSelection() {

0 commit comments

Comments
 (0)