mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
Better cleanTree fn.
- Better checks to precisely trim white space only at beginning and end of block - Don't keep the contents of <head> or <style> tags if inserted into body. - Always keep styles to preserve fidelity on paste. Fixes #95.
This commit is contained in:
parent
926f40d033
commit
7fc3ab55c3
4 changed files with 84 additions and 88 deletions
|
@ -1720,10 +1720,20 @@ var stylesRewriters = {
|
||||||
and whitespace nodes.
|
and whitespace nodes.
|
||||||
2. Convert inline tags into our preferred format.
|
2. Convert inline tags into our preferred format.
|
||||||
*/
|
*/
|
||||||
var cleanTree = function ( node, allowStyles ) {
|
var cleanTree = function cleanTree ( node ) {
|
||||||
var children = node.childNodes,
|
var children = node.childNodes,
|
||||||
i, l, child, nodeName, nodeType, rewriter, childLength,
|
blockParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
||||||
data, j, ll;
|
startsWithWS, endsWithWS, data;
|
||||||
|
|
||||||
|
blockParent = node;
|
||||||
|
while ( isInline( blockParent ) ) {
|
||||||
|
blockParent = blockParent.parentNode;
|
||||||
|
}
|
||||||
|
if ( !isBlock( blockParent ) ) {
|
||||||
|
blockParent = null;
|
||||||
|
}
|
||||||
|
contentWalker.root = blockParent;
|
||||||
|
|
||||||
for ( i = 0, l = children.length; i < l; i += 1 ) {
|
for ( i = 0, l = children.length; i < l; i += 1 ) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
nodeName = child.nodeName;
|
nodeName = child.nodeName;
|
||||||
|
@ -1736,55 +1746,43 @@ var cleanTree = function ( node, allowStyles ) {
|
||||||
} else if ( !allowedBlock.test( nodeName ) &&
|
} else if ( !allowedBlock.test( nodeName ) &&
|
||||||
!isInline( child ) ) {
|
!isInline( child ) ) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
l += childLength - 1;
|
if ( nodeName === 'HEAD' || nodeName === 'STYLE' ) {
|
||||||
node.replaceChild( empty( child ), child );
|
node.removeChild( child );
|
||||||
|
l -= 1;
|
||||||
|
} else {
|
||||||
|
l += childLength - 1;
|
||||||
|
node.replaceChild( empty( child ), child );
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if ( !allowStyles && child.style.cssText ) {
|
|
||||||
child.removeAttribute( 'style' );
|
|
||||||
}
|
}
|
||||||
if ( childLength ) {
|
if ( childLength ) {
|
||||||
cleanTree( child, allowStyles );
|
cleanTree( child );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( nodeType === TEXT_NODE ) {
|
if ( nodeType === TEXT_NODE ) {
|
||||||
data = child.data;
|
data = child.data;
|
||||||
// Use \S instead of notWS, because we want to remove nodes
|
// Use \s instead of notWS, because we want to remove nodes
|
||||||
// which are just nbsp, in order to cleanup <div>nbsp<br></div>
|
// which are just nbsp, in order to cleanup <div>nbsp<br></div>
|
||||||
// construct.
|
// construct.
|
||||||
if ( /\S/.test( data ) ) {
|
startsWithWS = /\s/.test( data.charAt( 0 ) );
|
||||||
// If the parent node is inline, don't trim this node as
|
endsWithWS = /\s/.test( data.charAt( data.length - 1 ) );
|
||||||
// it probably isn't at the end of the block.
|
if ( !startsWithWS && !endsWithWS ) {
|
||||||
if ( isInline( node ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
j = 0;
|
|
||||||
ll = data.length;
|
|
||||||
if ( !i || !isInline( children[ i - 1 ] ) ) {
|
|
||||||
while ( j < ll && !notWS.test( data.charAt( j ) ) ) {
|
|
||||||
j += 1;
|
|
||||||
}
|
|
||||||
if ( j ) {
|
|
||||||
child.data = data = data.slice( j );
|
|
||||||
ll -= j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( i + 1 === l || !isInline( children[ i + 1 ] ) ) {
|
|
||||||
j = ll;
|
|
||||||
while ( j > 0 && !notWS.test( data.charAt( j - 1 ) ) ) {
|
|
||||||
j -= 1;
|
|
||||||
}
|
|
||||||
if ( j < ll ) {
|
|
||||||
child.data = data.slice( 0, j );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// If we have just white space, it may still be important if it
|
if ( startsWithWS ) {
|
||||||
// separates two inline nodes, e.g. "<a>link</a> <a>link</a>".
|
contentWalker.currentNode = child;
|
||||||
else if ( i && i + 1 < l &&
|
if ( !blockParent || !contentWalker.previousNode() ) {
|
||||||
isInline( children[ i - 1 ] ) &&
|
data = data.replace( /^\s+/g, '' );
|
||||||
isInline( children[ i + 1 ] ) ) {
|
}
|
||||||
child.data = ' ';
|
}
|
||||||
|
if ( endsWithWS ) {
|
||||||
|
contentWalker.currentNode = child;
|
||||||
|
if ( !blockParent || !contentWalker.nextNode() ) {
|
||||||
|
data = data.replace( /\s+$/g, '' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( data ) {
|
||||||
|
child.data = data;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3319,7 +3317,7 @@ proto.setHTML = function ( html ) {
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
frag.appendChild( empty( div ) );
|
frag.appendChild( empty( div ) );
|
||||||
|
|
||||||
cleanTree( frag, true );
|
cleanTree( frag );
|
||||||
cleanupBRs( frag );
|
cleanupBRs( frag );
|
||||||
|
|
||||||
fixContainer( frag );
|
fixContainer( frag );
|
||||||
|
@ -3473,7 +3471,7 @@ proto.insertHTML = function ( html, isPaste ) {
|
||||||
};
|
};
|
||||||
|
|
||||||
addLinks( frag );
|
addLinks( frag );
|
||||||
cleanTree( frag, true );
|
cleanTree( frag );
|
||||||
cleanupBRs( frag );
|
cleanupBRs( frag );
|
||||||
removeEmptyInlines( frag );
|
removeEmptyInlines( frag );
|
||||||
frag.normalize();
|
frag.normalize();
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -172,10 +172,20 @@ var stylesRewriters = {
|
||||||
and whitespace nodes.
|
and whitespace nodes.
|
||||||
2. Convert inline tags into our preferred format.
|
2. Convert inline tags into our preferred format.
|
||||||
*/
|
*/
|
||||||
var cleanTree = function ( node, allowStyles ) {
|
var cleanTree = function cleanTree ( node ) {
|
||||||
var children = node.childNodes,
|
var children = node.childNodes,
|
||||||
i, l, child, nodeName, nodeType, rewriter, childLength,
|
blockParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
||||||
data, j, ll;
|
startsWithWS, endsWithWS, data;
|
||||||
|
|
||||||
|
blockParent = node;
|
||||||
|
while ( isInline( blockParent ) ) {
|
||||||
|
blockParent = blockParent.parentNode;
|
||||||
|
}
|
||||||
|
if ( !isBlock( blockParent ) ) {
|
||||||
|
blockParent = null;
|
||||||
|
}
|
||||||
|
contentWalker.root = blockParent;
|
||||||
|
|
||||||
for ( i = 0, l = children.length; i < l; i += 1 ) {
|
for ( i = 0, l = children.length; i < l; i += 1 ) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
nodeName = child.nodeName;
|
nodeName = child.nodeName;
|
||||||
|
@ -188,55 +198,43 @@ var cleanTree = function ( node, allowStyles ) {
|
||||||
} else if ( !allowedBlock.test( nodeName ) &&
|
} else if ( !allowedBlock.test( nodeName ) &&
|
||||||
!isInline( child ) ) {
|
!isInline( child ) ) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
l += childLength - 1;
|
if ( nodeName === 'HEAD' || nodeName === 'STYLE' ) {
|
||||||
node.replaceChild( empty( child ), child );
|
node.removeChild( child );
|
||||||
|
l -= 1;
|
||||||
|
} else {
|
||||||
|
l += childLength - 1;
|
||||||
|
node.replaceChild( empty( child ), child );
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if ( !allowStyles && child.style.cssText ) {
|
|
||||||
child.removeAttribute( 'style' );
|
|
||||||
}
|
}
|
||||||
if ( childLength ) {
|
if ( childLength ) {
|
||||||
cleanTree( child, allowStyles );
|
cleanTree( child );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( nodeType === TEXT_NODE ) {
|
if ( nodeType === TEXT_NODE ) {
|
||||||
data = child.data;
|
data = child.data;
|
||||||
// Use \S instead of notWS, because we want to remove nodes
|
// Use \s instead of notWS, because we want to remove nodes
|
||||||
// which are just nbsp, in order to cleanup <div>nbsp<br></div>
|
// which are just nbsp, in order to cleanup <div>nbsp<br></div>
|
||||||
// construct.
|
// construct.
|
||||||
if ( /\S/.test( data ) ) {
|
startsWithWS = /\s/.test( data.charAt( 0 ) );
|
||||||
// If the parent node is inline, don't trim this node as
|
endsWithWS = /\s/.test( data.charAt( data.length - 1 ) );
|
||||||
// it probably isn't at the end of the block.
|
if ( !startsWithWS && !endsWithWS ) {
|
||||||
if ( isInline( node ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
j = 0;
|
|
||||||
ll = data.length;
|
|
||||||
if ( !i || !isInline( children[ i - 1 ] ) ) {
|
|
||||||
while ( j < ll && !notWS.test( data.charAt( j ) ) ) {
|
|
||||||
j += 1;
|
|
||||||
}
|
|
||||||
if ( j ) {
|
|
||||||
child.data = data = data.slice( j );
|
|
||||||
ll -= j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( i + 1 === l || !isInline( children[ i + 1 ] ) ) {
|
|
||||||
j = ll;
|
|
||||||
while ( j > 0 && !notWS.test( data.charAt( j - 1 ) ) ) {
|
|
||||||
j -= 1;
|
|
||||||
}
|
|
||||||
if ( j < ll ) {
|
|
||||||
child.data = data.slice( 0, j );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// If we have just white space, it may still be important if it
|
if ( startsWithWS ) {
|
||||||
// separates two inline nodes, e.g. "<a>link</a> <a>link</a>".
|
contentWalker.currentNode = child;
|
||||||
else if ( i && i + 1 < l &&
|
if ( !blockParent || !contentWalker.previousNode() ) {
|
||||||
isInline( children[ i - 1 ] ) &&
|
data = data.replace( /^\s+/g, '' );
|
||||||
isInline( children[ i + 1 ] ) ) {
|
}
|
||||||
child.data = ' ';
|
}
|
||||||
|
if ( endsWithWS ) {
|
||||||
|
contentWalker.currentNode = child;
|
||||||
|
if ( !blockParent || !contentWalker.nextNode() ) {
|
||||||
|
data = data.replace( /\s+$/g, '' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( data ) {
|
||||||
|
child.data = data;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1294,7 +1294,7 @@ proto.setHTML = function ( html ) {
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
frag.appendChild( empty( div ) );
|
frag.appendChild( empty( div ) );
|
||||||
|
|
||||||
cleanTree( frag, true );
|
cleanTree( frag );
|
||||||
cleanupBRs( frag );
|
cleanupBRs( frag );
|
||||||
|
|
||||||
fixContainer( frag );
|
fixContainer( frag );
|
||||||
|
@ -1448,7 +1448,7 @@ proto.insertHTML = function ( html, isPaste ) {
|
||||||
};
|
};
|
||||||
|
|
||||||
addLinks( frag );
|
addLinks( frag );
|
||||||
cleanTree( frag, true );
|
cleanTree( frag );
|
||||||
cleanupBRs( frag );
|
cleanupBRs( frag );
|
||||||
removeEmptyInlines( frag );
|
removeEmptyInlines( frag );
|
||||||
frag.normalize();
|
frag.normalize();
|
||||||
|
|
Loading…
Reference in a new issue