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,23 +8,40 @@ export default class MoveBlockUpDownPlugin extends Plugin {
init() { init() {
const editor = this.editor; 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('moveBlockUp', new MoveBlockUpCommand(editor));
editor.commands.add('moveBlockDown', new MoveBlockDownCommand(editor)); editor.commands.add('moveBlockDown', new MoveBlockDownCommand(editor));
for (const keystroke of editor.config.get('moveBlockUp.keystroke') ?? []) { // Use native DOM capturing to intercept Ctrl/Alt + ↑/↓,
editor.keystrokes.set(keystroke, 'moveBlockUp'); // as plugin-level keystroke handling may fail when the selection is near an object.
} this.bindMoveBlockShortcuts(editor);
for (const keystroke of editor.config.get('moveBlockDown.keystroke') ?? []) {
editor.keystrokes.set(keystroke, 'moveBlockDown');
}
} }
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 });
});
}
} }
@ -49,10 +66,10 @@ abstract class MoveBlockUpDownCommand extends Command {
: [...selectedBlocks].reverse(); : [...selectedBlocks].reverse();
// Store selection offsets // Store selection offsets
const offsets = [ const firstBlock = selectedBlocks[0];
model.document.selection.getFirstPosition()?.offset, const lastBlock = selectedBlocks[selectedBlocks.length - 1];
model.document.selection.getLastPosition()?.offset const startOffset = model.document.selection.getFirstPosition()?.offset ?? 0;
]; const endOffset = model.document.selection.getLastPosition()?.offset ?? 0;
model.change((writer) => { model.change((writer) => {
// Move blocks // Move blocks
@ -65,19 +82,36 @@ abstract class MoveBlockUpDownCommand extends Command {
} }
// Restore selection to all items if many have been moved // Restore selection to all items if many have been moved
const range = writer.createRange( if (
writer.createPositionAt(selectedBlocks[0], offsets[0]), startOffset <= (firstBlock.maxOffset ?? Infinity) &&
writer.createPositionAt( endOffset <= (lastBlock.maxOffset ?? Infinity)
selectedBlocks[selectedBlocks.length - 1], offsets[1])); ) {
writer.setSelection(range); writer.setSelection(
writer.createRange(
writer.createPositionAt(firstBlock, startOffset),
writer.createPositionAt(lastBlock, endOffset)
)
);
}
this.scrollToSelection(); this.scrollToSelection();
}); });
} }
getSelectedBlocks(selection: DocumentSelection) { getSelectedBlocks(selection: DocumentSelection) {
return [...selection.getSelectedBlocks()]; 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() { scrollToSelection() {
// Ensure scroll happens in sync with DOM updates // Ensure scroll happens in sync with DOM updates