Skip to content

Commit

Permalink
Represent Editable value as array tree
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Mar 29, 2018
1 parent 5cab7a3 commit 5ba4eae
Show file tree
Hide file tree
Showing 19 changed files with 533 additions and 335 deletions.
1 change: 1 addition & 0 deletions blocks/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ export {
doBlocksMatchTemplate,
synchronizeBlocksWithTemplate,
} from './templates';
export { nodeListToTree } from './matchers';
63 changes: 55 additions & 8 deletions blocks/api/matchers.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,61 @@
/**
* WordPress dependencies
*/
import { createElement } from '@wordpress/element';

/**
* External dependencies
*/
import { nodeListToReact, nodeToReact } from 'dom-react';
export { attr, prop, html, text, query } from 'hpq';

export function buildTree( type, attributes, ...children ) {
children = children.map( ( child ) => {
if ( 'boolean' === typeof child ) {
child = null;
}

if ( null === child || undefined === child ) {
child = '';
} else if ( 'number' === typeof child ) {
child = String( child );
}

if ( 'string' === typeof child ) {
return child;
}

return buildTree( child );
} );

return [ type, attributes, children ];
}

export function nodeListToTree( nodeList, createElement ) {
return [ ...nodeList ].map( ( node ) => nodeToTree( node, createElement ) );
}

export function elementAsArray( type, attributes, children ) {
return [ type, attributes, children ];
}

export function nodeToTree( node, createElement = elementAsArray ) {
if ( ! node ) {
return null;
}

if ( node.nodeType === 3 ) {
return node.nodeValue;
}

if ( node.nodeType !== 1 ) {
return null;
}

const type = node.nodeName.toLowerCase();
const attributes = [ ...node.attributes ].reduce( ( result, { name, value } ) => {
result[ name ] = value;
return result;
}, {} );
const children = nodeListToTree( node.childNodes );

return createElement( type, attributes, children );
}

export const children = ( selector ) => {
return ( domNode ) => {
let match = domNode;
Expand All @@ -18,7 +65,7 @@ export const children = ( selector ) => {
}

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

return [];
Expand All @@ -33,6 +80,6 @@ export const node = ( selector ) => {
match = domNode.querySelector( selector );
}

return nodeToReact( match, createElement );
return nodeToTree( match );
};
};
8 changes: 2 additions & 6 deletions blocks/library/pullquote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ export const settings = {

return (
<blockquote className={ `align${ align }` }>
{ value && value.map( ( paragraph, i ) =>
<p key={ i }>{ paragraph.children && paragraph.children.props.children }</p>
) }
{ value.map( ( paragraph ) => paragraph.children ) }
{ citation && citation.length > 0 && (
<cite>{ citation }</cite>
) }
Expand All @@ -145,9 +143,7 @@ export const settings = {

return (
<blockquote className={ `align${ align }` }>
{ value && value.map( ( paragraph, i ) =>
<p key={ i }>{ paragraph.children && paragraph.children.props.children }</p>
) }
{ value.map( ( paragraph ) => paragraph.children ) }
{ citation && citation.length > 0 && (
<footer>{ citation }</footer>
) }
Expand Down
8 changes: 2 additions & 6 deletions blocks/library/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,7 @@ export const settings = {
className={ style === 2 ? 'is-large' : '' }
style={ { textAlign: align ? align : null } }
>
{ value.map( ( paragraph, i ) => (
<p key={ i }>{ paragraph.children && paragraph.children.props.children }</p>
) ) }
{ value.map( ( paragraph ) => paragraph.children ) }
{ citation && citation.length > 0 && (
<cite>{ citation }</cite>
) }
Expand All @@ -271,9 +269,7 @@ export const settings = {
className={ `blocks-quote-style-${ style }` }
style={ { textAlign: align ? align : null } }
>
{ value.map( ( paragraph, i ) => (
<p key={ i }>{ paragraph.children && paragraph.children.props.children }</p>
) ) }
{ value.map( ( paragraph ) => paragraph.children ) }
{ citation && citation.length > 0 && (
<footer>{ citation }</footer>
) }
Expand Down
42 changes: 29 additions & 13 deletions blocks/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
noop,
reject,
} from 'lodash';
import { nodeListToReact } from 'dom-react';
import 'element-closest';

/**
Expand All @@ -28,7 +27,7 @@ import { withSafeTimeout, Slot, Fill } from '@wordpress/components';
* Internal dependencies
*/
import './style.scss';
import { rawHandler } from '../api';
import { rawHandler, nodeListToTree } from '../api';
import FormatToolbar from './format-toolbar';
import TinyMCE from './tinymce';
import { pickAriaProps } from './aria';
Expand All @@ -37,6 +36,23 @@ import { EVENTS } from './constants';

const { BACKSPACE, DELETE, ENTER } = keycodes;

function toElement( value ) {
if ( ! value ) {
return null;
}

if ( ! Array.isArray( value ) ) {
return value;
}

const [ type, attributes, children ] = value;
if ( ! attributes || attributes.constructor !== Object ) {
return value.map( toElement );
}

return createElement( type, attributes, children.map( toElement ) );
}

export function createTinyMCEElement( type, props, ...children ) {
if ( props[ 'data-mce-bogus' ] === 'all' ) {
return null;
Expand All @@ -46,11 +62,11 @@ export function createTinyMCEElement( type, props, ...children ) {
return children;
}

return createElement(
return [
type,
omitBy( props, ( value, key ) => key.indexOf( 'data-mce-' ) === 0 ),
...children
);
children,
];
}

/**
Expand Down Expand Up @@ -530,8 +546,8 @@ export class RichText extends Component {
const index = dom.nodeIndex( selectedNode );
const beforeNodes = childNodes.slice( 0, index );
const afterNodes = childNodes.slice( index + 1 );
const beforeElement = nodeListToReact( beforeNodes, createTinyMCEElement );
const afterElement = nodeListToReact( afterNodes, createTinyMCEElement );
const beforeElement = nodeListToTree( beforeNodes, createTinyMCEElement );
const afterElement = nodeListToTree( afterNodes, createTinyMCEElement );

this.restoreContentAndSplit( beforeElement, afterElement );
} else {
Expand Down Expand Up @@ -590,8 +606,8 @@ export class RichText extends Component {
const beforeFragment = beforeRange.extractContents();
const afterFragment = afterRange.extractContents();

const beforeElement = nodeListToReact( beforeFragment.childNodes, createTinyMCEElement );
const afterElement = nodeListToReact( filterEmptyNodes( afterFragment.childNodes ), createTinyMCEElement );
const beforeElement = nodeListToTree( beforeFragment.childNodes, createTinyMCEElement );
const afterElement = nodeListToTree( filterEmptyNodes( afterFragment.childNodes ), createTinyMCEElement );

this.restoreContentAndSplit( beforeElement, afterElement, blocks );
} else {
Expand Down Expand Up @@ -642,8 +658,8 @@ export class RichText extends Component {
this.setContent( this.props.value );

this.restoreContentAndSplit(
nodeListToReact( before, createTinyMCEElement ),
nodeListToReact( after, createTinyMCEElement )
nodeListToTree( before, createTinyMCEElement ),
nodeListToTree( after, createTinyMCEElement )
);
}

Expand Down Expand Up @@ -682,7 +698,7 @@ export class RichText extends Component {
}

getContent() {
return nodeListToReact( this.editor.getBody().childNodes || [], createTinyMCEElement );
return nodeListToTree( this.editor.getBody().childNodes || [], createTinyMCEElement );
}

componentWillUnmount() {
Expand Down Expand Up @@ -823,7 +839,7 @@ export class RichText extends Component {
getSettings={ this.getSettings }
onSetup={ this.onSetup }
style={ style }
defaultValue={ value }
defaultValue={ toElement( value ) }
isPlaceholderVisible={ isPlaceholderVisible }
aria-label={ placeholder }
{ ...ariaProps }
Expand Down
22 changes: 15 additions & 7 deletions blocks/rich-text/test/__snapshots__/index.js.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`createTinyMCEElement should render a TinyMCE element 1`] = `
<p
a-prop="hi"
>
<p>
Child
</p>
</p>
Array [
"p",
Object {
"a-prop": "hi",
},
Array [
Array [
"p",
Object {},
Array [
"Child",
],
],
],
]
`;
4 changes: 2 additions & 2 deletions blocks/rich-text/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { diffAriaProps, pickAriaProps } from '../aria';

describe( 'createTinyMCEElement', () => {
const type = 'p';
const children = <p>Child</p>;
const children = createTinyMCEElement( 'p', {}, 'Child' );

test( 'should return null', () => {
const props = {
Expand All @@ -42,7 +42,7 @@ describe( 'createTinyMCEElement', () => {
'a-prop': 'hi',
};

const wrapper = shallow( createTinyMCEElement( type, props, children ) );
const wrapper = createTinyMCEElement( type, props, children );
expect( wrapper ).toMatchSnapshot();
} );
} );
Expand Down
11 changes: 7 additions & 4 deletions blocks/test/fixtures/core__heading__h2-em.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
"attributes": {
"content": [
"The ",
{
"type": "em",
"children": "Inserter"
},
[
"em",
{},
[
"Inserter"
]
],
" Tool"
],
"nodeName": "H2"
Expand Down
75 changes: 47 additions & 28 deletions blocks/test/fixtures/core__list__ul.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,56 @@
"attributes": {
"nodeName": "UL",
"values": [
{
"type": "li",
"children": "Text & Headings"
},
{
"type": "li",
"children": "Images & Videos"
},
{
"type": "li",
"children": "Galleries"
},
{
"type": "li",
"children": "Embeds, like YouTube, Tweets, or other WordPress posts."
},
{
"type": "li",
"children": "Layout blocks, like Buttons, Hero Images, Separators, etc."
},
{
"type": "li",
"children": [
[
"li",
{},
[
"Text & Headings"
]
],
[
"li",
{},
[
"Images & Videos"
]
],
[
"li",
{},
[
"Galleries"
]
],
[
"li",
{},
[
"Embeds, like YouTube, Tweets, or other WordPress posts."
]
],
[
"li",
{},
[
"Layout blocks, like Buttons, Hero Images, Separators, etc."
]
],
[
"li",
{},
[
"And ",
{
"type": "em",
"children": "Lists"
},
[
"em",
{},
[
"Lists"
]
],
" like this one of course :)"
]
}
]
]
},
"innerBlocks": [],
Expand Down
Loading

0 comments on commit 5ba4eae

Please sign in to comment.