mirror of https://github.com/halo-dev/halo
fix: code block content insertion location error (#5737)
#### What type of PR is this? /kind bug /area editor /milestone 2.15.x #### What this PR does / why we need it: 在编写多行文本后,粘贴代码块时,会出现粘贴的内容插入错误,其与代码块分割开。 [例如 #5736 中的示例所示](https://github.com/halo-dev/halo/assets/44745967/4b1ef8dc-60bf-47fd-b64d-23b0d6537d9e) 在本 PR 中,在创建 CodeBlock 时,将 Text 转为 `TextNode` 后,一同传入作为 `CodeBlock` 的 content。 另外为了保证插入代码块之后,光标处于代码块中,将会从插入位置的 from 开始往文档顶部搜索。 #### How to test it? 测试示例中的场景下,代码块插入是否正常。 测试在代码块前后放入其他代码块或者其他块,插入代码块后光标是否在代码块中。 #### Which issue(s) this PR fixes: Fixes #5736 #### Does this PR introduce a user-facing change? ```release-note 修复默认编辑器中粘贴代码块会出现错行的问题 ```pull/5655/head
parent
410a7557f9
commit
fdc2453cc8
|
@ -6,7 +6,13 @@ import {
|
|||
findParentNode,
|
||||
VueNodeViewRenderer,
|
||||
} from "@/tiptap/vue-3";
|
||||
import { EditorState, TextSelection, type Transaction } from "@/tiptap/pm";
|
||||
import {
|
||||
EditorState,
|
||||
Plugin,
|
||||
PluginKey,
|
||||
TextSelection,
|
||||
type Transaction,
|
||||
} from "@/tiptap/pm";
|
||||
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
|
||||
import type { CodeBlockLowlightOptions } from "@tiptap/extension-code-block-lowlight";
|
||||
import CodeBlockViewRenderer from "./CodeBlockViewRenderer.vue";
|
||||
|
@ -237,4 +243,70 @@ export default CodeBlockLowlight.extend<
|
|||
},
|
||||
};
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
// Solve the paste problem. Because the upstream has not been
|
||||
// able to deal with this problem for a long time, it is
|
||||
// handled manually locally.
|
||||
// see: https://github.com/ueberdosis/tiptap/pull/3606
|
||||
new Plugin({
|
||||
key: new PluginKey("codeBlockVSCodeHandlerFixPaste"),
|
||||
props: {
|
||||
handlePaste: (view, event) => {
|
||||
if (!event.clipboardData) {
|
||||
return false;
|
||||
}
|
||||
// don’t create a new code block within code blocks
|
||||
if (this.editor.isActive(this.type.name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const text = event.clipboardData.getData("text/plain");
|
||||
const vscode = event.clipboardData.getData("vscode-editor-data");
|
||||
const vscodeData = vscode ? JSON.parse(vscode) : undefined;
|
||||
const language = vscodeData?.mode;
|
||||
|
||||
if (!text || !language) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { tr, schema } = view.state;
|
||||
|
||||
// add text to code block
|
||||
// strip carriage return chars from text pasted as code
|
||||
// see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd
|
||||
const contentTextNode = schema.text(text.replace(/\r\n?/g, "\n"));
|
||||
|
||||
// create an empty code block
|
||||
tr.replaceSelectionWith(
|
||||
this.type.create({ language }, contentTextNode)
|
||||
);
|
||||
|
||||
const { selection } = tr;
|
||||
// Whether the current position is code block, if not, move forward to code block.
|
||||
let codeBlockPos = Math.max(0, selection.from - 1);
|
||||
while (
|
||||
codeBlockPos > 0 &&
|
||||
tr.doc.resolve(codeBlockPos).parent.type.name !== this.type.name
|
||||
) {
|
||||
codeBlockPos--;
|
||||
}
|
||||
// put cursor inside the newly created code block
|
||||
tr.setSelection(TextSelection.near(tr.doc.resolve(codeBlockPos)));
|
||||
|
||||
// store meta information
|
||||
// this is useful for other plugins that depends on the paste event
|
||||
// like the paste rule plugin
|
||||
tr.setMeta("paste", true);
|
||||
|
||||
view.dispatch(tr);
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
}),
|
||||
...(this.parent?.() || []),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue