Skip to content

Commit

Permalink
Merge inlines when inserting node into range
Browse files Browse the repository at this point in the history
  • Loading branch information
neilj committed Jul 14, 2016
1 parent 1324102 commit 766dea7
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 156 deletions.
139 changes: 62 additions & 77 deletions build/squire-raw.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [],
Expand All @@ -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 );
Expand All @@ -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;
}
Expand All @@ -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
Expand Down Expand Up @@ -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...
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 ];
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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
Expand All @@ -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 );
Expand Down
4 changes: 2 additions & 2 deletions build/squire.js

Large diffs are not rendered by default.

62 changes: 18 additions & 44 deletions source/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 ];
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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
Expand All @@ -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 );
Expand Down
Loading

0 comments on commit 766dea7

Please sign in to comment.