fix(move_block): Make the object movable

This commit is contained in:
SiriusXT 2025-06-09 10:04:10 +08:00
parent be447b4139
commit a23b0c5ec9

View File

@ -8,24 +8,41 @@ export default class MoveBlockUpDownPlugin extends Plugin {
init() {
const editor = this.editor;
editor.config.define('moveBlockUp', {
keystroke: ['ctrl+arrowup', 'alt+arrowup'],
});
editor.config.define('moveBlockDown', {
keystroke: ['ctrl+arrowdown', 'alt+arrowdown'],
});
editor.commands.add('moveBlockUp', new MoveBlockUpCommand(editor));
editor.commands.add('moveBlockDown', new MoveBlockDownCommand(editor));
for (const keystroke of editor.config.get('moveBlockUp.keystroke') ?? []) {
editor.keystrokes.set(keystroke, 'moveBlockUp');
}
for (const keystroke of editor.config.get('moveBlockDown.keystroke') ?? []) {
editor.keystrokes.set(keystroke, 'moveBlockDown');
}
// Use native DOM capturing to intercept Ctrl/Alt + ↑/↓,
// as plugin-level keystroke handling may fail when the selection is near an object.
this.bindMoveBlockShortcuts(editor);
}
bindMoveBlockShortcuts(editor: any) {
editor.editing.view.once('render', () => {
const domRoot = editor.editing.view.getDomRoot();
if (!domRoot) return;
const handleKeydown = (e: KeyboardEvent) => {
const keyMap = {
ArrowUp: 'moveBlockUp',
ArrowDown: 'moveBlockDown'
};
const command = keyMap[e.key];
const isCtrl = e.ctrlKey || e.metaKey;
const hasModifier = (isCtrl || e.altKey) && !(isCtrl && e.altKey);
if (command && hasModifier) {
e.preventDefault();
e.stopImmediatePropagation();
editor.execute(command);
}
};
domRoot.addEventListener('keydown', handleKeydown, { capture: true });
});
}
}
abstract class MoveBlockUpDownCommand extends Command {
@ -49,10 +66,10 @@ abstract class MoveBlockUpDownCommand extends Command {
: [...selectedBlocks].reverse();
// Store selection offsets
const offsets = [
model.document.selection.getFirstPosition()?.offset,
model.document.selection.getLastPosition()?.offset
];
const firstBlock = selectedBlocks[0];
const lastBlock = selectedBlocks[selectedBlocks.length - 1];
const startOffset = model.document.selection.getFirstPosition()?.offset ?? 0;
const endOffset = model.document.selection.getLastPosition()?.offset ?? 0;
model.change((writer) => {
// Move blocks
@ -65,19 +82,36 @@ abstract class MoveBlockUpDownCommand extends Command {
}
// Restore selection to all items if many have been moved
const range = writer.createRange(
writer.createPositionAt(selectedBlocks[0], offsets[0]),
writer.createPositionAt(
selectedBlocks[selectedBlocks.length - 1], offsets[1]));
writer.setSelection(range);
if (
startOffset <= (firstBlock.maxOffset ?? Infinity) &&
endOffset <= (lastBlock.maxOffset ?? Infinity)
) {
writer.setSelection(
writer.createRange(
writer.createPositionAt(firstBlock, startOffset),
writer.createPositionAt(lastBlock, endOffset)
)
);
}
this.scrollToSelection();
});
}
getSelectedBlocks(selection: DocumentSelection) {
return [...selection.getSelectedBlocks()];
}
getSelectedBlocks(selection: DocumentSelection) {
const blocks = [...selection.getSelectedBlocks()];
// If the selected block is an object, such as a block quote or admonition, return the entire block.
if (blocks.length === 1) {
const block = blocks[0];
const parent = block.parent;
if (!parent?.name?.startsWith('$')) {
return [parent as Element];
}
}
return blocks;
}
scrollToSelection() {
// Ensure scroll happens in sync with DOM updates