tiptap/packages/core/src/CommandManager.ts

158 lines
3.8 KiB
TypeScript
Raw Normal View History

import { EditorState, Transaction } from 'prosemirror-state'
2020-11-17 04:42:35 +08:00
import { Editor } from './Editor'
import createChainableState from './helpers/createChainableState'
2020-11-03 00:18:12 +08:00
import {
2020-11-16 22:56:44 +08:00
SingleCommands,
ChainedCommands,
2020-11-17 00:25:55 +08:00
CanCommands,
2021-06-05 03:56:29 +08:00
AnyCommands,
2021-01-28 16:50:17 +08:00
CommandProps,
2020-11-17 04:42:35 +08:00
} from './types'
2020-09-23 03:25:32 +08:00
export default class CommandManager {
editor: Editor
2020-09-24 06:29:05 +08:00
rawCommands: AnyCommands
2020-09-23 03:25:32 +08:00
customState?: EditorState
constructor(props: {
editor: Editor,
state?: EditorState,
}) {
this.editor = props.editor
this.rawCommands = this.editor.extensionManager.commands
this.customState = props.state
}
get hasCustomState(): boolean {
return !!this.customState
}
get state(): EditorState {
return this.customState || this.editor.state
2020-09-23 14:59:21 +08:00
}
get commands(): SingleCommands {
const { rawCommands, editor, state } = this
const { view } = editor
2020-12-01 19:45:30 +08:00
const { tr } = state
const props = this.buildProps(tr)
2020-11-13 16:58:30 +08:00
return Object.fromEntries(Object
.entries(rawCommands)
2020-11-13 16:58:30 +08:00
.map(([name, command]) => {
2021-06-05 03:56:29 +08:00
const method = (...args: any[]) => {
2021-02-17 01:00:40 +08:00
const callback = command(...args)(props)
2020-11-13 16:58:30 +08:00
if (!tr.getMeta('preventDispatch') && !this.hasCustomState) {
2020-12-02 16:28:55 +08:00
view.dispatch(tr)
}
2020-11-13 16:58:30 +08:00
return callback
}
return [name, method]
2021-06-05 03:56:29 +08:00
})) as unknown as SingleCommands
2020-11-13 16:58:30 +08:00
}
get chain(): () => ChainedCommands {
return () => this.createChain()
}
get can(): () => CanCommands {
return () => this.createCan()
}
2021-01-28 16:50:17 +08:00
public createChain(startTr?: Transaction, shouldDispatch = true): ChainedCommands {
const { rawCommands, editor, state } = this
const { view } = editor
2020-09-23 03:25:32 +08:00
const callbacks: boolean[] = []
const hasStartTransaction = !!startTr
2020-11-13 16:58:30 +08:00
const tr = startTr || state.tr
2020-09-23 03:25:32 +08:00
2021-02-10 22:10:03 +08:00
const run = () => {
if (
!hasStartTransaction
&& shouldDispatch
&& !tr.getMeta('preventDispatch')
&& !this.hasCustomState
) {
2021-02-10 22:10:03 +08:00
view.dispatch(tr)
}
2020-09-23 03:25:32 +08:00
return callbacks.every(callback => callback === true)
2021-02-10 22:10:03 +08:00
}
2020-09-23 03:25:32 +08:00
2021-02-10 22:10:03 +08:00
const chain = {
...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
2021-04-27 05:33:45 +08:00
const chainedCommand = (...args: never[]) => {
2020-12-02 06:32:39 +08:00
const props = this.buildProps(tr, shouldDispatch)
2020-09-23 03:25:32 +08:00
const callback = command(...args)(props)
2020-12-02 06:32:39 +08:00
2020-09-23 03:25:32 +08:00
callbacks.push(callback)
2021-02-10 22:10:03 +08:00
return chain
2020-09-23 03:25:32 +08:00
}
2021-02-10 22:10:03 +08:00
return [name, chainedCommand]
})),
run,
} as unknown as ChainedCommands
return chain
2020-09-23 03:25:32 +08:00
}
2021-01-28 16:50:17 +08:00
public createCan(startTr?: Transaction): CanCommands {
const { rawCommands, state } = this
2021-02-16 18:27:58 +08:00
const dispatch = undefined
2020-11-13 16:58:30 +08:00
const tr = startTr || state.tr
2020-11-03 00:18:12 +08:00
const props = this.buildProps(tr, dispatch)
const formattedCommands = Object.fromEntries(Object
.entries(rawCommands)
2020-11-03 00:18:12 +08:00
.map(([name, command]) => {
2021-04-27 05:33:45 +08:00
return [name, (...args: never[]) => command(...args)({ ...props, dispatch })]
2021-06-05 03:56:29 +08:00
})) as unknown as SingleCommands
2020-11-03 00:18:12 +08:00
return {
...formattedCommands,
chain: () => this.createChain(tr, dispatch),
2020-11-17 00:25:55 +08:00
} as CanCommands
2020-11-03 00:18:12 +08:00
}
2021-01-28 16:50:17 +08:00
public buildProps(tr: Transaction, shouldDispatch = true): CommandProps {
const { rawCommands, editor, state } = this
const { view } = editor
2020-09-23 03:35:02 +08:00
2020-12-02 06:32:39 +08:00
if (state.storedMarks) {
tr.setStoredMarks(state.storedMarks)
}
2021-02-17 01:00:40 +08:00
const props: CommandProps = {
tr,
2020-09-23 03:35:02 +08:00
editor,
view,
state: createChainableState({
state,
transaction: tr,
}),
2020-11-02 21:29:58 +08:00
dispatch: shouldDispatch
? () => undefined
2020-11-02 21:29:58 +08:00
: undefined,
chain: () => this.createChain(tr),
2020-11-03 00:18:12 +08:00
can: () => this.createCan(tr),
2020-09-23 03:35:02 +08:00
get commands() {
return Object.fromEntries(Object
.entries(rawCommands)
2020-09-23 03:35:02 +08:00
.map(([name, command]) => {
2021-04-27 05:33:45 +08:00
return [name, (...args: never[]) => command(...args)(props)]
2021-06-05 03:56:29 +08:00
})) as unknown as SingleCommands
2020-09-24 06:29:05 +08:00
},
2020-09-23 03:35:02 +08:00
}
return props
}
2020-09-24 06:29:05 +08:00
}