Skip to content

Commit

Permalink
Blocks: Represent children as array of node objects
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Aug 25, 2017
1 parent de51e24 commit 6521f06
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 47 deletions.
1 change: 1 addition & 0 deletions blocks/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as source from './source';

export { source };
export { createBlock, switchToBlockType } from './factory';
export { toElement } from './nodes';
export { default as parse } from './parser';
export { default as pasteHandler } from './paste';
export { default as serialize, getBlockDefaultClassname } from './serializer';
Expand Down
72 changes: 72 additions & 0 deletions blocks/api/nodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* External dependencies
*/
import { reduce, map } from 'lodash';

/**
* WordPress dependencies
*/
import { createElement } from '@wordpress/element';

export function namedNodeMapToObject( namedNodeMap ) {
return reduce( namedNodeMap, ( result, entry ) => {
result[ entry.name ] = entry.value;
return result;
}, {} );
}

export function toText( node ) {
return {
type: 'text',
text: node.nodeValue,
};
}

export function toNode( node ) {
const { nodeName, attributes, childNodes } = node;

return {
type: 'node',
name: nodeName.toLowerCase(),
attributes: namedNodeMapToObject( attributes ),
children: children( childNodes ),
};
}

export function children( childNodes ) {
return reduce( childNodes, ( result, childNode ) => {
switch ( childNode.nodeType ) {
case window.Node.ELEMENT_NODE:
result.push( toNode( childNode ) );
break;

case window.Node.TEXT_NODE:
result.push( toText( childNode ) );
break;
}

return result;
}, [] );
}

export function toElement( value ) {
if ( value === null || value === undefined ) {
return;
}

if ( Array.isArray( value ) ) {
return map( toElement, value );
}

switch ( value.type ) {
case 'text':
return value.text;

case 'element':
return createElement(
value.name,
value.attributes,
toElement( value.children ),
);
}
}
68 changes: 32 additions & 36 deletions blocks/api/source.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
/**
* WordPress dependencies
*/
import { createElement } from '@wordpress/element';

/**
* External dependencies
*/
import { nodeListToReact, nodeToReact } from 'dom-react';
import { flow } from 'lodash';
import {
attr as originalAttr,
Expand All @@ -16,6 +10,26 @@ import {
query as originalQuery,
} from 'hpq';

/**
* Internal dependencies
*/
import * as nodes from './nodes';

function applySelector( selector ) {
return ( element ) => {
if ( selector ) {
return element.querySelector( selector );
}

return element;
};
}

function applyKnownSourceFlag( source ) {
source._wpBlocksKnownSource = true;
return source;
}

/**
* Given a source function creator, returns a new function which applies an
* internal flag to the created source.
Expand All @@ -24,40 +38,22 @@ import {
* @return {Function} Modified source function creator
*/
function withKnownSourceFlag( fn ) {
return flow( fn, ( source ) => {
source._wpBlocksKnownSource = true;
return source;
} );
return flow( fn, applyKnownSourceFlag );
}

export const attr = withKnownSourceFlag( originalAttr );
export const prop = withKnownSourceFlag( originalProp );
export const html = withKnownSourceFlag( originalHtml );
export const text = withKnownSourceFlag( originalText );
export const query = withKnownSourceFlag( originalQuery );
export const children = withKnownSourceFlag( ( selector ) => {
return ( domNode ) => {
let match = domNode;

if ( selector ) {
match = domNode.querySelector( selector );
}

if ( match ) {
return nodeListToReact( match.childNodes || [], createElement );
}

return [];
};
} );
export const node = withKnownSourceFlag( ( selector ) => {
return ( domNode ) => {
let match = domNode;

if ( selector ) {
match = domNode.querySelector( selector );
}

return nodeToReact( match, createElement );
};
} );
export const children = ( selector ) => flow(
applySelector( selector ),
( match ) => match.childNodes,
nodes.children,
applyKnownSourceFlag
);
export const node = ( selector ) => flow(
applySelector( selector ),
nodes.toNode,
applyKnownSourceFlag
);
5 changes: 3 additions & 2 deletions blocks/editable/tinymce.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Component, Children, createElement } from '@wordpress/element';
import { Component, createElement } from '@wordpress/element';
import { toElement } from '@wordpress/blocks';

export default class TinyMCE extends Component {
componentDidMount() {
Expand Down Expand Up @@ -85,7 +86,7 @@ export default class TinyMCE extends Component {
// us to show and focus the content before it's truly ready to edit.
let children;
if ( defaultValue ) {
children = Children.toArray( defaultValue );
children = toElement( defaultValue );
}

return createElement( tagName, {
Expand Down
6 changes: 3 additions & 3 deletions blocks/library/paragraph/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { concatChildren } from '@wordpress/element';
* Internal dependencies
*/
import './style.scss';
import { registerBlockType, createBlock, source, setDefaultBlock } from '../../api';
import { registerBlockType, createBlock, source, setDefaultBlock, toElement } from '../../api';
import AlignmentToolbar from '../../alignment-toolbar';
import BlockControls from '../../block-controls';
import Editable from '../../editable';
Expand Down Expand Up @@ -124,10 +124,10 @@ registerBlockType( 'core/paragraph', {
const className = dropCap ? 'has-drop-cap' : null;

if ( ! align ) {
return <p className={ className }>{ content }</p>;
return <p className={ className }>{ toElement( content ) }</p>;
}

return <p style={ { textAlign: align } } className={ className }>{ content }</p>;
return <p style={ { textAlign: align } } className={ className }>{ toElement( content ) }</p>;
},
} );

Expand Down
4 changes: 2 additions & 2 deletions blocks/library/pullquote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { __ } from '@wordpress/i18n';
*/
import './editor.scss';
import './style.scss';
import { registerBlockType, source } from '../../api';
import { registerBlockType, source, toElement } from '../../api';
import Editable from '../../editable';
import BlockControls from '../../block-controls';
import BlockAlignmentToolbar from '../../block-alignment-toolbar';
Expand Down Expand Up @@ -95,7 +95,7 @@ registerBlockType( 'core/pullquote', {

return (
<blockquote className={ `align${ align }` }>
{ value && value.map( ( paragraph, i ) => <p key={ i }>{ paragraph.props.children }</p> ) }
{ toElement( value ) }
{ citation && citation.length > 0 && (
<footer>{ citation }</footer>
) }
Expand Down
6 changes: 2 additions & 4 deletions blocks/library/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Toolbar } from '@wordpress/components';
* Internal dependencies
*/
import './style.scss';
import { registerBlockType, createBlock, source } from '../../api';
import { registerBlockType, createBlock, source, toElement } from '../../api';
import AlignmentToolbar from '../../alignment-toolbar';
import BlockControls from '../../block-controls';
import Editable from '../../editable';
Expand Down Expand Up @@ -209,9 +209,7 @@ registerBlockType( 'core/quote', {
className={ `blocks-quote-style-${ style }` }
style={ { textAlign: align ? align : null } }
>
{ value.map( ( paragraph, i ) => (
<p key={ i }>{ paragraph.props.children }</p>
) ) }
{ toElement( value ) }
{ citation && citation.length > 0 && (
<footer>{ citation }</footer>
) }
Expand Down

0 comments on commit 6521f06

Please sign in to comment.