0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 07:13:08 -05:00

Merge inlines when inserting node into range

This commit is contained in:
Neil Jenkins 2016-07-14 12:15:06 +10:00
parent 13241028f1
commit 766dea7ccf
5 changed files with 126 additions and 156 deletions

View file

@ -546,10 +546,7 @@ function split ( node, offset, stopNode, root ) {
return offset;
}
function mergeInlines ( node, range ) {
if ( node.nodeType !== ELEMENT_NODE ) {
return;
}
function _mergeInlines ( node, fakeRange ) {
var children = node.childNodes,
l = children.length,
frags = [],
@ -559,30 +556,30 @@ function mergeInlines ( node, range ) {
prev = l && children[ l - 1 ];
if ( l && isInline( child ) && areAlike( child, prev ) &&
!leafNodeNames[ child.nodeName ] ) {
if ( range.startContainer === child ) {
range.startContainer = prev;
range.startOffset += getLength( prev );
if ( fakeRange.startContainer === child ) {
fakeRange.startContainer = prev;
fakeRange.startOffset += getLength( prev );
}
if ( range.endContainer === child ) {
range.endContainer = prev;
range.endOffset += getLength( prev );
if ( fakeRange.endContainer === child ) {
fakeRange.endContainer = prev;
fakeRange.endOffset += getLength( prev );
}
if ( range.startContainer === node ) {
if ( range.startOffset > l ) {
range.startOffset -= 1;
if ( fakeRange.startContainer === node ) {
if ( fakeRange.startOffset > l ) {
fakeRange.startOffset -= 1;
}
else if ( range.startOffset === l ) {
range.startContainer = prev;
range.startOffset = getLength( prev );
else if ( fakeRange.startOffset === l ) {
fakeRange.startContainer = prev;
fakeRange.startOffset = getLength( prev );
}
}
if ( range.endContainer === node ) {
if ( range.endOffset > l ) {
range.endOffset -= 1;
if ( fakeRange.endContainer === node ) {
if ( fakeRange.endOffset > l ) {
fakeRange.endOffset -= 1;
}
else if ( range.endOffset === l ) {
range.endContainer = prev;
range.endOffset = getLength( prev );
else if ( fakeRange.endOffset === l ) {
fakeRange.endContainer = prev;
fakeRange.endOffset = getLength( prev );
}
}
detach( child );
@ -598,14 +595,31 @@ function mergeInlines ( node, range ) {
while ( len-- ) {
child.appendChild( frags.pop() );
}
mergeInlines( child, range );
_mergeInlines( child, fakeRange );
}
}
}
function mergeInlines ( node, range ) {
if ( node.nodeType === TEXT_NODE ) {
node = node.parentNode;
}
if ( node.nodeType === ELEMENT_NODE ) {
var fakeRange = {
startContainer: range.startContainer,
startOffset: range.startOffset,
endContainer: range.endContainer,
endOffset: range.endOffset
};
_mergeInlines( node, fakeRange );
range.setStart( fakeRange.startContainer, fakeRange.startOffset );
range.setEnd( fakeRange.endContainer, fakeRange.endOffset );
}
}
function mergeWithBlock ( block, next, range ) {
var container = next,
last, offset, _range;
last, offset;
while ( container.parentNode.childNodes.length === 1 ) {
container = container.parentNode;
}
@ -620,18 +634,11 @@ function mergeWithBlock ( block, next, range ) {
offset -= 1;
}
_range = {
startContainer: block,
startOffset: offset,
endContainer: block,
endOffset: offset
};
block.appendChild( empty( next ) );
mergeInlines( block, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setStart( block, offset );
range.collapse( true );
mergeInlines( block, range );
// Opera inserts a BR if you delete the last piece of text
// in a block-level element. Unfortunately, it then gets
@ -886,6 +893,10 @@ var insertTreeFragmentIntoRange = function ( range, frag, root ) {
if ( allInline ) {
// If inline, just insert at the current position.
insertNodeInRange( range, frag );
if ( range.startContainer !== range.endContainer ) {
mergeInlines( range.endContainer, range );
}
mergeInlines( range.startContainer, range );
range.collapse( false );
} else {
// Otherwise...
@ -2691,12 +2702,7 @@ proto.getCursorPosition = function ( range ) {
rect = node.getBoundingClientRect();
parent = node.parentNode;
parent.removeChild( node );
mergeInlines( parent, {
startContainer: range.startContainer,
endContainer: range.endContainer,
startOffset: range.startOffset,
endOffset: range.endOffset
});
mergeInlines( parent, range );
}
return rect;
};
@ -2969,38 +2975,31 @@ proto._getRangeAndRemoveBookmark = function ( range ) {
if ( start && end ) {
var startContainer = start.parentNode,
endContainer = end.parentNode,
collapsed;
var _range = {
startContainer: startContainer,
endContainer: endContainer,
startOffset: indexOf.call( startContainer.childNodes, start ),
endOffset: indexOf.call( endContainer.childNodes, end )
};
startOffset = indexOf.call( startContainer.childNodes, start ),
endOffset = indexOf.call( endContainer.childNodes, end );
if ( startContainer === endContainer ) {
_range.endOffset -= 1;
endOffset -= 1;
}
detach( start );
detach( end );
// Merge any text nodes we split
mergeInlines( startContainer, _range );
if ( startContainer !== endContainer ) {
mergeInlines( endContainer, _range );
}
if ( !range ) {
range = this._doc.createRange();
}
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
collapsed = range.collapsed;
range.setStart( startContainer, startOffset );
range.setEnd( endContainer, endOffset );
// Merge any text nodes we split
mergeInlines( startContainer, range );
if ( startContainer !== endContainer ) {
mergeInlines( endContainer, range );
}
// If we didn't split a text node, we should move into any adjacent
// text node to current selection point
if ( collapsed ) {
if ( range.collapsed ) {
startContainer = range.startContainer;
if ( startContainer.nodeType === TEXT_NODE ) {
endContainer = startContainer.childNodes[ range.startOffset ];
@ -3458,15 +3457,7 @@ proto._removeFormat = function ( tag, attributes, range, partial ) {
if ( fixer ) {
range.collapse( false );
}
var _range = {
startContainer: range.startContainer,
startOffset: range.startOffset,
endContainer: range.endContainer,
endOffset: range.endOffset
};
mergeInlines( root, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
mergeInlines( root, range );
return range;
};
@ -4299,7 +4290,7 @@ proto.removeAllFormatting = function ( range ) {
var cleanNodes = doc.createDocumentFragment();
var nodeAfterSplit = split( endContainer, endOffset, stopNode, root );
var nodeInSplit = split( startContainer, startOffset, stopNode, root );
var nextNode, _range, childNodes;
var nextNode, childNodes;
// Then replace contents in split with a cleaned version of the same:
// blocks become default blocks, text and leaf nodes survive, everything
@ -4326,15 +4317,9 @@ proto.removeAllFormatting = function ( range ) {
}
// Merge text nodes at edges, if possible
_range = {
startContainer: stopNode,
startOffset: startOffset,
endContainer: stopNode,
endOffset: endOffset
};
mergeInlines( stopNode, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
range.setStart( stopNode, startOffset );
range.setEnd( stopNode, endOffset );
mergeInlines( stopNode, range );
// And move back down the tree
moveRangeBoundariesDownTree( range );

File diff suppressed because one or more lines are too long

View file

@ -392,12 +392,7 @@ proto.getCursorPosition = function ( range ) {
rect = node.getBoundingClientRect();
parent = node.parentNode;
parent.removeChild( node );
mergeInlines( parent, {
startContainer: range.startContainer,
endContainer: range.endContainer,
startOffset: range.startOffset,
endOffset: range.endOffset
});
mergeInlines( parent, range );
}
return rect;
};
@ -670,38 +665,31 @@ proto._getRangeAndRemoveBookmark = function ( range ) {
if ( start && end ) {
var startContainer = start.parentNode,
endContainer = end.parentNode,
collapsed;
var _range = {
startContainer: startContainer,
endContainer: endContainer,
startOffset: indexOf.call( startContainer.childNodes, start ),
endOffset: indexOf.call( endContainer.childNodes, end )
};
startOffset = indexOf.call( startContainer.childNodes, start ),
endOffset = indexOf.call( endContainer.childNodes, end );
if ( startContainer === endContainer ) {
_range.endOffset -= 1;
endOffset -= 1;
}
detach( start );
detach( end );
// Merge any text nodes we split
mergeInlines( startContainer, _range );
if ( startContainer !== endContainer ) {
mergeInlines( endContainer, _range );
}
if ( !range ) {
range = this._doc.createRange();
}
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
collapsed = range.collapsed;
range.setStart( startContainer, startOffset );
range.setEnd( endContainer, endOffset );
// Merge any text nodes we split
mergeInlines( startContainer, range );
if ( startContainer !== endContainer ) {
mergeInlines( endContainer, range );
}
// If we didn't split a text node, we should move into any adjacent
// text node to current selection point
if ( collapsed ) {
if ( range.collapsed ) {
startContainer = range.startContainer;
if ( startContainer.nodeType === TEXT_NODE ) {
endContainer = startContainer.childNodes[ range.startOffset ];
@ -1159,15 +1147,7 @@ proto._removeFormat = function ( tag, attributes, range, partial ) {
if ( fixer ) {
range.collapse( false );
}
var _range = {
startContainer: range.startContainer,
startOffset: range.startOffset,
endContainer: range.endContainer,
endOffset: range.endOffset
};
mergeInlines( root, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
mergeInlines( root, range );
return range;
};
@ -2000,7 +1980,7 @@ proto.removeAllFormatting = function ( range ) {
var cleanNodes = doc.createDocumentFragment();
var nodeAfterSplit = split( endContainer, endOffset, stopNode, root );
var nodeInSplit = split( startContainer, startOffset, stopNode, root );
var nextNode, _range, childNodes;
var nextNode, childNodes;
// Then replace contents in split with a cleaned version of the same:
// blocks become default blocks, text and leaf nodes survive, everything
@ -2027,15 +2007,9 @@ proto.removeAllFormatting = function ( range ) {
}
// Merge text nodes at edges, if possible
_range = {
startContainer: stopNode,
startOffset: startOffset,
endContainer: stopNode,
endOffset: endOffset
};
mergeInlines( stopNode, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
range.setStart( stopNode, startOffset );
range.setEnd( stopNode, endOffset );
mergeInlines( stopNode, range );
// And move back down the tree
moveRangeBoundariesDownTree( range );

View file

@ -368,10 +368,7 @@ function split ( node, offset, stopNode, root ) {
return offset;
}
function mergeInlines ( node, range ) {
if ( node.nodeType !== ELEMENT_NODE ) {
return;
}
function _mergeInlines ( node, fakeRange ) {
var children = node.childNodes,
l = children.length,
frags = [],
@ -381,30 +378,30 @@ function mergeInlines ( node, range ) {
prev = l && children[ l - 1 ];
if ( l && isInline( child ) && areAlike( child, prev ) &&
!leafNodeNames[ child.nodeName ] ) {
if ( range.startContainer === child ) {
range.startContainer = prev;
range.startOffset += getLength( prev );
if ( fakeRange.startContainer === child ) {
fakeRange.startContainer = prev;
fakeRange.startOffset += getLength( prev );
}
if ( range.endContainer === child ) {
range.endContainer = prev;
range.endOffset += getLength( prev );
if ( fakeRange.endContainer === child ) {
fakeRange.endContainer = prev;
fakeRange.endOffset += getLength( prev );
}
if ( range.startContainer === node ) {
if ( range.startOffset > l ) {
range.startOffset -= 1;
if ( fakeRange.startContainer === node ) {
if ( fakeRange.startOffset > l ) {
fakeRange.startOffset -= 1;
}
else if ( range.startOffset === l ) {
range.startContainer = prev;
range.startOffset = getLength( prev );
else if ( fakeRange.startOffset === l ) {
fakeRange.startContainer = prev;
fakeRange.startOffset = getLength( prev );
}
}
if ( range.endContainer === node ) {
if ( range.endOffset > l ) {
range.endOffset -= 1;
if ( fakeRange.endContainer === node ) {
if ( fakeRange.endOffset > l ) {
fakeRange.endOffset -= 1;
}
else if ( range.endOffset === l ) {
range.endContainer = prev;
range.endOffset = getLength( prev );
else if ( fakeRange.endOffset === l ) {
fakeRange.endContainer = prev;
fakeRange.endOffset = getLength( prev );
}
}
detach( child );
@ -420,14 +417,31 @@ function mergeInlines ( node, range ) {
while ( len-- ) {
child.appendChild( frags.pop() );
}
mergeInlines( child, range );
_mergeInlines( child, fakeRange );
}
}
}
function mergeInlines ( node, range ) {
if ( node.nodeType === TEXT_NODE ) {
node = node.parentNode;
}
if ( node.nodeType === ELEMENT_NODE ) {
var fakeRange = {
startContainer: range.startContainer,
startOffset: range.startOffset,
endContainer: range.endContainer,
endOffset: range.endOffset
};
_mergeInlines( node, fakeRange );
range.setStart( fakeRange.startContainer, fakeRange.startOffset );
range.setEnd( fakeRange.endContainer, fakeRange.endOffset );
}
}
function mergeWithBlock ( block, next, range ) {
var container = next,
last, offset, _range;
last, offset;
while ( container.parentNode.childNodes.length === 1 ) {
container = container.parentNode;
}
@ -442,18 +456,11 @@ function mergeWithBlock ( block, next, range ) {
offset -= 1;
}
_range = {
startContainer: block,
startOffset: offset,
endContainer: block,
endOffset: offset
};
block.appendChild( empty( next ) );
mergeInlines( block, _range );
range.setStart( _range.startContainer, _range.startOffset );
range.setStart( block, offset );
range.collapse( true );
mergeInlines( block, range );
// Opera inserts a BR if you delete the last piece of text
// in a block-level element. Unfortunately, it then gets

View file

@ -202,6 +202,10 @@ var insertTreeFragmentIntoRange = function ( range, frag, root ) {
if ( allInline ) {
// If inline, just insert at the current position.
insertNodeInRange( range, frag );
if ( range.startContainer !== range.endContainer ) {
mergeInlines( range.endContainer, range );
}
mergeInlines( range.startContainer, range );
range.collapse( false );
} else {
// Otherwise...