Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
let nextType = $to.pos == $from.end() ? grandParent.contentMatchAt(0).defaultType : null
let tr = state.tr.delete($from.pos, $to.pos)
let types = nextType && [null, {type: nextType}]
// NOTE
//
// still not sure about the logic behind this `nextType` and `types`
//
// seems that
// 1. cursor at the end of a paragraph
// 1. nextType is a `paragraph` (a NodeType)
// 2. cursor in the middle of a para
// 1. nextType is null
//
if (!canSplit(tr.doc, $from.pos, 2, types)) return false
// HACK
//
// NOTE
// I tried to *do the right thing* by modifying this `types` before `canSplit`,
// yet changing it caused `canSplit` to return false
// spent a day digging into the code,
// `validContent`, `matchFragment`, eventually `matchType`
// in the original version, the parameter in `matchType` is a `text`,
// yet in the hijacked one, it's a `list_item`
//
// stopped debugging, made a patch here, and it worked
//
types = types ?? []
types[0] = {type: itemType}
return tr;
}
if ($from.parent.content.size == 0) {
// In an empty list item.
return splitEmptyListItem(tr, schema);
}
const nextType =
$to.pos == $from.end()
? grandParent.contentMatchAt($from.indexAfter(-1)).defaultType
: null;
tr = tr.delete($from.pos, $to.pos);
const types = nextType && [null, {type: nextType}];
if (!canSplit(tr.doc, $from.pos, 2, types)) {
return tr;
}
return tr.split($from.pos, 2, types);
}
let {$from, $to} = state.selection
if (state.selection instanceof NodeSelection && state.selection.node.isBlock) {
if (!$from.parentOffset || !canSplit(state.doc, $from.pos)) return false
if (dispatch) dispatch(state.tr.split($from.pos).scrollIntoView())
return true
}
if (!$from.parent.isBlock) return false
if (dispatch) {
let atEnd = $to.parentOffset == $to.parent.content.size
let tr = state.tr
if (state.selection instanceof TextSelection) tr.deleteSelection()
let deflt = $from.depth == 0 ? null : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
let types = atEnd && deflt ? [{type: deflt}] : null
let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt && [{type: deflt}])) {
types = [{type: deflt}]
can = true
}
if (can) {
tr.split(tr.mapping.map($from.pos), 1, types)
if (!atEnd && !$from.parentOffset && $from.parent.type != deflt &&
$from.node(-1).canReplace($from.index(-1), $from.indexAfter(-1), Fragment.from(deflt.create(), $from.parent)))
tr.setNodeMarkup(tr.mapping.map($from.before()), deflt)
}
dispatch(tr.scrollIntoView())
}
return true
}
let found = 0
for (let i = 0; i < wrappers.length; i++) {
if (wrappers[i].type == nodeType) {
found = i + 1;
}
};
let splitDepth = wrappers.length - found;
let splitPos = range.start + wrappers.length - (doJoin ? 2 : 0);
let parent = range.parent;
for (
let i = range.startIndex, e = range.endIndex, first = true;
i < e; i++,
first = false
) {
if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
tr = tr.split(splitPos, splitDepth)
splitPos += 2 * splitDepth;
}
splitPos += parent.child(i).nodeSize;
}
return tr;
}
if (state.selection instanceof NodeSelection && state.selection.node.isBlock) {
if (!$from.parentOffset || !canSplit(state.doc, $from.pos)) return false
if (dispatch) dispatch(state.tr.split($from.pos).scrollIntoView())
return true
}
if (!$from.parent.isBlock) return false
if (dispatch) {
let atEnd = $to.parentOffset == $to.parent.content.size
let tr = state.tr
if (state.selection instanceof TextSelection) tr.deleteSelection()
let deflt = $from.depth == 0 ? null : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
let types = atEnd && deflt ? [{type: deflt}] : null
let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt && [{type: deflt}])) {
types = [{type: deflt}]
can = true
}
if (can) {
tr.split(tr.mapping.map($from.pos), 1, types)
if (!atEnd && !$from.parentOffset && $from.parent.type != deflt &&
$from.node(-1).canReplace($from.index(-1), $from.indexAfter(-1), Fragment.from(deflt.create(), $from.parent)))
tr.setNodeMarkup(tr.mapping.map($from.before()), deflt)
}
dispatch(tr.scrollIntoView())
}
return true
}
export function splitBlock(state, dispatch) {
let {$from, $to} = state.selection
if (state.selection instanceof NodeSelection && state.selection.node.isBlock) {
if (!$from.parentOffset || !canSplit(state.doc, $from.pos)) return false
if (dispatch) dispatch(state.tr.split($from.pos).scrollIntoView())
return true
}
if (!$from.parent.isBlock) return false
if (dispatch) {
let atEnd = $to.parentOffset == $to.parent.content.size
let tr = state.tr
if (state.selection instanceof TextSelection) tr.deleteSelection()
let deflt = $from.depth == 0 ? null : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
let types = atEnd && deflt ? [{type: deflt}] : null
let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt && [{type: deflt}])) {
types = [{type: deflt}]
can = true
export function liftEmptyBlock(state, dispatch) {
let {$cursor} = state.selection
if (!$cursor || $cursor.parent.content.size) return false
if ($cursor.depth > 1 && $cursor.after() != $cursor.end(-1)) {
let before = $cursor.before()
if (canSplit(state.doc, before)) {
if (dispatch) dispatch(state.tr.split(before).scrollIntoView())
return true
}
}
let range = $cursor.blockRange(), target = range && liftTarget(range)
if (target == null) return false
if (dispatch) dispatch(state.tr.lift(range, target).scrollIntoView())
return true
}