@wordpress/blocks
Version:
Block API for WordPress.
87 lines (76 loc) • 2.29 kB
JavaScript
/**
* Internal dependencies
*/
import { getSibling } from './utils';
function isFormattingSpace( character ) {
return (
character === ' ' ||
character === '\r' ||
character === '\n' ||
character === '\t'
);
}
/**
* Removes spacing that formats HTML.
*
* @see https://www.w3.org/TR/css-text-3/#white-space-processing
*
* @param {Node} node The node to be processed.
* @return {void}
*/
export default function htmlFormattingRemover( node ) {
if ( node.nodeType !== node.TEXT_NODE ) {
return;
}
// Ignore pre content. Note that this does not use Element#closest due to
// a combination of (a) node may not be Element and (b) node.parentElement
// does not have full support in all browsers (Internet Exporer).
//
// See: https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement#Browser_compatibility
/** @type {Node?} */
let parent = node;
while ( ( parent = parent.parentNode ) ) {
if (
parent.nodeType === parent.ELEMENT_NODE &&
parent.nodeName === 'PRE'
) {
return;
}
}
// First, replace any sequence of HTML formatting space with a single space.
let newData = node.data.replace( /[ \r\n\t]+/g, ' ' );
// Remove the leading space if the text element is at the start of a block,
// is preceded by a line break element, or has a space in the previous
// node.
if ( newData[ 0 ] === ' ' ) {
const previousSibling = getSibling( node, 'previous' );
if (
! previousSibling ||
previousSibling.nodeName === 'BR' ||
previousSibling.textContent.slice( -1 ) === ' '
) {
newData = newData.slice( 1 );
}
}
// Remove the trailing space if the text element is at the end of a block,
// is succeeded by a line break element, or has a space in the next text
// node.
if ( newData[ newData.length - 1 ] === ' ' ) {
const nextSibling = getSibling( node, 'next' );
if (
! nextSibling ||
nextSibling.nodeName === 'BR' ||
( nextSibling.nodeType === nextSibling.TEXT_NODE &&
isFormattingSpace( nextSibling.textContent[ 0 ] ) )
) {
newData = newData.slice( 0, -1 );
}
}
// If there's no data left, remove the node, so `previousSibling` stays
// accurate. Otherwise, update the node data.
if ( ! newData ) {
node.parentNode.removeChild( node );
} else {
node.data = newData;
}
}