mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 15:23:29 -05:00
Merge inlines when inserting node into range
This commit is contained in:
parent
13241028f1
commit
766dea7ccf
5 changed files with 126 additions and 156 deletions
|
@ -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
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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...
|
||||
|
|
Loading…
Reference in a new issue