I have a ListItem node with custom attributes and using the splitListItem command copies the attributes from the original ListItem into the split off ListItem. I need a way to create the split off ListItem using the node’s default attributes.
This is the code from the commands-list module:
function splitListItem(nodeType) {
return function(pm) {
let {$from, $to, node} = pm.selection
if ((node && node.isBlock) || !$from.parent.content.size ||
$from.depth < 2 || !$from.sameParent($to)) return false
let grandParent = $from.node(-1)
if (grandParent.type != nodeType) return false
let nextType = $to.pos == $from.end() ? grandParent.defaultContentType($from.indexAfter(-1)) : null
let tr = pm.tr.delete($from.pos, $to.pos)
if (!canSplit(tr.doc, $from.pos, 2, nextType)) return false
tr.split($from.pos, 2, nextType).applyAndScroll()
return true
}
}
I saw that the split transform accepts a typeAfter and a attrsAfter argument, which seems like it should allow me to achieve what I want. But it looks like the arguments are used at multiple depths during the split, which doesn’t make sense in this case as the ListItem contains a Paragraph, which is of a different type and needs different attributes. Maybe I’m misunderstanding something?
What would be the best way to customize the splitListItem command to create the split off ListItem with the node’s default attributes instead of the attributes of the ListItem that was split?
I did not reimplement the existing split transform, but used it for reference.
The problem I faced with the standard split command is that it only allows you to specify the type and attributes for the “inner” node when using a depth larger than 1. In my case with the list item the depth is 2. Specifying a type and attributes only applies to the paragraph inside the list item, but still copies the attributes of the list item. I needed exactly the opposite: To keep the attributes of the paragraph and reset the attributes of the splitted wrapping list item.
Hi,
I reimplement the splitListItem function for use default ListItem attributes when splitting a ListItem.
Here is my code:
function splitListItem(itemType) {
return function(state, dispatch) {
let {$from, $to, node} = state.selection
if ((node && node.isBlock) || $from.depth < 2 || !$from.sameParent($to)) return false
let grandParent = $from.node(-1)
if (grandParent.type != itemType) return false
if ($from.parent.content.size == 0) {
// In an empty block. If this is a nested list, the wrapping
// list item should be split. Otherwise, bail out and let next
// command handle lifting.
if ($from.depth == 2 || $from.node(-3).type != itemType ||
$from.index(-2) != $from.node(-2).childCount - 1) return false
if (dispatch) {
let wrap = Fragment.empty, keepItem = $from.index(-1) > 0
// Build a fragment containing empty versions of the structure
// from the outer list item to the parent node of the cursor
for (let d = $from.depth - (keepItem ? 1 : 2); d >= $from.depth - 3; d--)
wrap = Fragment.from($from.node(d).copy(wrap))
// Add a second list item with an empty default start node
wrap = wrap.append(Fragment.from(itemType.createAndFill()))
let tr = state.tr.replace($from.before(keepItem ? null : -1), $from.after(-3), new Slice(wrap, keepItem ? 3 : 2, 2))
tr.setSelection(state.selection.constructor.near(tr.doc.resolve($from.pos + (keepItem ? 3 : 2))))
dispatch(tr.scrollIntoView())
}
return true
}
let nextType = $to.pos == $from.end() ? grandParent.contentMatchAt($from.indexAfter(-1)).defaultType : null
let tr = state.tr.delete($from.pos, $to.pos)
/* Change starts from here */
let types = nextType && [{type: itemType}, {type: nextType}]
if (!types) types = [{type: itemType}, null]
/* Change ends here */
if (!canSplitForCheckListItem(tr.doc, $from.pos, 2, types)) return false
if (dispatch) dispatch(tr.split($from.pos, 2, types).scrollIntoView())
return true
}
}
Is this reimplement function correct or not ?
I can’t use this function to get the result I wanted…
Hey @marijn, I also needed the functionality to use splitListItem with default attrs instead of copying them. Maybe you could consider to add this to prosemirror-schema-list (or another package), because I needed to replace just one line in splitListItem() from prosemirror-schema-list and one line in canSplit() from prosemirror-transform to get this working. Maybe with an option as second parameter?
See this discussion. Specifically, feel free to open a pull request that factors internal functionality from that module into (more or less clean, self-contained) exported functions, and we’ll discuss the details in the code review.