mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
Fix erroneous white-space removal when pasting inline fragment.
This commit is contained in:
parent
def56193d4
commit
2a8fb93cd9
6 changed files with 174 additions and 58 deletions
|
@ -7,6 +7,7 @@
|
||||||
var DOCUMENT_POSITION_PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING
|
var DOCUMENT_POSITION_PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING
|
||||||
var ELEMENT_NODE = 1; // Node.ELEMENT_NODE;
|
var ELEMENT_NODE = 1; // Node.ELEMENT_NODE;
|
||||||
var TEXT_NODE = 3; // Node.TEXT_NODE;
|
var TEXT_NODE = 3; // Node.TEXT_NODE;
|
||||||
|
var DOCUMENT_FRAGMENT_NODE = 11; // Node.DOCUMENT_FRAGMENT_NODE;
|
||||||
var SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT;
|
var SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT;
|
||||||
var SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT;
|
var SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT;
|
||||||
|
|
||||||
|
@ -140,7 +141,35 @@ TreeWalker.prototype.previousNode = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|FN|EL)|EM|FONT|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TR(?:IKE|ONG)|MALL|AMP)?|U|VAR|WBR)$/;
|
// Previous node in post-order.
|
||||||
|
TreeWalker.prototype.previousPONode = function () {
|
||||||
|
var current = this.currentNode,
|
||||||
|
root = this.root,
|
||||||
|
nodeType = this.nodeType,
|
||||||
|
filter = this.filter,
|
||||||
|
node;
|
||||||
|
while ( true ) {
|
||||||
|
node = current.lastChild;
|
||||||
|
while ( !node && current ) {
|
||||||
|
if ( current === root ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = current.previousSibling;
|
||||||
|
if ( !node ) { current = current.parentNode; }
|
||||||
|
}
|
||||||
|
if ( !node ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
|
||||||
|
filter( node ) ) {
|
||||||
|
this.currentNode = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
current = node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|U|VAR|WBR)$/;
|
||||||
|
|
||||||
var leafNodeNames = {
|
var leafNodeNames = {
|
||||||
BR: 1,
|
BR: 1,
|
||||||
|
@ -189,11 +218,13 @@ function isInline ( node ) {
|
||||||
return inlineNodeNames.test( node.nodeName );
|
return inlineNodeNames.test( node.nodeName );
|
||||||
}
|
}
|
||||||
function isBlock ( node ) {
|
function isBlock ( node ) {
|
||||||
return node.nodeType === ELEMENT_NODE &&
|
var type = node.nodeType;
|
||||||
|
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
|
||||||
!isInline( node ) && every( node.childNodes, isInline );
|
!isInline( node ) && every( node.childNodes, isInline );
|
||||||
}
|
}
|
||||||
function isContainer ( node ) {
|
function isContainer ( node ) {
|
||||||
return node.nodeType === ELEMENT_NODE &&
|
var type = node.nodeType;
|
||||||
|
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
|
||||||
!isInline( node ) && !isBlock( node );
|
!isInline( node ) && !isBlock( node );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1548,8 +1579,6 @@ keyHandlers[ ctrlKey + 'y' ] = mapKeyTo( 'redo' );
|
||||||
keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' );
|
keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' );
|
||||||
keyHandlers[ ctrlKey + 'shift-z' ] = mapKeyTo( 'redo' );
|
keyHandlers[ ctrlKey + 'shift-z' ] = mapKeyTo( 'redo' );
|
||||||
|
|
||||||
var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
|
|
||||||
|
|
||||||
var fontSizes = {
|
var fontSizes = {
|
||||||
1: 10,
|
1: 10,
|
||||||
2: 13,
|
2: 13,
|
||||||
|
@ -1713,6 +1742,14 @@ var stylesRewriters = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
|
||||||
|
|
||||||
|
var blacklist = /^(?:HEAD|META|STYLE)/;
|
||||||
|
|
||||||
|
var walker = new TreeWalker( null, SHOW_TEXT|SHOW_ELEMENT, function () {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Two purposes:
|
Two purposes:
|
||||||
|
|
||||||
|
@ -1722,17 +1759,14 @@ var stylesRewriters = {
|
||||||
*/
|
*/
|
||||||
var cleanTree = function cleanTree ( node ) {
|
var cleanTree = function cleanTree ( node ) {
|
||||||
var children = node.childNodes,
|
var children = node.childNodes,
|
||||||
blockParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
nonInlineParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
||||||
startsWithWS, endsWithWS, data;
|
startsWithWS, endsWithWS, data, sibling;
|
||||||
|
|
||||||
blockParent = node;
|
nonInlineParent = node;
|
||||||
while ( isInline( blockParent ) ) {
|
while ( isInline( nonInlineParent ) ) {
|
||||||
blockParent = blockParent.parentNode;
|
nonInlineParent = nonInlineParent.parentNode;
|
||||||
}
|
}
|
||||||
if ( !isBlock( blockParent ) ) {
|
walker.root = nonInlineParent;
|
||||||
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];
|
||||||
|
@ -1743,16 +1777,15 @@ var cleanTree = function cleanTree ( node ) {
|
||||||
childLength = child.childNodes.length;
|
childLength = child.childNodes.length;
|
||||||
if ( rewriter ) {
|
if ( rewriter ) {
|
||||||
child = rewriter( child, node );
|
child = rewriter( child, node );
|
||||||
} else if ( !allowedBlock.test( nodeName ) &&
|
} else if ( blacklist.test( nodeName ) ) {
|
||||||
!isInline( child ) ) {
|
node.removeChild( child );
|
||||||
i -= 1;
|
i -= 1;
|
||||||
if ( nodeName === 'HEAD' || nodeName === 'STYLE' ) {
|
l -= 1;
|
||||||
node.removeChild( child );
|
continue;
|
||||||
l -= 1;
|
} else if ( !allowedBlock.test( nodeName ) && !isInline( child ) ) {
|
||||||
} else {
|
i -= 1;
|
||||||
l += childLength - 1;
|
l += childLength - 1;
|
||||||
node.replaceChild( empty( child ), child );
|
node.replaceChild( empty( child ), child );
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( childLength ) {
|
if ( childLength ) {
|
||||||
|
@ -1769,16 +1802,41 @@ var cleanTree = function cleanTree ( node ) {
|
||||||
if ( !startsWithWS && !endsWithWS ) {
|
if ( !startsWithWS && !endsWithWS ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Iterate through the nodes; if we hit some other content
|
||||||
|
// before the start of a new block we don't trim
|
||||||
if ( startsWithWS ) {
|
if ( startsWithWS ) {
|
||||||
contentWalker.currentNode = child;
|
walker.currentNode = child;
|
||||||
if ( !blockParent || !contentWalker.previousNode() ) {
|
while ( sibling = walker.previousPONode() ) {
|
||||||
|
nodeName = sibling.nodeName;
|
||||||
|
if ( nodeName === 'IMG' ||
|
||||||
|
( nodeName === '#text' &&
|
||||||
|
/\S/.test( sibling.data ) ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !isInline( sibling ) ) {
|
||||||
|
sibling = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !sibling ) {
|
||||||
data = data.replace( /^\s+/g, '' );
|
data = data.replace( /^\s+/g, '' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( endsWithWS ) {
|
if ( endsWithWS ) {
|
||||||
contentWalker.currentNode = child;
|
walker.currentNode = child;
|
||||||
if ( !blockParent || !contentWalker.nextNode() ) {
|
while ( sibling = walker.nextNode() ) {
|
||||||
data = data.replace( /\s+$/g, '' );
|
if ( nodeName === 'IMG' ||
|
||||||
|
( nodeName === '#text' &&
|
||||||
|
/\S/.test( sibling.data ) ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !isInline( sibling ) ) {
|
||||||
|
sibling = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !sibling ) {
|
||||||
|
data = data.replace( /^\s+/g, '' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( data ) {
|
if ( data ) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,5 @@
|
||||||
/*jshint strict:false, undef:false, unused:false */
|
/*jshint strict:false, undef:false, unused:false */
|
||||||
|
|
||||||
var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
|
|
||||||
|
|
||||||
var fontSizes = {
|
var fontSizes = {
|
||||||
1: 10,
|
1: 10,
|
||||||
2: 13,
|
2: 13,
|
||||||
|
@ -165,6 +163,14 @@ var stylesRewriters = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
|
||||||
|
|
||||||
|
var blacklist = /^(?:HEAD|META|STYLE)/;
|
||||||
|
|
||||||
|
var walker = new TreeWalker( null, SHOW_TEXT|SHOW_ELEMENT, function () {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Two purposes:
|
Two purposes:
|
||||||
|
|
||||||
|
@ -174,17 +180,14 @@ var stylesRewriters = {
|
||||||
*/
|
*/
|
||||||
var cleanTree = function cleanTree ( node ) {
|
var cleanTree = function cleanTree ( node ) {
|
||||||
var children = node.childNodes,
|
var children = node.childNodes,
|
||||||
blockParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
nonInlineParent, i, l, child, nodeName, nodeType, rewriter, childLength,
|
||||||
startsWithWS, endsWithWS, data;
|
startsWithWS, endsWithWS, data, sibling;
|
||||||
|
|
||||||
blockParent = node;
|
nonInlineParent = node;
|
||||||
while ( isInline( blockParent ) ) {
|
while ( isInline( nonInlineParent ) ) {
|
||||||
blockParent = blockParent.parentNode;
|
nonInlineParent = nonInlineParent.parentNode;
|
||||||
}
|
}
|
||||||
if ( !isBlock( blockParent ) ) {
|
walker.root = nonInlineParent;
|
||||||
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];
|
||||||
|
@ -195,16 +198,15 @@ var cleanTree = function cleanTree ( node ) {
|
||||||
childLength = child.childNodes.length;
|
childLength = child.childNodes.length;
|
||||||
if ( rewriter ) {
|
if ( rewriter ) {
|
||||||
child = rewriter( child, node );
|
child = rewriter( child, node );
|
||||||
} else if ( !allowedBlock.test( nodeName ) &&
|
} else if ( blacklist.test( nodeName ) ) {
|
||||||
!isInline( child ) ) {
|
node.removeChild( child );
|
||||||
i -= 1;
|
i -= 1;
|
||||||
if ( nodeName === 'HEAD' || nodeName === 'STYLE' ) {
|
l -= 1;
|
||||||
node.removeChild( child );
|
continue;
|
||||||
l -= 1;
|
} else if ( !allowedBlock.test( nodeName ) && !isInline( child ) ) {
|
||||||
} else {
|
i -= 1;
|
||||||
l += childLength - 1;
|
l += childLength - 1;
|
||||||
node.replaceChild( empty( child ), child );
|
node.replaceChild( empty( child ), child );
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( childLength ) {
|
if ( childLength ) {
|
||||||
|
@ -221,16 +223,41 @@ var cleanTree = function cleanTree ( node ) {
|
||||||
if ( !startsWithWS && !endsWithWS ) {
|
if ( !startsWithWS && !endsWithWS ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Iterate through the nodes; if we hit some other content
|
||||||
|
// before the start of a new block we don't trim
|
||||||
if ( startsWithWS ) {
|
if ( startsWithWS ) {
|
||||||
contentWalker.currentNode = child;
|
walker.currentNode = child;
|
||||||
if ( !blockParent || !contentWalker.previousNode() ) {
|
while ( sibling = walker.previousPONode() ) {
|
||||||
|
nodeName = sibling.nodeName;
|
||||||
|
if ( nodeName === 'IMG' ||
|
||||||
|
( nodeName === '#text' &&
|
||||||
|
/\S/.test( sibling.data ) ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !isInline( sibling ) ) {
|
||||||
|
sibling = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !sibling ) {
|
||||||
data = data.replace( /^\s+/g, '' );
|
data = data.replace( /^\s+/g, '' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( endsWithWS ) {
|
if ( endsWithWS ) {
|
||||||
contentWalker.currentNode = child;
|
walker.currentNode = child;
|
||||||
if ( !blockParent || !contentWalker.nextNode() ) {
|
while ( sibling = walker.nextNode() ) {
|
||||||
data = data.replace( /\s+$/g, '' );
|
if ( nodeName === 'IMG' ||
|
||||||
|
( nodeName === '#text' &&
|
||||||
|
/\S/.test( sibling.data ) ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !isInline( sibling ) ) {
|
||||||
|
sibling = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !sibling ) {
|
||||||
|
data = data.replace( /^\s+/g, '' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( data ) {
|
if ( data ) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
var DOCUMENT_POSITION_PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING
|
var DOCUMENT_POSITION_PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING
|
||||||
var ELEMENT_NODE = 1; // Node.ELEMENT_NODE;
|
var ELEMENT_NODE = 1; // Node.ELEMENT_NODE;
|
||||||
var TEXT_NODE = 3; // Node.TEXT_NODE;
|
var TEXT_NODE = 3; // Node.TEXT_NODE;
|
||||||
|
var DOCUMENT_FRAGMENT_NODE = 11; // Node.DOCUMENT_FRAGMENT_NODE;
|
||||||
var SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT;
|
var SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT;
|
||||||
var SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT;
|
var SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*jshint strict:false, undef:false, unused:false */
|
/*jshint strict:false, undef:false, unused:false */
|
||||||
|
|
||||||
var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|FN|EL)|EM|FONT|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TR(?:IKE|ONG)|MALL|AMP)?|U|VAR|WBR)$/;
|
var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|U|VAR|WBR)$/;
|
||||||
|
|
||||||
var leafNodeNames = {
|
var leafNodeNames = {
|
||||||
BR: 1,
|
BR: 1,
|
||||||
|
@ -49,11 +49,13 @@ function isInline ( node ) {
|
||||||
return inlineNodeNames.test( node.nodeName );
|
return inlineNodeNames.test( node.nodeName );
|
||||||
}
|
}
|
||||||
function isBlock ( node ) {
|
function isBlock ( node ) {
|
||||||
return node.nodeType === ELEMENT_NODE &&
|
var type = node.nodeType;
|
||||||
|
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
|
||||||
!isInline( node ) && every( node.childNodes, isInline );
|
!isInline( node ) && every( node.childNodes, isInline );
|
||||||
}
|
}
|
||||||
function isContainer ( node ) {
|
function isContainer ( node ) {
|
||||||
return node.nodeType === ELEMENT_NODE &&
|
var type = node.nodeType;
|
||||||
|
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
|
||||||
!isInline( node ) && !isBlock( node );
|
!isInline( node ) && !isBlock( node );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,3 +88,31 @@ TreeWalker.prototype.previousNode = function () {
|
||||||
current = node;
|
current = node;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Previous node in post-order.
|
||||||
|
TreeWalker.prototype.previousPONode = function () {
|
||||||
|
var current = this.currentNode,
|
||||||
|
root = this.root,
|
||||||
|
nodeType = this.nodeType,
|
||||||
|
filter = this.filter,
|
||||||
|
node;
|
||||||
|
while ( true ) {
|
||||||
|
node = current.lastChild;
|
||||||
|
while ( !node && current ) {
|
||||||
|
if ( current === root ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = current.previousSibling;
|
||||||
|
if ( !node ) { current = current.parentNode; }
|
||||||
|
}
|
||||||
|
if ( !node ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
|
||||||
|
filter( node ) ) {
|
||||||
|
this.currentNode = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
current = node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue