add withAttributes and withMarks option to splitBlock command

This commit is contained in:
Philipp Kühn
2020-11-04 17:01:51 +01:00
parent 1d3de73f82
commit 09ddf954a7
4 changed files with 47 additions and 8 deletions

View File

@@ -131,7 +131,7 @@ export default class CommandManager {
view, view,
state: this.chainableState(tr, state), state: this.chainableState(tr, state),
dispatch: shouldDispatch dispatch: shouldDispatch
? () => true ? () => undefined
: undefined, : undefined,
chain: () => this.createChain(tr), chain: () => this.createChain(tr),
can: () => this.createCan(tr), can: () => this.createCan(tr),

View File

@@ -29,11 +29,11 @@ export const BaseKeymap = createExtension({
]) ])
return { return {
Enter: () => this.editor.try(({ state, dispatch }) => [ Enter: () => this.editor.try(({ commands, state, dispatch }) => [
() => newlineInCode(state, dispatch), () => newlineInCode(state, dispatch),
() => createParagraphNear(state, dispatch), () => createParagraphNear(state, dispatch),
() => liftEmptyBlock(state, dispatch), () => liftEmptyBlock(state, dispatch),
() => splitBlockKeepMarks(state, dispatch), () => commands.splitBlock(),
]), ]),
'Mod-Enter': exitCode, 'Mod-Enter': exitCode,
Backspace: () => handleBackspace(), Backspace: () => handleBackspace(),

View File

@@ -1,6 +1,6 @@
import { canSplit } from 'prosemirror-transform' import { canSplit } from 'prosemirror-transform'
import { ContentMatch, Fragment } from 'prosemirror-model' import { ContentMatch, Fragment } from 'prosemirror-model'
import { NodeSelection, TextSelection } from 'prosemirror-state' import { EditorState, NodeSelection, TextSelection } from 'prosemirror-state'
import { Command } from '../Editor' import { Command } from '../Editor'
import { createExtension } from '../Extension' import { createExtension } from '../Extension'
@@ -13,10 +13,29 @@ function defaultBlockAt(match: ContentMatch) {
return null return null
} }
interface SplitBlockOptions {
withAttributes: boolean,
withMarks: boolean,
}
function keepMarks(state: EditorState) {
const marks = state.storedMarks
|| (state.selection.$to.parentOffset && state.selection.$from.marks())
if (marks) {
state.tr.ensureMarks(marks)
}
}
export const SplitBlock = createExtension({ export const SplitBlock = createExtension({
addCommands() { addCommands() {
return { return {
splitBlock: (copyAttributes = false): Command => ({ tr, dispatch }) => { splitBlock: (options: Partial<SplitBlockOptions> = {}): Command => ({ tr, state, dispatch }) => {
const defaultOptions: SplitBlockOptions = {
withAttributes: false,
withMarks: true,
}
const config = { ...defaultOptions, ...options }
const { selection, doc } = tr const { selection, doc } = tr
const { $from, $to } = selection const { $from, $to } = selection
@@ -26,6 +45,10 @@ export const SplitBlock = createExtension({
} }
if (dispatch) { if (dispatch) {
if (config.withMarks) {
keepMarks(state)
}
tr.split($from.pos).scrollIntoView() tr.split($from.pos).scrollIntoView()
} }
@@ -48,7 +71,12 @@ export const SplitBlock = createExtension({
: defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1))) : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
let types = atEnd && deflt let types = atEnd && deflt
? [{ type: deflt, attrs: copyAttributes ? $from.node().attrs : {} }] ? [{
type: deflt,
attrs: config.withAttributes
? $from.node().attrs
: {},
}]
: undefined : undefined
let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types) let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
@@ -60,7 +88,12 @@ export const SplitBlock = createExtension({
) { ) {
can = true can = true
types = deflt types = deflt
? [{ type: deflt, attrs: copyAttributes ? $from.node().attrs : {} }] ? [{
type: deflt,
attrs: config.withAttributes
? $from.node().attrs
: {},
}]
: undefined : undefined
} }
@@ -77,6 +110,10 @@ export const SplitBlock = createExtension({
} }
} }
if (config.withMarks) {
keepMarks(state)
}
tr.scrollIntoView() tr.scrollIntoView()
} }

View File

@@ -49,7 +49,9 @@ const TextAlign = createExtension({
// TODO: re-use only 'textAlign' attribute // TODO: re-use only 'textAlign' attribute
// TODO: use custom splitBlock only for `this.options.types` // TODO: use custom splitBlock only for `this.options.types`
// TODO: use complete default enter handler (chainCommand) with custom splitBlock // TODO: use complete default enter handler (chainCommand) with custom splitBlock
Enter: () => this.editor.splitBlock(true), Enter: () => this.editor.splitBlock({
withAttributes: true,
}),
} }
}, },
}) })