Select entire link when clicking and editing
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
Node,
|
Node,
|
||||||
Mark as ProsemirrorMark,
|
Mark as ProsemirrorMark,
|
||||||
} from "prosemirror-model";
|
} from "prosemirror-model";
|
||||||
import { Command, EditorState, Plugin } from "prosemirror-state";
|
import { Command, EditorState, Plugin, TextSelection } from "prosemirror-state";
|
||||||
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
|
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
@@ -194,15 +194,50 @@ export default class Link extends Mark {
|
|||||||
return DecorationSet.create(state.doc, decorations);
|
return DecorationSet.create(state.doc, decorations);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClick = (view: EditorView, pos: number) => {
|
||||||
|
const { doc, tr } = view.state;
|
||||||
|
const range = getMarkRange(
|
||||||
|
doc.resolve(pos),
|
||||||
|
this.editor.schema.marks.link
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!range || range.from === pos || range.to === pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const $start = doc.resolve(range.from);
|
||||||
|
const $end = doc.resolve(range.to);
|
||||||
|
tr.setSelection(new TextSelection($start, $end));
|
||||||
|
|
||||||
|
view.dispatch(tr);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
// Failed to set selection
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const plugin: Plugin = new Plugin({
|
const plugin: Plugin = new Plugin({
|
||||||
state: {
|
state: {
|
||||||
init: (config, state) => getLinkDecorations(state),
|
init: (_config, state) => getLinkDecorations(state),
|
||||||
apply: (tr, decorationSet, _oldState, newState) =>
|
apply: (tr, decorationSet, _oldState, newState) =>
|
||||||
tr.docChanged ? getLinkDecorations(newState) : decorationSet,
|
tr.docChanged ? getLinkDecorations(newState) : decorationSet,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
decorations: (state: EditorState) => plugin.getState(state),
|
decorations: (state: EditorState) => plugin.getState(state),
|
||||||
handleDOMEvents: {
|
handleDOMEvents: {
|
||||||
|
contextmenu: (view: EditorView, event: MouseEvent) => {
|
||||||
|
const result = view.posAtCoords({
|
||||||
|
left: event.clientX,
|
||||||
|
top: event.clientY,
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
return handleClick(view, result.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
mousedown: (view: EditorView, event: MouseEvent) => {
|
mousedown: (view: EditorView, event: MouseEvent) => {
|
||||||
const target = (event.target as HTMLElement)?.closest("a");
|
const target = (event.target as HTMLElement)?.closest("a");
|
||||||
if (!(target instanceof HTMLAnchorElement) || event.button !== 0) {
|
if (!(target instanceof HTMLAnchorElement) || event.button !== 0) {
|
||||||
@@ -235,6 +270,16 @@ export default class Link extends Mark {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = view.posAtCoords({
|
||||||
|
left: event.clientX,
|
||||||
|
top: event.clientY,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result && handleClick(view, result.pos)) {
|
||||||
|
event.preventDefault();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
click: (view: EditorView, event: MouseEvent) => {
|
click: (view: EditorView, event: MouseEvent) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user