0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 15:23:29 -05:00

Fix delete behaviour

1. Fixes cursor position when deleting starting with a selection at beginning
   of block.
2. Fixes block disappears when whole inline contents is deleted.
This commit is contained in:
Neil Jenkins 2017-01-09 14:07:20 +11:00
parent 066bdd2cde
commit 6f83f23881
6 changed files with 62 additions and 66 deletions

View file

@ -858,28 +858,24 @@ var extractContentsOfRange = function ( range, common, root ) {
}; };
var deleteContentsOfRange = function ( range, root ) { var deleteContentsOfRange = function ( range, root ) {
// Move boundaries up as much as possible to reduce need to split. var startBlock = getStartBlockOfRange( range, root );
// But we need to check whether we've moved the boundary outside of a var endBlock = getEndBlockOfRange( range, root );
// block. If so, the entire block will be removed, so we shouldn't merge var needsMerge = ( startBlock !== endBlock );
// later. var frag, child;
moveRangeBoundariesUpTree( range );
var startBlock = range.startContainer, // Move boundaries up as much as possible without exiting block,
endBlock = range.endContainer, // to reduce need to split.
needsMerge = ( isInline( startBlock ) || isBlock( startBlock ) ) && moveRangeBoundariesUpTree( range, startBlock, endBlock );
( isInline( endBlock ) || isBlock( endBlock ) );
// Remove selected range // Remove selected range
var frag = extractContentsOfRange( range, null, root ); frag = extractContentsOfRange( range, null, root );
// Move boundaries back down tree so that they are inside the blocks. // Move boundaries back down tree as far as possible.
// If we don't do this, the range may be collapsed to a point between
// two blocks, so get(Start|End)BlockOfRange will return null.
moveRangeBoundariesDownTree( range ); moveRangeBoundariesDownTree( range );
// If we split into two different blocks, merge the blocks. // If we split into two different blocks, merge the blocks.
startBlock = getStartBlockOfRange( range, root );
if ( needsMerge ) { if ( needsMerge ) {
// endBlock will have been split, so need to refetch
endBlock = getEndBlockOfRange( range, root ); endBlock = getEndBlockOfRange( range, root );
if ( startBlock && endBlock && startBlock !== endBlock ) { if ( startBlock && endBlock && startBlock !== endBlock ) {
mergeWithBlock( startBlock, endBlock, range ); mergeWithBlock( startBlock, endBlock, range );
@ -892,12 +888,12 @@ var deleteContentsOfRange = function ( range, root ) {
} }
// Ensure root has a block-level element in it. // Ensure root has a block-level element in it.
var child = root.firstChild; child = root.firstChild;
if ( !child || child.nodeName === 'BR' ) { if ( !child || child.nodeName === 'BR' ) {
fixCursor( root, root ); fixCursor( root, root );
range.selectNodeContents( root.firstChild ); range.selectNodeContents( root.firstChild );
} else { } else {
range.collapse( range.endContainer === root ? true : false ); range.collapse( true );
} }
return frag; return frag;
}; };
@ -1113,19 +1109,22 @@ var moveRangeBoundariesDownTree = function ( range ) {
} }
}; };
var moveRangeBoundariesUpTree = function ( range, common ) { var moveRangeBoundariesUpTree = function ( range, startMax, endMax ) {
var startContainer = range.startContainer, var startContainer = range.startContainer;
startOffset = range.startOffset, var startOffset = range.startOffset;
endContainer = range.endContainer, var endContainer = range.endContainer;
endOffset = range.endOffset, var endOffset = range.endOffset;
maySkipBR = true, var maySkipBR = true;
parent; var parent;
if ( !common ) { if ( !startMax ) {
common = range.commonAncestorContainer; startMax = range.commonAncestorContainer;
}
if ( !endMax ) {
endMax = startMax;
} }
while ( startContainer !== common && !startOffset ) { while ( startContainer !== startMax && !startOffset ) {
parent = startContainer.parentNode; parent = startContainer.parentNode;
startOffset = indexOf.call( parent.childNodes, startContainer ); startOffset = indexOf.call( parent.childNodes, startContainer );
startContainer = parent; startContainer = parent;
@ -1139,7 +1138,7 @@ var moveRangeBoundariesUpTree = function ( range, common ) {
endOffset += 1; endOffset += 1;
maySkipBR = false; maySkipBR = false;
} }
if ( endContainer === common || if ( endContainer === endMax ||
endOffset !== getLength( endContainer ) ) { endOffset !== getLength( endContainer ) ) {
break; break;
} }
@ -1638,7 +1637,7 @@ var keyHandlers = {
// delete it ourselves, because the browser won't if it is not // delete it ourselves, because the browser won't if it is not
// inline. // inline.
originalRange = range.cloneRange(); originalRange = range.cloneRange();
moveRangeBoundariesUpTree( range, self._root ); moveRangeBoundariesUpTree( range, root, root );
cursorContainer = range.endContainer; cursorContainer = range.endContainer;
cursorOffset = range.endOffset; cursorOffset = range.endOffset;
if ( cursorContainer.nodeType === ELEMENT_NODE ) { if ( cursorContainer.nodeType === ELEMENT_NODE ) {
@ -2178,7 +2177,6 @@ var onCut = function ( event ) {
// Mobile Safari flat out doesn't work: // Mobile Safari flat out doesn't work:
// https://bugs.webkit.org/show_bug.cgi?id=143776 // https://bugs.webkit.org/show_bug.cgi?id=143776
if ( !isEdge && !isIOS && clipboardData ) { if ( !isEdge && !isIOS && clipboardData ) {
moveRangeBoundariesUpTree( range, root );
node.appendChild( deleteContentsOfRange( range, root ) ); node.appendChild( deleteContentsOfRange( range, root ) );
setClipboardData( clipboardData, node, root ); setClipboardData( clipboardData, node, root );
event.preventDefault(); event.preventDefault();
@ -2212,7 +2210,7 @@ var onCopy = function ( event ) {
endBlock = getEndBlockOfRange( range, root ); endBlock = getEndBlockOfRange( range, root );
copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root; copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root;
moveRangeBoundariesDownTree( range ); moveRangeBoundariesDownTree( range );
moveRangeBoundariesUpTree( range, copyRoot ); moveRangeBoundariesUpTree( range, copyRoot, copyRoot );
contents = range.cloneContents(); contents = range.cloneContents();
parent = range.commonAncestorContainer; parent = range.commonAncestorContainer;
if ( parent.nodeType === TEXT_NODE ) { if ( parent.nodeType === TEXT_NODE ) {
@ -3720,7 +3718,7 @@ proto.modifyBlocks = function ( modify, range ) {
expandRangeToBlockBoundaries( range, root ); expandRangeToBlockBoundaries( range, root );
// 3. Remove range. // 3. Remove range.
moveRangeBoundariesUpTree( range, root ); moveRangeBoundariesUpTree( range, root, root );
frag = extractContentsOfRange( range, root, root ); frag = extractContentsOfRange( range, root, root );
// 4. Modify tree of fragment and reinsert. // 4. Modify tree of fragment and reinsert.
@ -4454,7 +4452,7 @@ proto.removeAllFormatting = function ( range ) {
this.saveUndoState( range ); this.saveUndoState( range );
// Avoid splitting where we're already at edges. // Avoid splitting where we're already at edges.
moveRangeBoundariesUpTree( range, stopNode ); moveRangeBoundariesUpTree( range, stopNode, stopNode );
// Split the selection up to the block, or if whole selection in same // Split the selection up to the block, or if whole selection in same
// block, expand range boundaries to ends of block and split up to root. // block, expand range boundaries to ends of block and split up to root.

File diff suppressed because one or more lines are too long

View file

@ -51,7 +51,6 @@ var onCut = function ( event ) {
// Mobile Safari flat out doesn't work: // Mobile Safari flat out doesn't work:
// https://bugs.webkit.org/show_bug.cgi?id=143776 // https://bugs.webkit.org/show_bug.cgi?id=143776
if ( !isEdge && !isIOS && clipboardData ) { if ( !isEdge && !isIOS && clipboardData ) {
moveRangeBoundariesUpTree( range, root );
node.appendChild( deleteContentsOfRange( range, root ) ); node.appendChild( deleteContentsOfRange( range, root ) );
setClipboardData( clipboardData, node, root ); setClipboardData( clipboardData, node, root );
event.preventDefault(); event.preventDefault();
@ -85,7 +84,7 @@ var onCopy = function ( event ) {
endBlock = getEndBlockOfRange( range, root ); endBlock = getEndBlockOfRange( range, root );
copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root; copyRoot = ( ( startBlock === endBlock ) && startBlock ) || root;
moveRangeBoundariesDownTree( range ); moveRangeBoundariesDownTree( range );
moveRangeBoundariesUpTree( range, copyRoot ); moveRangeBoundariesUpTree( range, copyRoot, copyRoot );
contents = range.cloneContents(); contents = range.cloneContents();
parent = range.commonAncestorContainer; parent = range.commonAncestorContainer;
if ( parent.nodeType === TEXT_NODE ) { if ( parent.nodeType === TEXT_NODE ) {

View file

@ -1301,7 +1301,7 @@ proto.modifyBlocks = function ( modify, range ) {
expandRangeToBlockBoundaries( range, root ); expandRangeToBlockBoundaries( range, root );
// 3. Remove range. // 3. Remove range.
moveRangeBoundariesUpTree( range, root ); moveRangeBoundariesUpTree( range, root, root );
frag = extractContentsOfRange( range, root, root ); frag = extractContentsOfRange( range, root, root );
// 4. Modify tree of fragment and reinsert. // 4. Modify tree of fragment and reinsert.
@ -2035,7 +2035,7 @@ proto.removeAllFormatting = function ( range ) {
this.saveUndoState( range ); this.saveUndoState( range );
// Avoid splitting where we're already at edges. // Avoid splitting where we're already at edges.
moveRangeBoundariesUpTree( range, stopNode ); moveRangeBoundariesUpTree( range, stopNode, stopNode );
// Split the selection up to the block, or if whole selection in same // Split the selection up to the block, or if whole selection in same
// block, expand range boundaries to ends of block and split up to root. // block, expand range boundaries to ends of block and split up to root.

View file

@ -362,7 +362,7 @@ var keyHandlers = {
// delete it ourselves, because the browser won't if it is not // delete it ourselves, because the browser won't if it is not
// inline. // inline.
originalRange = range.cloneRange(); originalRange = range.cloneRange();
moveRangeBoundariesUpTree( range, self._root ); moveRangeBoundariesUpTree( range, root, root );
cursorContainer = range.endContainer; cursorContainer = range.endContainer;
cursorOffset = range.endOffset; cursorOffset = range.endOffset;
if ( cursorContainer.nodeType === ELEMENT_NODE ) { if ( cursorContainer.nodeType === ELEMENT_NODE ) {

View file

@ -133,28 +133,24 @@ var extractContentsOfRange = function ( range, common, root ) {
}; };
var deleteContentsOfRange = function ( range, root ) { var deleteContentsOfRange = function ( range, root ) {
// Move boundaries up as much as possible to reduce need to split. var startBlock = getStartBlockOfRange( range, root );
// But we need to check whether we've moved the boundary outside of a var endBlock = getEndBlockOfRange( range, root );
// block. If so, the entire block will be removed, so we shouldn't merge var needsMerge = ( startBlock !== endBlock );
// later. var frag, child;
moveRangeBoundariesUpTree( range );
var startBlock = range.startContainer, // Move boundaries up as much as possible without exiting block,
endBlock = range.endContainer, // to reduce need to split.
needsMerge = ( isInline( startBlock ) || isBlock( startBlock ) ) && moveRangeBoundariesUpTree( range, startBlock, endBlock );
( isInline( endBlock ) || isBlock( endBlock ) );
// Remove selected range // Remove selected range
var frag = extractContentsOfRange( range, null, root ); frag = extractContentsOfRange( range, null, root );
// Move boundaries back down tree so that they are inside the blocks. // Move boundaries back down tree as far as possible.
// If we don't do this, the range may be collapsed to a point between
// two blocks, so get(Start|End)BlockOfRange will return null.
moveRangeBoundariesDownTree( range ); moveRangeBoundariesDownTree( range );
// If we split into two different blocks, merge the blocks. // If we split into two different blocks, merge the blocks.
startBlock = getStartBlockOfRange( range, root );
if ( needsMerge ) { if ( needsMerge ) {
// endBlock will have been split, so need to refetch
endBlock = getEndBlockOfRange( range, root ); endBlock = getEndBlockOfRange( range, root );
if ( startBlock && endBlock && startBlock !== endBlock ) { if ( startBlock && endBlock && startBlock !== endBlock ) {
mergeWithBlock( startBlock, endBlock, range ); mergeWithBlock( startBlock, endBlock, range );
@ -167,12 +163,12 @@ var deleteContentsOfRange = function ( range, root ) {
} }
// Ensure root has a block-level element in it. // Ensure root has a block-level element in it.
var child = root.firstChild; child = root.firstChild;
if ( !child || child.nodeName === 'BR' ) { if ( !child || child.nodeName === 'BR' ) {
fixCursor( root, root ); fixCursor( root, root );
range.selectNodeContents( root.firstChild ); range.selectNodeContents( root.firstChild );
} else { } else {
range.collapse( range.endContainer === root ? true : false ); range.collapse( true );
} }
return frag; return frag;
}; };
@ -388,19 +384,22 @@ var moveRangeBoundariesDownTree = function ( range ) {
} }
}; };
var moveRangeBoundariesUpTree = function ( range, common ) { var moveRangeBoundariesUpTree = function ( range, startMax, endMax ) {
var startContainer = range.startContainer, var startContainer = range.startContainer;
startOffset = range.startOffset, var startOffset = range.startOffset;
endContainer = range.endContainer, var endContainer = range.endContainer;
endOffset = range.endOffset, var endOffset = range.endOffset;
maySkipBR = true, var maySkipBR = true;
parent; var parent;
if ( !common ) { if ( !startMax ) {
common = range.commonAncestorContainer; startMax = range.commonAncestorContainer;
}
if ( !endMax ) {
endMax = startMax;
} }
while ( startContainer !== common && !startOffset ) { while ( startContainer !== startMax && !startOffset ) {
parent = startContainer.parentNode; parent = startContainer.parentNode;
startOffset = indexOf.call( parent.childNodes, startContainer ); startOffset = indexOf.call( parent.childNodes, startContainer );
startContainer = parent; startContainer = parent;
@ -414,7 +413,7 @@ var moveRangeBoundariesUpTree = function ( range, common ) {
endOffset += 1; endOffset += 1;
maySkipBR = false; maySkipBR = false;
} }
if ( endContainer === common || if ( endContainer === endMax ||
endOffset !== getLength( endContainer ) ) { endOffset !== getLength( endContainer ) ) {
break; break;
} }