0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2025-01-03 13:16:31 -05:00

Better fix up of mixed inline/block content.

This commit is contained in:
Neil Jenkins 2014-05-27 11:31:06 +10:00
parent 46706db889
commit aca8fd4fab
4 changed files with 96 additions and 78 deletions

View file

@ -508,7 +508,7 @@ function mergeContainers ( node ) {
var prev = node.previousSibling, var prev = node.previousSibling,
first = node.firstChild, first = node.firstChild,
isListItem = ( node.nodeName === 'LI' ), isListItem = ( node.nodeName === 'LI' ),
block; needsFix, block;
// Do not merge LIs, unless it only contains a UL // Do not merge LIs, unless it only contains a UL
if ( isListItem && ( !first || !/^[OU]L$/.test( first.nodeName ) ) ) { if ( isListItem && ( !first || !/^[OU]L$/.test( first.nodeName ) ) ) {
@ -526,7 +526,11 @@ function mergeContainers ( node ) {
} }
} }
detach( node ); detach( node );
needsFix = !isContainer( node );
prev.appendChild( empty( node ) ); prev.appendChild( empty( node ) );
if ( needsFix ) {
fixContainer( prev );
}
if ( first ) { if ( first ) {
mergeContainers( first ); mergeContainers( first );
} }
@ -537,6 +541,42 @@ function mergeContainers ( node ) {
} }
} }
// Recursively examine container nodes and wrap any inline children.
function fixContainer ( container ) {
var children = container.childNodes,
doc = container.ownerDocument,
wrapper = null,
i, l, child, isBR;
for ( i = 0, l = children.length; i < l; i += 1 ) {
child = children[i];
isBR = child.nodeName === 'BR';
if ( !isBR && isInline( child ) ) {
if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); }
wrapper.appendChild( child );
i -= 1;
l -= 1;
} else if ( isBR || wrapper ) {
if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); }
fixCursor( wrapper );
if ( isBR ) {
container.replaceChild( wrapper, child );
} else {
container.insertBefore( wrapper, child );
i += 1;
l += 1;
}
wrapper = null;
}
if ( isContainer( child ) ) {
fixContainer( child );
}
}
if ( wrapper ) {
container.appendChild( fixCursor( wrapper ) );
}
return container;
}
function createElement ( doc, tag, props, children ) { function createElement ( doc, tag, props, children ) {
var el = doc.createElement( tag ), var el = doc.createElement( tag ),
attr, value, i, l; attr, value, i, l;
@ -1114,6 +1154,7 @@ var expandRangeToBlockBoundaries = function ( range ) {
mergeInlines, mergeInlines,
mergeWithBlock, mergeWithBlock,
mergeContainers, mergeContainers,
fixContainer,
createElement, createElement,
forEachTextNodeInRange, forEachTextNodeInRange,
@ -2092,7 +2133,7 @@ var removeList = function ( frag ) {
child = children[ll]; child = children[ll];
replaceWith( child, empty( child ) ); replaceWith( child, empty( child ) );
} }
wrapTopLevelInline( listFrag, 'DIV' ); fixContainer( listFrag );
replaceWith( list, listFrag ); replaceWith( list, listFrag );
} }
return frag; return frag;
@ -2153,7 +2194,7 @@ var decreaseListLevel = function ( frag ) {
item = parent; item = parent;
} }
}, this ); }, this );
wrapTopLevelInline( frag, 'DIV' ); fixContainer( frag );
return frag; return frag;
}; };
@ -2450,38 +2491,6 @@ var cleanTree = function ( node, allowStyles ) {
return node; return node;
}; };
var wrapTopLevelInline = function ( root, tag ) {
var children = root.childNodes,
doc = root.ownerDocument,
wrapper = null,
i, l, child, isBR;
for ( i = 0, l = children.length; i < l; i += 1 ) {
child = children[i];
isBR = child.nodeName === 'BR';
if ( !isBR && isInline( child ) ) {
if ( !wrapper ) { wrapper = createElement( doc, tag ); }
wrapper.appendChild( child );
i -= 1;
l -= 1;
} else if ( isBR || wrapper ) {
if ( !wrapper ) { wrapper = createElement( doc, tag ); }
fixCursor( wrapper );
if ( isBR ) {
root.replaceChild( wrapper, child );
} else {
root.insertBefore( wrapper, child );
i += 1;
l += 1;
}
wrapper = null;
}
}
if ( wrapper ) {
root.appendChild( fixCursor( wrapper ) );
}
return root;
};
var notWSTextNode = function ( node ) { var notWSTextNode = function ( node ) {
return ( node.nodeType === ELEMENT_NODE ? return ( node.nodeType === ELEMENT_NODE ?
node.nodeName === 'BR' : node.nodeName === 'BR' :
@ -2532,7 +2541,7 @@ var cleanupBRs = function ( root ) {
// If this is not inside a block, replace it by wrapping // If this is not inside a block, replace it by wrapping
// inlines in DIV. // inlines in DIV.
if ( !isBlock( block ) || !tagAfterSplit[ block.nodeName ] ) { if ( !isBlock( block ) || !tagAfterSplit[ block.nodeName ] ) {
wrapTopLevelInline( block, 'DIV' ); fixContainer( block );
} }
// If in a block we can split, split it instead, but only if there // If in a block we can split, split it instead, but only if there
// is actual text content in the block. Otherwise, the <br> is a // is actual text content in the block. Otherwise, the <br> is a
@ -2833,7 +2842,7 @@ var keyHandlers = {
} }
} }
} }
wrapTopLevelInline( block, 'DIV' ); fixContainer( block );
splitTag = 'DIV'; splitTag = 'DIV';
if ( !splitNode ) { if ( !splitNode ) {
splitNode = block.firstChild; splitNode = block.firstChild;
@ -3188,7 +3197,7 @@ proto.setHTML = function ( html ) {
cleanTree( frag, true ); cleanTree( frag, true );
cleanupBRs( frag ); cleanupBRs( frag );
wrapTopLevelInline( frag, 'DIV' ); fixContainer( frag );
// Fix cursor // Fix cursor
var node = frag; var node = frag;

File diff suppressed because one or more lines are too long

View file

@ -42,6 +42,7 @@
mergeInlines, mergeInlines,
mergeWithBlock, mergeWithBlock,
mergeContainers, mergeContainers,
fixContainer,
createElement, createElement,
forEachTextNodeInRange, forEachTextNodeInRange,
@ -1020,7 +1021,7 @@ var removeList = function ( frag ) {
child = children[ll]; child = children[ll];
replaceWith( child, empty( child ) ); replaceWith( child, empty( child ) );
} }
wrapTopLevelInline( listFrag, 'DIV' ); fixContainer( listFrag );
replaceWith( list, listFrag ); replaceWith( list, listFrag );
} }
return frag; return frag;
@ -1081,7 +1082,7 @@ var decreaseListLevel = function ( frag ) {
item = parent; item = parent;
} }
}, this ); }, this );
wrapTopLevelInline( frag, 'DIV' ); fixContainer( frag );
return frag; return frag;
}; };
@ -1378,38 +1379,6 @@ var cleanTree = function ( node, allowStyles ) {
return node; return node;
}; };
var wrapTopLevelInline = function ( root, tag ) {
var children = root.childNodes,
doc = root.ownerDocument,
wrapper = null,
i, l, child, isBR;
for ( i = 0, l = children.length; i < l; i += 1 ) {
child = children[i];
isBR = child.nodeName === 'BR';
if ( !isBR && isInline( child ) ) {
if ( !wrapper ) { wrapper = createElement( doc, tag ); }
wrapper.appendChild( child );
i -= 1;
l -= 1;
} else if ( isBR || wrapper ) {
if ( !wrapper ) { wrapper = createElement( doc, tag ); }
fixCursor( wrapper );
if ( isBR ) {
root.replaceChild( wrapper, child );
} else {
root.insertBefore( wrapper, child );
i += 1;
l += 1;
}
wrapper = null;
}
}
if ( wrapper ) {
root.appendChild( fixCursor( wrapper ) );
}
return root;
};
var notWSTextNode = function ( node ) { var notWSTextNode = function ( node ) {
return ( node.nodeType === ELEMENT_NODE ? return ( node.nodeType === ELEMENT_NODE ?
node.nodeName === 'BR' : node.nodeName === 'BR' :
@ -1460,7 +1429,7 @@ var cleanupBRs = function ( root ) {
// If this is not inside a block, replace it by wrapping // If this is not inside a block, replace it by wrapping
// inlines in DIV. // inlines in DIV.
if ( !isBlock( block ) || !tagAfterSplit[ block.nodeName ] ) { if ( !isBlock( block ) || !tagAfterSplit[ block.nodeName ] ) {
wrapTopLevelInline( block, 'DIV' ); fixContainer( block );
} }
// If in a block we can split, split it instead, but only if there // If in a block we can split, split it instead, but only if there
// is actual text content in the block. Otherwise, the <br> is a // is actual text content in the block. Otherwise, the <br> is a
@ -1761,7 +1730,7 @@ var keyHandlers = {
} }
} }
} }
wrapTopLevelInline( block, 'DIV' ); fixContainer( block );
splitTag = 'DIV'; splitTag = 'DIV';
if ( !splitNode ) { if ( !splitNode ) {
splitNode = block.firstChild; splitNode = block.firstChild;
@ -2116,7 +2085,7 @@ proto.setHTML = function ( html ) {
cleanTree( frag, true ); cleanTree( frag, true );
cleanupBRs( frag ); cleanupBRs( frag );
wrapTopLevelInline( frag, 'DIV' ); fixContainer( frag );
// Fix cursor // Fix cursor
var node = frag; var node = frag;

View file

@ -366,7 +366,7 @@ function mergeContainers ( node ) {
var prev = node.previousSibling, var prev = node.previousSibling,
first = node.firstChild, first = node.firstChild,
isListItem = ( node.nodeName === 'LI' ), isListItem = ( node.nodeName === 'LI' ),
block; needsFix, block;
// Do not merge LIs, unless it only contains a UL // Do not merge LIs, unless it only contains a UL
if ( isListItem && ( !first || !/^[OU]L$/.test( first.nodeName ) ) ) { if ( isListItem && ( !first || !/^[OU]L$/.test( first.nodeName ) ) ) {
@ -384,7 +384,11 @@ function mergeContainers ( node ) {
} }
} }
detach( node ); detach( node );
needsFix = !isContainer( node );
prev.appendChild( empty( node ) ); prev.appendChild( empty( node ) );
if ( needsFix ) {
fixContainer( prev );
}
if ( first ) { if ( first ) {
mergeContainers( first ); mergeContainers( first );
} }
@ -395,6 +399,42 @@ function mergeContainers ( node ) {
} }
} }
// Recursively examine container nodes and wrap any inline children.
function fixContainer ( container ) {
var children = container.childNodes,
doc = container.ownerDocument,
wrapper = null,
i, l, child, isBR;
for ( i = 0, l = children.length; i < l; i += 1 ) {
child = children[i];
isBR = child.nodeName === 'BR';
if ( !isBR && isInline( child ) ) {
if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); }
wrapper.appendChild( child );
i -= 1;
l -= 1;
} else if ( isBR || wrapper ) {
if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); }
fixCursor( wrapper );
if ( isBR ) {
container.replaceChild( wrapper, child );
} else {
container.insertBefore( wrapper, child );
i += 1;
l += 1;
}
wrapper = null;
}
if ( isContainer( child ) ) {
fixContainer( child );
}
}
if ( wrapper ) {
container.appendChild( fixCursor( wrapper ) );
}
return container;
}
function createElement ( doc, tag, props, children ) { function createElement ( doc, tag, props, children ) {
var el = doc.createElement( tag ), var el = doc.createElement( tag ),
attr, value, i, l; attr, value, i, l;