mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
parent
239b7d19e9
commit
48fabd491a
6 changed files with 200 additions and 246 deletions
|
@ -265,6 +265,10 @@ function getNextBlock ( node, root ) {
|
||||||
return node !== root ? node : null;
|
return node !== root ? node : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isEmptyBlock ( block ) {
|
||||||
|
return !block.textContent && !block.querySelector( 'IMG' );
|
||||||
|
}
|
||||||
|
|
||||||
function areAlike ( node, node2 ) {
|
function areAlike ( node, node2 ) {
|
||||||
return !isLeaf( node ) && (
|
return !isLeaf( node ) && (
|
||||||
node.nodeType === node2.nodeType &&
|
node.nodeType === node2.nodeType &&
|
||||||
|
@ -348,7 +352,7 @@ function getPath ( node, root ) {
|
||||||
|
|
||||||
function getLength ( node ) {
|
function getLength ( node ) {
|
||||||
var nodeType = node.nodeType;
|
var nodeType = node.nodeType;
|
||||||
return nodeType === ELEMENT_NODE ?
|
return nodeType === ELEMENT_NODE || nodeType === DOCUMENT_FRAGMENT_NODE ?
|
||||||
node.childNodes.length : node.length || 0;
|
node.childNodes.length : node.length || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,11 +655,14 @@ function mergeInlines ( node, range ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeWithBlock ( block, next, range ) {
|
function mergeWithBlock ( block, next, range, root ) {
|
||||||
var container = next,
|
var container = next;
|
||||||
last, offset;
|
var parent, last, offset;
|
||||||
while ( container.parentNode.childNodes.length === 1 ) {
|
while ( ( parent = container.parentNode ) &&
|
||||||
container = container.parentNode;
|
parent !== root &&
|
||||||
|
parent.nodeType === ELEMENT_NODE &&
|
||||||
|
parent.childNodes.length === 1 ) {
|
||||||
|
container = parent;
|
||||||
}
|
}
|
||||||
detach( container );
|
detach( container );
|
||||||
|
|
||||||
|
@ -879,7 +886,7 @@ var deleteContentsOfRange = function ( range, root ) {
|
||||||
// endBlock will have been split, so need to refetch
|
// 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, root );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,134 +908,107 @@ var deleteContentsOfRange = function ( range, root ) {
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
// Contents of range will be deleted.
|
||||||
|
// After method, range will be around inserted content
|
||||||
var insertTreeFragmentIntoRange = function ( range, frag, root ) {
|
var insertTreeFragmentIntoRange = function ( range, frag, root ) {
|
||||||
// Check if it's all inline content
|
var node, block, blockContentsAfterSplit, stopPoint, container, offset;
|
||||||
var allInline = true,
|
var nodeAfterSplit, nodeBeforeSplit, tempRange;
|
||||||
children = frag.childNodes,
|
|
||||||
l = children.length;
|
// Fixup content: ensure no top-level inline, and add cursor fix elements.
|
||||||
while ( l-- ) {
|
fixContainer( frag, root );
|
||||||
if ( !isInline( children[l] ) ) {
|
node = frag;
|
||||||
allInline = false;
|
while ( ( node = getNextBlock( node, root ) ) ) {
|
||||||
break;
|
fixCursor( node, root );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete any selected content
|
// Delete any selected content.
|
||||||
if ( !range.collapsed ) {
|
if ( !range.collapsed ) {
|
||||||
deleteContentsOfRange( range, root );
|
deleteContentsOfRange( range, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move range down into text nodes
|
// Move range down into text nodes.
|
||||||
moveRangeBoundariesDownTree( range );
|
moveRangeBoundariesDownTree( range );
|
||||||
|
range.collapse( false ); // collapse to end
|
||||||
|
|
||||||
if ( allInline ) {
|
// Where will we split up to? First blockquote parent, otherwise root.
|
||||||
// If inline, just insert at the current position.
|
stopPoint = getNearest( range.endContainer, root, 'BLOCKQUOTE' ) || root;
|
||||||
insertNodeInRange( range, frag );
|
|
||||||
if ( range.startContainer !== range.endContainer ) {
|
// Merge the contents of the first block in the frag with the focused block.
|
||||||
mergeInlines( range.endContainer, range );
|
// If there are contents in the block after the focus point, collect this
|
||||||
}
|
// up to insert in the last block later
|
||||||
mergeInlines( range.startContainer, range );
|
block = getStartBlockOfRange( range );
|
||||||
range.collapse( false );
|
if ( block ) {
|
||||||
} else {
|
moveRangeBoundariesUpTree( range, block, block, root );
|
||||||
// Otherwise...
|
range.collapse( true ); // collapse to start
|
||||||
// 1. Split up to blockquote (if a parent) or root
|
container = range.endContainer;
|
||||||
var splitPoint = range.startContainer,
|
offset = range.endOffset;
|
||||||
|
// Remove trailing <br> – we don't want this considered content to be
|
||||||
|
// inserted again later
|
||||||
|
cleanupBRs( block, root, false );
|
||||||
|
if ( isInline( container ) ) {
|
||||||
|
// Split up to block parent.
|
||||||
nodeAfterSplit = split(
|
nodeAfterSplit = split(
|
||||||
splitPoint,
|
container, offset, getPreviousBlock( container, root ), root );
|
||||||
range.startOffset,
|
container = nodeAfterSplit.parentNode;
|
||||||
getNearest( splitPoint.parentNode, root, 'BLOCKQUOTE' ) || root,
|
offset = indexOf.call( container.childNodes, nodeAfterSplit );
|
||||||
root
|
}
|
||||||
),
|
if ( /*isBlock( container ) && */offset !== getLength( container ) ) {
|
||||||
nodeBeforeSplit = nodeAfterSplit.previousSibling,
|
// Collect any inline contents of the block after the range point
|
||||||
startContainer = nodeBeforeSplit,
|
blockContentsAfterSplit =
|
||||||
startOffset = startContainer.childNodes.length,
|
root.ownerDocument.createDocumentFragment();
|
||||||
endContainer = nodeAfterSplit,
|
while ( ( node = container.childNodes[ offset ] ) ) {
|
||||||
endOffset = 0,
|
blockContentsAfterSplit.appendChild( node );
|
||||||
parent = nodeAfterSplit.parentNode,
|
|
||||||
child, node, prev, next, startAnchor;
|
|
||||||
|
|
||||||
// 2. Move down into edge either side of split and insert any inline
|
|
||||||
// nodes at the beginning/end of the fragment
|
|
||||||
while ( ( child = startContainer.lastChild ) &&
|
|
||||||
child.nodeType === ELEMENT_NODE ) {
|
|
||||||
if ( child.nodeName === 'BR' ) {
|
|
||||||
startOffset -= 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
startContainer = child;
|
|
||||||
startOffset = startContainer.childNodes.length;
|
|
||||||
}
|
|
||||||
while ( ( child = endContainer.firstChild ) &&
|
|
||||||
child.nodeType === ELEMENT_NODE &&
|
|
||||||
child.nodeName !== 'BR' ) {
|
|
||||||
endContainer = child;
|
|
||||||
}
|
|
||||||
startAnchor = startContainer.childNodes[ startOffset ] || null;
|
|
||||||
while ( ( child = frag.firstChild ) && isInline( child ) ) {
|
|
||||||
startContainer.insertBefore( child, startAnchor );
|
|
||||||
}
|
|
||||||
while ( ( child = frag.lastChild ) && isInline( child ) ) {
|
|
||||||
endContainer.insertBefore( child, endContainer.firstChild );
|
|
||||||
endOffset += 1;
|
|
||||||
}
|
}
|
||||||
|
// And merge the first block in.
|
||||||
|
mergeWithBlock( container, getNextBlock( frag, frag ), range, root );
|
||||||
|
|
||||||
// 3. Fix cursor then insert block(s) in the fragment
|
// And where we will insert
|
||||||
node = frag;
|
offset = indexOf.call( container.parentNode.childNodes, container ) + 1;
|
||||||
while ( node = getNextBlock( node, root ) ) {
|
container = container.parentNode;
|
||||||
fixCursor( node, root );
|
range.setEnd( container, offset );
|
||||||
}
|
}
|
||||||
parent.insertBefore( frag, nodeAfterSplit );
|
|
||||||
|
|
||||||
// 4. Remove empty nodes created either side of split, then
|
// Is there still any content in the fragment?
|
||||||
// merge containers at the edges.
|
if ( getLength( frag ) ) {
|
||||||
next = nodeBeforeSplit.nextSibling;
|
moveRangeBoundariesUpTree( range, stopPoint, stopPoint, root );
|
||||||
node = getPreviousBlock( next, root );
|
// Now split after block up to blockquote (if a parent) or root
|
||||||
if ( node && !/\S/.test( node.textContent ) ) {
|
nodeAfterSplit = split(
|
||||||
do {
|
range.endContainer, range.endOffset, stopPoint, root );
|
||||||
parent = node.parentNode;
|
nodeBeforeSplit = nodeAfterSplit ?
|
||||||
parent.removeChild( node );
|
nodeAfterSplit.previousSibling :
|
||||||
node = parent;
|
stopPoint.lastChild;
|
||||||
} while ( node && !node.lastChild && node !== root );
|
stopPoint.insertBefore( frag, nodeAfterSplit );
|
||||||
}
|
if ( nodeAfterSplit ) {
|
||||||
if ( !nodeBeforeSplit.parentNode ) {
|
range.setEndBefore( nodeAfterSplit );
|
||||||
nodeBeforeSplit = next.previousSibling;
|
} else {
|
||||||
}
|
range.setEnd( stopPoint, getLength( stopPoint ) );
|
||||||
if ( !startContainer.parentNode ) {
|
|
||||||
startContainer = nodeBeforeSplit || next.parentNode;
|
|
||||||
startOffset = nodeBeforeSplit ?
|
|
||||||
nodeBeforeSplit.childNodes.length : 0;
|
|
||||||
}
|
|
||||||
// Merge inserted containers with edges of split
|
|
||||||
if ( isContainer( next ) ) {
|
|
||||||
mergeContainers( next, root );
|
|
||||||
}
|
}
|
||||||
|
block = getEndBlockOfRange( range, root );
|
||||||
|
|
||||||
|
// Get a reference that won't be invalidated if we merge containers.
|
||||||
|
moveRangeBoundariesDownTree( range );
|
||||||
|
container = range.endContainer;
|
||||||
|
offset = range.endOffset;
|
||||||
|
|
||||||
prev = nodeAfterSplit.previousSibling;
|
|
||||||
node = isBlock( nodeAfterSplit ) ?
|
|
||||||
nodeAfterSplit : getNextBlock( nodeAfterSplit, root );
|
|
||||||
if ( node && !/\S/.test( node.textContent ) ) {
|
|
||||||
do {
|
|
||||||
parent = node.parentNode;
|
|
||||||
parent.removeChild( node );
|
|
||||||
node = parent;
|
|
||||||
} while ( node && !node.lastChild && node !== root );
|
|
||||||
}
|
|
||||||
if ( !nodeAfterSplit.parentNode ) {
|
|
||||||
nodeAfterSplit = prev.nextSibling;
|
|
||||||
}
|
|
||||||
if ( !endOffset ) {
|
|
||||||
endContainer = prev;
|
|
||||||
endOffset = prev.childNodes.length;
|
|
||||||
}
|
|
||||||
// Merge inserted containers with edges of split
|
// Merge inserted containers with edges of split
|
||||||
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
||||||
mergeContainers( nodeAfterSplit, root );
|
mergeContainers( nodeAfterSplit, root );
|
||||||
}
|
}
|
||||||
|
nodeAfterSplit = nodeBeforeSplit && nodeBeforeSplit.nextSibling;
|
||||||
range.setStart( startContainer, startOffset );
|
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
||||||
range.setEnd( endContainer, endOffset );
|
mergeContainers( nodeAfterSplit, root );
|
||||||
moveRangeBoundariesDownTree( range );
|
}
|
||||||
|
range.setEnd( container, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert inline content saved from before.
|
||||||
|
if ( blockContentsAfterSplit ) {
|
||||||
|
tempRange = range.cloneRange();
|
||||||
|
mergeWithBlock( block, blockContentsAfterSplit, tempRange, root );
|
||||||
|
range.setEnd( tempRange.endContainer, tempRange.endOffset );
|
||||||
|
}
|
||||||
|
moveRangeBoundariesDownTree( range );
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
@ -1467,7 +1447,7 @@ var keyHandlers = {
|
||||||
block = parent;
|
block = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !block.textContent ) {
|
if ( isEmptyBlock( block ) ) {
|
||||||
// Break list
|
// Break list
|
||||||
if ( getNearest( block, root, 'UL' ) ||
|
if ( getNearest( block, root, 'UL' ) ||
|
||||||
getNearest( block, root, 'OL' ) ) {
|
getNearest( block, root, 'OL' ) ) {
|
||||||
|
@ -1560,7 +1540,7 @@ var keyHandlers = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise merge.
|
// Otherwise merge.
|
||||||
mergeWithBlock( previous, current, range );
|
mergeWithBlock( previous, current, range, root );
|
||||||
// If deleted line between containers, merge newly adjacent
|
// If deleted line between containers, merge newly adjacent
|
||||||
// containers.
|
// containers.
|
||||||
current = previous.parentNode;
|
current = previous.parentNode;
|
||||||
|
@ -1627,7 +1607,7 @@ var keyHandlers = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise merge.
|
// Otherwise merge.
|
||||||
mergeWithBlock( current, next, range );
|
mergeWithBlock( current, next, range, root );
|
||||||
// If deleted line between containers, merge newly adjacent
|
// If deleted line between containers, merge newly adjacent
|
||||||
// containers.
|
// containers.
|
||||||
next = current.parentNode;
|
next = current.parentNode;
|
||||||
|
@ -4306,11 +4286,8 @@ proto.insertPlainText = function ( plainText, isPaste ) {
|
||||||
for ( i = 0, l = lines.length; i < l; i += 1 ) {
|
for ( i = 0, l = lines.length; i < l; i += 1 ) {
|
||||||
line = lines[i];
|
line = lines[i];
|
||||||
line = escapeHTMLFragement( line ).replace( / (?= )/g, ' ' );
|
line = escapeHTMLFragement( line ).replace( / (?= )/g, ' ' );
|
||||||
// Wrap all but first/last lines in <div></div>
|
// Wrap each line in <div></div>
|
||||||
if ( i && i + 1 < l ) {
|
lines[i] = openBlock + ( line || '<BR>' ) + closeBlock;
|
||||||
line = openBlock + ( line || '<BR>' ) + closeBlock;
|
|
||||||
}
|
|
||||||
lines[i] = line;
|
|
||||||
}
|
}
|
||||||
return this.insertHTML( lines.join( '' ), isPaste );
|
return this.insertHTML( lines.join( '' ), isPaste );
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1852,11 +1852,8 @@ proto.insertPlainText = function ( plainText, isPaste ) {
|
||||||
for ( i = 0, l = lines.length; i < l; i += 1 ) {
|
for ( i = 0, l = lines.length; i < l; i += 1 ) {
|
||||||
line = lines[i];
|
line = lines[i];
|
||||||
line = escapeHTMLFragement( line ).replace( / (?= )/g, ' ' );
|
line = escapeHTMLFragement( line ).replace( / (?= )/g, ' ' );
|
||||||
// Wrap all but first/last lines in <div></div>
|
// Wrap each line in <div></div>
|
||||||
if ( i && i + 1 < l ) {
|
lines[i] = openBlock + ( line || '<BR>' ) + closeBlock;
|
||||||
line = openBlock + ( line || '<BR>' ) + closeBlock;
|
|
||||||
}
|
|
||||||
lines[i] = line;
|
|
||||||
}
|
}
|
||||||
return this.insertHTML( lines.join( '' ), isPaste );
|
return this.insertHTML( lines.join( '' ), isPaste );
|
||||||
};
|
};
|
||||||
|
|
|
@ -188,7 +188,7 @@ var keyHandlers = {
|
||||||
block = parent;
|
block = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !block.textContent ) {
|
if ( isEmptyBlock( block ) ) {
|
||||||
// Break list
|
// Break list
|
||||||
if ( getNearest( block, root, 'UL' ) ||
|
if ( getNearest( block, root, 'UL' ) ||
|
||||||
getNearest( block, root, 'OL' ) ) {
|
getNearest( block, root, 'OL' ) ) {
|
||||||
|
@ -281,7 +281,7 @@ var keyHandlers = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise merge.
|
// Otherwise merge.
|
||||||
mergeWithBlock( previous, current, range );
|
mergeWithBlock( previous, current, range, root );
|
||||||
// If deleted line between containers, merge newly adjacent
|
// If deleted line between containers, merge newly adjacent
|
||||||
// containers.
|
// containers.
|
||||||
current = previous.parentNode;
|
current = previous.parentNode;
|
||||||
|
@ -348,7 +348,7 @@ var keyHandlers = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise merge.
|
// Otherwise merge.
|
||||||
mergeWithBlock( current, next, range );
|
mergeWithBlock( current, next, range, root );
|
||||||
// If deleted line between containers, merge newly adjacent
|
// If deleted line between containers, merge newly adjacent
|
||||||
// containers.
|
// containers.
|
||||||
next = current.parentNode;
|
next = current.parentNode;
|
||||||
|
|
|
@ -85,6 +85,10 @@ function getNextBlock ( node, root ) {
|
||||||
return node !== root ? node : null;
|
return node !== root ? node : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isEmptyBlock ( block ) {
|
||||||
|
return !block.textContent && !block.querySelector( 'IMG' );
|
||||||
|
}
|
||||||
|
|
||||||
function areAlike ( node, node2 ) {
|
function areAlike ( node, node2 ) {
|
||||||
return !isLeaf( node ) && (
|
return !isLeaf( node ) && (
|
||||||
node.nodeType === node2.nodeType &&
|
node.nodeType === node2.nodeType &&
|
||||||
|
@ -168,7 +172,7 @@ function getPath ( node, root ) {
|
||||||
|
|
||||||
function getLength ( node ) {
|
function getLength ( node ) {
|
||||||
var nodeType = node.nodeType;
|
var nodeType = node.nodeType;
|
||||||
return nodeType === ELEMENT_NODE ?
|
return nodeType === ELEMENT_NODE || nodeType === DOCUMENT_FRAGMENT_NODE ?
|
||||||
node.childNodes.length : node.length || 0;
|
node.childNodes.length : node.length || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,11 +475,14 @@ function mergeInlines ( node, range ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeWithBlock ( block, next, range ) {
|
function mergeWithBlock ( block, next, range, root ) {
|
||||||
var container = next,
|
var container = next;
|
||||||
last, offset;
|
var parent, last, offset;
|
||||||
while ( container.parentNode.childNodes.length === 1 ) {
|
while ( ( parent = container.parentNode ) &&
|
||||||
container = container.parentNode;
|
parent !== root &&
|
||||||
|
parent.nodeType === ELEMENT_NODE &&
|
||||||
|
parent.childNodes.length === 1 ) {
|
||||||
|
container = parent;
|
||||||
}
|
}
|
||||||
detach( container );
|
detach( container );
|
||||||
|
|
||||||
|
|
189
source/Range.js
189
source/Range.js
|
@ -154,7 +154,7 @@ var deleteContentsOfRange = function ( range, root ) {
|
||||||
// endBlock will have been split, so need to refetch
|
// 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, root );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,134 +176,107 @@ var deleteContentsOfRange = function ( range, root ) {
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
// Contents of range will be deleted.
|
||||||
|
// After method, range will be around inserted content
|
||||||
var insertTreeFragmentIntoRange = function ( range, frag, root ) {
|
var insertTreeFragmentIntoRange = function ( range, frag, root ) {
|
||||||
// Check if it's all inline content
|
var node, block, blockContentsAfterSplit, stopPoint, container, offset;
|
||||||
var allInline = true,
|
var nodeAfterSplit, nodeBeforeSplit, tempRange;
|
||||||
children = frag.childNodes,
|
|
||||||
l = children.length;
|
// Fixup content: ensure no top-level inline, and add cursor fix elements.
|
||||||
while ( l-- ) {
|
fixContainer( frag, root );
|
||||||
if ( !isInline( children[l] ) ) {
|
node = frag;
|
||||||
allInline = false;
|
while ( ( node = getNextBlock( node, root ) ) ) {
|
||||||
break;
|
fixCursor( node, root );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete any selected content
|
// Delete any selected content.
|
||||||
if ( !range.collapsed ) {
|
if ( !range.collapsed ) {
|
||||||
deleteContentsOfRange( range, root );
|
deleteContentsOfRange( range, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move range down into text nodes
|
// Move range down into text nodes.
|
||||||
moveRangeBoundariesDownTree( range );
|
moveRangeBoundariesDownTree( range );
|
||||||
|
range.collapse( false ); // collapse to end
|
||||||
|
|
||||||
if ( allInline ) {
|
// Where will we split up to? First blockquote parent, otherwise root.
|
||||||
// If inline, just insert at the current position.
|
stopPoint = getNearest( range.endContainer, root, 'BLOCKQUOTE' ) || root;
|
||||||
insertNodeInRange( range, frag );
|
|
||||||
if ( range.startContainer !== range.endContainer ) {
|
// Merge the contents of the first block in the frag with the focused block.
|
||||||
mergeInlines( range.endContainer, range );
|
// If there are contents in the block after the focus point, collect this
|
||||||
}
|
// up to insert in the last block later
|
||||||
mergeInlines( range.startContainer, range );
|
block = getStartBlockOfRange( range );
|
||||||
range.collapse( false );
|
if ( block ) {
|
||||||
} else {
|
moveRangeBoundariesUpTree( range, block, block, root );
|
||||||
// Otherwise...
|
range.collapse( true ); // collapse to start
|
||||||
// 1. Split up to blockquote (if a parent) or root
|
container = range.endContainer;
|
||||||
var splitPoint = range.startContainer,
|
offset = range.endOffset;
|
||||||
|
// Remove trailing <br> – we don't want this considered content to be
|
||||||
|
// inserted again later
|
||||||
|
cleanupBRs( block, root, false );
|
||||||
|
if ( isInline( container ) ) {
|
||||||
|
// Split up to block parent.
|
||||||
nodeAfterSplit = split(
|
nodeAfterSplit = split(
|
||||||
splitPoint,
|
container, offset, getPreviousBlock( container, root ), root );
|
||||||
range.startOffset,
|
container = nodeAfterSplit.parentNode;
|
||||||
getNearest( splitPoint.parentNode, root, 'BLOCKQUOTE' ) || root,
|
offset = indexOf.call( container.childNodes, nodeAfterSplit );
|
||||||
root
|
}
|
||||||
),
|
if ( /*isBlock( container ) && */offset !== getLength( container ) ) {
|
||||||
nodeBeforeSplit = nodeAfterSplit.previousSibling,
|
// Collect any inline contents of the block after the range point
|
||||||
startContainer = nodeBeforeSplit,
|
blockContentsAfterSplit =
|
||||||
startOffset = startContainer.childNodes.length,
|
root.ownerDocument.createDocumentFragment();
|
||||||
endContainer = nodeAfterSplit,
|
while ( ( node = container.childNodes[ offset ] ) ) {
|
||||||
endOffset = 0,
|
blockContentsAfterSplit.appendChild( node );
|
||||||
parent = nodeAfterSplit.parentNode,
|
|
||||||
child, node, prev, next, startAnchor;
|
|
||||||
|
|
||||||
// 2. Move down into edge either side of split and insert any inline
|
|
||||||
// nodes at the beginning/end of the fragment
|
|
||||||
while ( ( child = startContainer.lastChild ) &&
|
|
||||||
child.nodeType === ELEMENT_NODE ) {
|
|
||||||
if ( child.nodeName === 'BR' ) {
|
|
||||||
startOffset -= 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
startContainer = child;
|
|
||||||
startOffset = startContainer.childNodes.length;
|
|
||||||
}
|
|
||||||
while ( ( child = endContainer.firstChild ) &&
|
|
||||||
child.nodeType === ELEMENT_NODE &&
|
|
||||||
child.nodeName !== 'BR' ) {
|
|
||||||
endContainer = child;
|
|
||||||
}
|
|
||||||
startAnchor = startContainer.childNodes[ startOffset ] || null;
|
|
||||||
while ( ( child = frag.firstChild ) && isInline( child ) ) {
|
|
||||||
startContainer.insertBefore( child, startAnchor );
|
|
||||||
}
|
|
||||||
while ( ( child = frag.lastChild ) && isInline( child ) ) {
|
|
||||||
endContainer.insertBefore( child, endContainer.firstChild );
|
|
||||||
endOffset += 1;
|
|
||||||
}
|
}
|
||||||
|
// And merge the first block in.
|
||||||
|
mergeWithBlock( container, getNextBlock( frag, frag ), range, root );
|
||||||
|
|
||||||
// 3. Fix cursor then insert block(s) in the fragment
|
// And where we will insert
|
||||||
node = frag;
|
offset = indexOf.call( container.parentNode.childNodes, container ) + 1;
|
||||||
while ( node = getNextBlock( node, root ) ) {
|
container = container.parentNode;
|
||||||
fixCursor( node, root );
|
range.setEnd( container, offset );
|
||||||
}
|
}
|
||||||
parent.insertBefore( frag, nodeAfterSplit );
|
|
||||||
|
|
||||||
// 4. Remove empty nodes created either side of split, then
|
// Is there still any content in the fragment?
|
||||||
// merge containers at the edges.
|
if ( getLength( frag ) ) {
|
||||||
next = nodeBeforeSplit.nextSibling;
|
moveRangeBoundariesUpTree( range, stopPoint, stopPoint, root );
|
||||||
node = getPreviousBlock( next, root );
|
// Now split after block up to blockquote (if a parent) or root
|
||||||
if ( node && !/\S/.test( node.textContent ) ) {
|
nodeAfterSplit = split(
|
||||||
do {
|
range.endContainer, range.endOffset, stopPoint, root );
|
||||||
parent = node.parentNode;
|
nodeBeforeSplit = nodeAfterSplit ?
|
||||||
parent.removeChild( node );
|
nodeAfterSplit.previousSibling :
|
||||||
node = parent;
|
stopPoint.lastChild;
|
||||||
} while ( node && !node.lastChild && node !== root );
|
stopPoint.insertBefore( frag, nodeAfterSplit );
|
||||||
}
|
if ( nodeAfterSplit ) {
|
||||||
if ( !nodeBeforeSplit.parentNode ) {
|
range.setEndBefore( nodeAfterSplit );
|
||||||
nodeBeforeSplit = next.previousSibling;
|
} else {
|
||||||
}
|
range.setEnd( stopPoint, getLength( stopPoint ) );
|
||||||
if ( !startContainer.parentNode ) {
|
|
||||||
startContainer = nodeBeforeSplit || next.parentNode;
|
|
||||||
startOffset = nodeBeforeSplit ?
|
|
||||||
nodeBeforeSplit.childNodes.length : 0;
|
|
||||||
}
|
|
||||||
// Merge inserted containers with edges of split
|
|
||||||
if ( isContainer( next ) ) {
|
|
||||||
mergeContainers( next, root );
|
|
||||||
}
|
}
|
||||||
|
block = getEndBlockOfRange( range, root );
|
||||||
|
|
||||||
|
// Get a reference that won't be invalidated if we merge containers.
|
||||||
|
moveRangeBoundariesDownTree( range );
|
||||||
|
container = range.endContainer;
|
||||||
|
offset = range.endOffset;
|
||||||
|
|
||||||
prev = nodeAfterSplit.previousSibling;
|
|
||||||
node = isBlock( nodeAfterSplit ) ?
|
|
||||||
nodeAfterSplit : getNextBlock( nodeAfterSplit, root );
|
|
||||||
if ( node && !/\S/.test( node.textContent ) ) {
|
|
||||||
do {
|
|
||||||
parent = node.parentNode;
|
|
||||||
parent.removeChild( node );
|
|
||||||
node = parent;
|
|
||||||
} while ( node && !node.lastChild && node !== root );
|
|
||||||
}
|
|
||||||
if ( !nodeAfterSplit.parentNode ) {
|
|
||||||
nodeAfterSplit = prev.nextSibling;
|
|
||||||
}
|
|
||||||
if ( !endOffset ) {
|
|
||||||
endContainer = prev;
|
|
||||||
endOffset = prev.childNodes.length;
|
|
||||||
}
|
|
||||||
// Merge inserted containers with edges of split
|
// Merge inserted containers with edges of split
|
||||||
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
||||||
mergeContainers( nodeAfterSplit, root );
|
mergeContainers( nodeAfterSplit, root );
|
||||||
}
|
}
|
||||||
|
nodeAfterSplit = nodeBeforeSplit && nodeBeforeSplit.nextSibling;
|
||||||
range.setStart( startContainer, startOffset );
|
if ( nodeAfterSplit && isContainer( nodeAfterSplit ) ) {
|
||||||
range.setEnd( endContainer, endOffset );
|
mergeContainers( nodeAfterSplit, root );
|
||||||
moveRangeBoundariesDownTree( range );
|
}
|
||||||
|
range.setEnd( container, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert inline content saved from before.
|
||||||
|
if ( blockContentsAfterSplit ) {
|
||||||
|
tempRange = range.cloneRange();
|
||||||
|
mergeWithBlock( block, blockContentsAfterSplit, tempRange, root );
|
||||||
|
range.setEnd( tempRange.endContainer, tempRange.endOffset );
|
||||||
|
}
|
||||||
|
moveRangeBoundariesDownTree( range );
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
Loading…
Reference in a new issue