mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-12-21 07:18:05 +08:00
137 lines
3.3 KiB
TypeScript
137 lines
3.3 KiB
TypeScript
|
import { EditorState, Transaction } from "prosemirror-state";
|
||
|
import { ChainedCommands, Editor } from "./Editor";
|
||
|
|
||
|
export default class CommandManager {
|
||
|
|
||
|
editor: Editor
|
||
|
commands: { [key: string]: any } = {}
|
||
|
|
||
|
constructor(editor: Editor, commands: any) {
|
||
|
this.editor = editor
|
||
|
this.commands = commands
|
||
|
}
|
||
|
|
||
|
public runSingleCommand(name: string) {
|
||
|
const { commands, editor } = this
|
||
|
const { state, view } = editor
|
||
|
const command = commands[name]
|
||
|
|
||
|
if (!command) {
|
||
|
// TODO: prevent vue devtools to throw error
|
||
|
// throw new Error(`tiptap: command '${name}' not found.`)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return (...args: any) => {
|
||
|
const { tr } = state
|
||
|
|
||
|
const props = {
|
||
|
editor: this.editor,
|
||
|
state: this.chainableEditorState(tr, state),
|
||
|
view,
|
||
|
dispatch: () => false,
|
||
|
// chain: this.chain.bind(this),
|
||
|
tr,
|
||
|
}
|
||
|
|
||
|
Object.defineProperty(props, 'commands', {
|
||
|
get: function() {
|
||
|
return Object.fromEntries(Object
|
||
|
.entries(commands)
|
||
|
.map(([name, command]) => {
|
||
|
return [name, (...args: any[]) => command(...args)(props)]
|
||
|
}))
|
||
|
}
|
||
|
})
|
||
|
|
||
|
const callback = command(...args)(props)
|
||
|
|
||
|
view.dispatch(tr)
|
||
|
|
||
|
return callback
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public createChain() {
|
||
|
const { commands, editor } = this
|
||
|
const { state, view } = editor
|
||
|
const { tr } = state
|
||
|
const callbacks: boolean[] = []
|
||
|
|
||
|
return new Proxy({}, {
|
||
|
get: (target, name: string, proxy) => {
|
||
|
if (name === 'run') {
|
||
|
view.dispatch(tr)
|
||
|
|
||
|
return () => callbacks.every(callback => callback === true)
|
||
|
}
|
||
|
|
||
|
const command = commands[name]
|
||
|
|
||
|
if (!command) {
|
||
|
throw new Error(`tiptap: command '${name}' not found.`)
|
||
|
}
|
||
|
|
||
|
return (...args: any) => {
|
||
|
const props = {
|
||
|
editor: editor,
|
||
|
state: this.chainableEditorState(tr, state),
|
||
|
view: view,
|
||
|
dispatch: () => false,
|
||
|
// chain: this.chain.bind(this),
|
||
|
tr,
|
||
|
}
|
||
|
|
||
|
// const self = this.editor
|
||
|
Object.defineProperty(props, 'commands', {
|
||
|
get: function() {
|
||
|
return Object.fromEntries(Object
|
||
|
.entries(commands)
|
||
|
.map(([name, command]) => {
|
||
|
return [name, (...args: any[]) => command(...args)(props)]
|
||
|
}))
|
||
|
}
|
||
|
});
|
||
|
|
||
|
const callback = command(...args)(props)
|
||
|
callbacks.push(callback)
|
||
|
|
||
|
return proxy
|
||
|
}
|
||
|
}
|
||
|
}) as ChainedCommands
|
||
|
}
|
||
|
|
||
|
public chainableEditorState(tr: Transaction, state: EditorState): EditorState {
|
||
|
let selection = tr.selection
|
||
|
let doc = tr.doc
|
||
|
let storedMarks = tr.storedMarks
|
||
|
|
||
|
return {
|
||
|
...state,
|
||
|
schema: state.schema,
|
||
|
plugins: state.plugins,
|
||
|
apply: state.apply.bind(state),
|
||
|
applyTransaction: state.applyTransaction.bind(state),
|
||
|
reconfigure: state.reconfigure.bind(state),
|
||
|
toJSON: state.toJSON.bind(state),
|
||
|
get storedMarks() {
|
||
|
return storedMarks
|
||
|
},
|
||
|
get selection() {
|
||
|
return selection
|
||
|
},
|
||
|
get doc() {
|
||
|
return doc
|
||
|
},
|
||
|
get tr() {
|
||
|
selection = tr.selection
|
||
|
doc = tr.doc
|
||
|
storedMarks = tr.storedMarks
|
||
|
|
||
|
return tr
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
|
||
|
}
|