Initial
This commit is contained in:
86
resources/app/common/prosemirror/content-link-plugin.mjs
Normal file
86
resources/app/common/prosemirror/content-link-plugin.mjs
Normal file
@@ -0,0 +1,86 @@
|
||||
import ProseMirrorPlugin from "./plugin.mjs";
|
||||
import {Plugin} from "prosemirror-state";
|
||||
|
||||
/**
|
||||
* A class responsible for handling the dropping of Documents onto the editor and creating content links for them.
|
||||
* @extends {ProseMirrorPlugin}
|
||||
*/
|
||||
export default class ProseMirrorContentLinkPlugin extends ProseMirrorPlugin {
|
||||
/**
|
||||
* @typedef {object} ProseMirrorContentLinkOptions
|
||||
* @property {ClientDocument} [document] The parent document housing this editor.
|
||||
* @property {boolean} [relativeLinks=false] Whether to generate links relative to the parent document.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Schema} schema The ProseMirror schema.
|
||||
* @param {ProseMirrorContentLinkOptions} options Additional options to configure the plugin's behaviour.
|
||||
*/
|
||||
constructor(schema, {document, relativeLinks=false}={}) {
|
||||
super(schema);
|
||||
|
||||
if ( relativeLinks && !document ) {
|
||||
throw new Error("A document must be provided in order to generate relative links.");
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent document housing this editor.
|
||||
* @type {ClientDocument}
|
||||
*/
|
||||
Object.defineProperty(this, "document", {value: document, writable: false});
|
||||
|
||||
/**
|
||||
* Whether to generate links relative to the parent document.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Object.defineProperty(this, "relativeLinks", {value: relativeLinks, writable: false});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static build(schema, options={}) {
|
||||
const plugin = new ProseMirrorContentLinkPlugin(schema, options);
|
||||
return new Plugin({
|
||||
props: {
|
||||
handleDrop: plugin._onDrop.bind(plugin)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle a drop onto the editor.
|
||||
* @param {EditorView} view The ProseMirror editor view.
|
||||
* @param {DragEvent} event The drop event.
|
||||
* @param {Slice} slice A slice of editor content.
|
||||
* @param {boolean} moved Whether the slice has been moved from a different part of the editor.
|
||||
* @protected
|
||||
*/
|
||||
_onDrop(view, event, slice, moved) {
|
||||
if ( moved ) return;
|
||||
const pos = view.posAtCoords({left: event.clientX, top: event.clientY});
|
||||
const data = TextEditor.getDragEventData(event);
|
||||
if ( !data.type ) return;
|
||||
const options = {};
|
||||
if ( this.relativeLinks ) options.relativeTo = this.document;
|
||||
const selection = view.state.selection;
|
||||
if ( !selection.empty ) {
|
||||
const content = selection.content().content;
|
||||
options.label = content.textBetween(0, content.size);
|
||||
}
|
||||
TextEditor.getContentLink(data, options).then(link => {
|
||||
if ( !link ) return;
|
||||
const tr = view.state.tr;
|
||||
if ( selection.empty ) tr.insertText(link, pos.pos);
|
||||
else tr.replaceSelectionWith(this.schema.text(link));
|
||||
view.dispatch(tr);
|
||||
// Focusing immediately only seems to work in Chrome. In Firefox we must yield execution before attempting to
|
||||
// focus, otherwise the cursor becomes invisible until the user manually unfocuses and refocuses.
|
||||
setTimeout(view.focus.bind(view), 0);
|
||||
});
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user