@@ -4,6 +4,7 @@ import { TextSelection } from "prosemirror-state";
44import { ReplaceAroundStep } from "prosemirror-transform" ;
55import {
66 getBottomNestedBlockInfo ,
7+ getNextBlockInfo ,
78 getParentBlockInfo ,
89 getPrevBlockInfo ,
910 mergeBlocksCommand ,
@@ -296,20 +297,13 @@ export const KeyboardShortcutsExtension = Extension.create<{
296297 } else if (
297298 prevBlockInfo . blockContent . node . type . spec . content === ""
298299 ) {
299- const nonEditableBlockContentStartPos =
300- prevBlockInfo . blockContent . afterPos -
301- prevBlockInfo . blockContent . node . nodeSize ;
302-
303300 chainedCommands = chainedCommands . setNodeSelection (
304- nonEditableBlockContentStartPos ,
301+ prevBlockInfo . blockContent . beforePos ,
305302 ) ;
306303 } else {
307- const blockContentStartPos =
308- prevBlockInfo . blockContent . afterPos -
309- prevBlockInfo . blockContent . node . nodeSize ;
310-
311- chainedCommands =
312- chainedCommands . setTextSelection ( blockContentStartPos ) ;
304+ chainedCommands = chainedCommands . setTextSelection (
305+ prevBlockInfo . blockContent . afterPos - 1 ,
306+ ) ;
313307 }
314308
315309 return chainedCommands
@@ -383,50 +377,150 @@ export const KeyboardShortcutsExtension = Extension.create<{
383377 ] ) ;
384378
385379 const handleDelete = ( ) =>
386- this . editor . commands . first ( ( { commands } ) => [
380+ this . editor . commands . first ( ( { chain , commands } ) => [
387381 // Deletes the selection if it's not empty.
388382 ( ) => commands . deleteSelection ( ) ,
389383 // Merges block with the next one (at the same nesting level or lower),
390384 // if one exists, the block has no children, and the selection is at the
391385 // end of the block.
392386 ( ) =>
393387 commands . command ( ( { state } ) => {
394- // TODO: Change this to not rely on offsets & schema assumptions
395388 const blockInfo = getBlockInfoFromSelection ( state ) ;
396389 if ( ! blockInfo . isBlockContainer ) {
397390 return false ;
398391 }
399- const {
400- bnBlock : blockContainer ,
401- blockContent,
402- childContainer,
403- } = blockInfo ;
392+ const { bnBlock : blockContainer , blockContent } = blockInfo ;
404393
405- const { depth } = state . doc . resolve ( blockContainer . beforePos ) ;
406- const blockAtDocEnd =
407- blockContainer . afterPos === state . doc . nodeSize - 3 ;
408394 const selectionAtBlockEnd =
409395 state . selection . from === blockContent . afterPos - 1 ;
410396 const selectionEmpty = state . selection . empty ;
411- const hasChildBlocks = childContainer !== undefined ;
412397
413- if (
414- ! blockAtDocEnd &&
415- selectionAtBlockEnd &&
416- selectionEmpty &&
417- ! hasChildBlocks
418- ) {
419- let oldDepth = depth ;
420- let newPos = blockContainer . afterPos + 1 ;
421- let newDepth = state . doc . resolve ( newPos ) . depth ;
422-
423- while ( newDepth < oldDepth ) {
424- oldDepth = newDepth ;
425- newPos += 2 ;
426- newDepth = state . doc . resolve ( newPos ) . depth ;
398+ const posBetweenBlocks = blockContainer . afterPos ;
399+
400+ if ( selectionAtBlockEnd && selectionEmpty ) {
401+ return chain ( )
402+ . command ( mergeBlocksCommand ( posBetweenBlocks ) )
403+ . scrollIntoView ( )
404+ . run ( ) ;
405+ }
406+
407+ return false ;
408+ } ) ,
409+ // Deletes the current block if it's an empty block with inline content,
410+ // and moves the selection to the next block.
411+ ( ) =>
412+ commands . command ( ( { state } ) => {
413+ const blockInfo = getBlockInfoFromSelection ( state ) ;
414+ if ( ! blockInfo . isBlockContainer ) {
415+ return false ;
416+ }
417+
418+ const blockEmpty =
419+ blockInfo . blockContent . node . childCount === 0 &&
420+ blockInfo . blockContent . node . type . spec . content === "inline*" ;
421+
422+ if ( blockEmpty ) {
423+ const nextBlockInfo = getNextBlockInfo (
424+ state . doc ,
425+ blockInfo . bnBlock . beforePos ,
426+ ) ;
427+ if ( ! nextBlockInfo || ! nextBlockInfo . isBlockContainer ) {
428+ return false ;
429+ }
430+
431+ let chainedCommands = chain ( ) ;
432+
433+ if (
434+ nextBlockInfo . blockContent . node . type . spec . content ===
435+ "tableRow+"
436+ ) {
437+ const tableBlockStartPos = blockInfo . bnBlock . afterPos + 1 ;
438+ const tableBlockContentStartPos = tableBlockStartPos + 1 ;
439+ const firstRowStartPos = tableBlockContentStartPos + 1 ;
440+ const firstCellStartPos = firstRowStartPos + 1 ;
441+ const firstCellParagraphStartPos = firstCellStartPos + 1 ;
442+
443+ chainedCommands = chainedCommands . setTextSelection (
444+ firstCellParagraphStartPos ,
445+ ) ;
446+ } else if (
447+ nextBlockInfo . blockContent . node . type . spec . content === ""
448+ ) {
449+ chainedCommands = chainedCommands . setNodeSelection (
450+ nextBlockInfo . blockContent . beforePos ,
451+ ) ;
452+ } else {
453+ chainedCommands = chainedCommands . setTextSelection (
454+ nextBlockInfo . blockContent . beforePos + 1 ,
455+ ) ;
427456 }
428457
429- return commands . command ( mergeBlocksCommand ( newPos - 1 ) ) ;
458+ return chainedCommands
459+ . deleteRange ( {
460+ from : blockInfo . bnBlock . beforePos ,
461+ to : blockInfo . bnBlock . afterPos ,
462+ } )
463+ . scrollIntoView ( )
464+ . run ( ) ;
465+ }
466+
467+ return false ;
468+ } ) ,
469+ // Deletes next block if it contains no content and isn't a table,
470+ // when the selection is empty and at the end of the block. Moves the
471+ // current block into the deleted block's place.
472+ ( ) =>
473+ commands . command ( ( { state } ) => {
474+ const blockInfo = getBlockInfoFromSelection ( state ) ;
475+
476+ if ( ! blockInfo . isBlockContainer ) {
477+ // TODO
478+ throw new Error ( `todo` ) ;
479+ }
480+
481+ const selectionAtBlockEnd =
482+ state . selection . from === blockInfo . blockContent . afterPos - 1 ;
483+ const selectionEmpty = state . selection . empty ;
484+
485+ const nextBlockInfo = getNextBlockInfo (
486+ state . doc ,
487+ blockInfo . bnBlock . beforePos ,
488+ ) ;
489+ if ( ! nextBlockInfo ) {
490+ return false ;
491+ }
492+ if ( ! nextBlockInfo . isBlockContainer ) {
493+ // TODO
494+ throw new Error ( `todo` ) ;
495+ }
496+
497+ if ( nextBlockInfo && selectionAtBlockEnd && selectionEmpty ) {
498+ const nextBlockNotTableAndNoContent =
499+ nextBlockInfo . blockContent . node . type . spec . content === "" ||
500+ ( nextBlockInfo . blockContent . node . type . spec . content ===
501+ "inline*" &&
502+ nextBlockInfo . blockContent . node . childCount === 0 ) ;
503+
504+ if ( nextBlockNotTableAndNoContent ) {
505+ if ( nextBlockInfo . bnBlock . node . childCount === 2 ) {
506+ const childBlocks =
507+ nextBlockInfo . bnBlock . node . lastChild ! . content ;
508+ return chain ( )
509+ . deleteRange ( {
510+ from : nextBlockInfo . bnBlock . beforePos ,
511+ to : nextBlockInfo . bnBlock . afterPos ,
512+ } )
513+ . insertContentAt ( blockInfo . bnBlock . afterPos , childBlocks )
514+ . run ( ) ;
515+ }
516+
517+ return chain ( )
518+ . deleteRange ( {
519+ from : nextBlockInfo . bnBlock . beforePos ,
520+ to : nextBlockInfo . bnBlock . afterPos ,
521+ } )
522+ . run ( ) ;
523+ }
430524 }
431525
432526 return false ;
0 commit comments