Skip to content

Commit

Permalink
Editable: Use valueToElement to render stored tree representation
Browse files Browse the repository at this point in the history
  • Loading branch information
gziolo committed Dec 13, 2017
1 parent df23eea commit e9b7111
Show file tree
Hide file tree
Showing 22 changed files with 67 additions and 104 deletions.
8 changes: 0 additions & 8 deletions blocks/api/simple-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,3 @@ export function applySimpleNodeList( tree, node ) {
}
} );
}

export function createHTMLFromSimpleNodeList( tree ) {
const doc = document.implementation.createHTMLDocument( '' );

applySimpleNodeList( tree, doc.body );

return doc.body.innerHTML;
}
32 changes: 10 additions & 22 deletions blocks/api/test/matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,59 +11,47 @@ import { renderToString } from '@wordpress/element';
/**
* Internal dependencies
*/
import * as sources from '../matchers';
import { valueToElement } from '../../editable';
import Editable from '../../editable';
import * as matchers from '../matchers';

describe( 'matchers', () => {
const html = '<blockquote><p>A delicious <b>sundae</b> dessert.</p><p>I want it!</p><footer>The Cook</footer></blockquote>';

describe( 'children()', () => {
it( 'should return a source function', () => {
const source = sources.children();
const source = matchers.children();

expect( typeof source ).toBe( 'function' );
} );

it( 'should return HTML equivalent WPElement of matched element', () => {
// Assumption here is that we can cleanly convert back and forth
// between a string and WPElement representation
const match = parse( html, sources.children() );
const match = parse( html, matchers.children() );

expect( renderToString( valueToElement( match ) ) ).toBe( html );
expect(
renderToString( <Editable.Value value={ match } /> )
).toBe( html );
} );
} );

describe( 'node()', () => {
it( 'should return a source function', () => {
const source = sources.node();
const source = matchers.node();

expect( typeof source ).toBe( 'function' );
} );

it( 'should return HTML equivalent WPElement of matched element', () => {
// Assumption here is that we can cleanly convert back and forth
// between a string and WPElement representation
const match = parse( html, sources.node() );
const match = parse( html, matchers.node() );

expect(
renderToString( valueToElement( [ match ] ) )
renderToString( <Editable.Value value={ [ match ] } /> )
).toBe(
`<body>${ html }</body>`
);
} );
} );

describe( 'query', () => {
it( 'should return HTML equivalent WPElement of matched element using selector', () => {
// Assumption here is that we can cleanly convert back and forth
// between a string and WPElement representation
const match = parse( html, sources.query( 'blockquote > p', sources.node( ) ) );

expect(
renderToString( valueToElement( match ) )
).toBe(
'<p>A delicious <b>sundae</b> dessert.</p><p>I want it!</p>'
);
} );
} );
} );
27 changes: 16 additions & 11 deletions blocks/editable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { Slot, Fill } from '@wordpress/components';
import './style.scss';
import { rawHandler } from '../api';
import * as matchers from '../api/matchers';
import { applySimpleNodeList, createHTMLFromSimpleNodeList } from '../api/simple-dom';
import { applySimpleNodeList } from '../api/simple-dom';
import FormatToolbar from './format-toolbar';
import TinyMCE from './tinymce';
import { pickAriaProps } from './aria';
Expand Down Expand Up @@ -82,7 +82,7 @@ const DEFAULT_FORMATS = [ 'bold', 'italic', 'strikethrough', 'link' ];
* @param {Array} value Value to transform
* @return {WPElement} Element.
*/
export function valueToElement( value ) {
function valueToElement( value ) {
if ( ! Array.isArray( value ) ) {
return value;
}
Expand All @@ -93,8 +93,19 @@ export function valueToElement( value ) {
}

const [ type, props, ...children ] = element;
const reactProps = Object.keys( props ).reduce( ( accumulator, key ) => {
const mapping = {
class: 'className',
for: 'htmlFor',
};

return {
...accumulator,
[ mapping[ key ] ? mapping[ key ] : key ]: props[ key ],
};
}, { key: i } );

return createElement( type, { ...props, key: i }, ...valueToElement( children ) );
return createElement( type, { ...reactProps }, ...valueToElement( children ) );
} );
}

Expand Down Expand Up @@ -871,7 +882,7 @@ export default class Editable extends Component {
getSettings={ this.getSettings }
onSetup={ this.onSetup }
style={ style }
defaultValue={ createHTMLFromSimpleNodeList( value ) }
defaultValue={ valueToElement( value ) }
isPlaceholderVisible={ isPlaceholderVisible }
aria-label={ placeholder }
{ ...ariaProps }
Expand Down Expand Up @@ -901,10 +912,4 @@ Editable.defaultProps = {
formatters: [],
};

Editable.Value = ( { tagName: TagName = 'div', value = [], ...props } ) => {
const HTML = createHTMLFromSimpleNodeList( value );

return (
<TagName dangerouslySetInnerHTML={ { __html: HTML } } { ...props } />
);
};
Editable.Value = ( { value } ) => valueToElement( value );
12 changes: 6 additions & 6 deletions blocks/editable/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,26 +152,26 @@ describe( 'Editable', () => {
} );

describe( 'Editable.Value', () => {
const Component = ( { value } ) => (
const MyComponent = ( { value } ) => (
<div>
<Editable.Value value={ value } />
</div>
);

it( 'should render value containing string', () => {
const value = [ 'Hello, Dolly!' ];
const wrapper = shallow( <Component value={ value } /> );
const wrapper = shallow( <MyComponent value={ value } /> );

expect( wrapper.html() ).toBe( '<div>Hello, Dolly!</div>' );
} );

it( 'should render value containing a single DOM node', () => {
const value = [
[ 'h1', {}, 'This is a header' ],
[ 'h1', { class: 'my-class' }, 'This is a header' ],
];
const wrapper = shallow( <Component value={ value } /> );
const wrapper = shallow( <MyComponent value={ value } /> );

expect( wrapper.html() ).toBe( '<div><h1>This is a header</h1></div>' );
expect( wrapper.html() ).toBe( '<div><h1 class="my-class">This is a header</h1></div>' );
} );

it( 'should render value with deeply nested DOM nodes', () => {
Expand All @@ -186,7 +186,7 @@ describe( 'Editable', () => {
] ],
'.',
];
const wrapper = shallow( <Component value={ value } /> );
const wrapper = shallow( <MyComponent value={ value } /> );

expect( wrapper.html() ).toBe(
'<div>This is a <strong>paragraph</strong> with a <a href=\"https://w.org/\">link with <b>bold <i>and italics</i></b></a>.</div>'
Expand Down
13 changes: 6 additions & 7 deletions blocks/editable/tinymce.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Component, createElement } from '@wordpress/element';
import { Component, Children, createElement } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -105,10 +105,10 @@ export default class TinyMCE extends Component {
// If a default value is provided, render it into the DOM even before
// TinyMCE finishes initializing. This avoids a short delay by allowing
// us to show and focus the content before it's truly ready to edit.
// let children;
// if ( defaultValue ) {
// children = Children.toArray( defaultValue );
// }
let children;
if ( defaultValue ) {
children = Children.toArray( defaultValue );
}

return createElement( tagName, {
ref: ( node ) => this.editorNode = node,
Expand All @@ -117,7 +117,6 @@ export default class TinyMCE extends Component {
className: classnames( className, 'blocks-editable__tinymce' ),
style,
...ariaProps,
dangerouslySetInnerHTML: { __html: defaultValue },
} );
}, children );
}
}
2 changes: 1 addition & 1 deletion blocks/library/audio/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ registerBlockType( 'core/audio', {
return (
<figure className={ align ? `align${ align }` : null }>
<audio controls="controls" src={ src } />
<Editable.Value tagName="figcaption" value={ caption } />
{ caption && caption.length > 0 && <figcaption><Editable.Value value={ caption } /></figcaption> }
</figure>
);
},
Expand Down
10 changes: 3 additions & 7 deletions blocks/library/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,9 @@ registerBlockType( 'core/button', {

return (
<div className={ `align${ align }` } style={ { backgroundColor: color } }>
<Editable.Value
tagName="a"
value={ text }
href={ url }
title={ title }
style={ { color: textColor } }
/>
<a href={ url } title={ title } style={ { color: textColor } }>
<Editable.Value value={ text } />
</a>
</div>
);
},
Expand Down
2 changes: 1 addition & 1 deletion blocks/library/cover-image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ registerBlockType( 'core/cover-image', {

return (
<section className={ classes } style={ style }>
<Editable.Value tagName="h2" value={ title } />
<h2><Editable.Value value={ title } /></h2>
</section>
);
},
Expand Down
2 changes: 1 addition & 1 deletion blocks/library/embed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k
return (
<figure className={ align ? `align${ align }` : null }>
{ `\n${ url }\n` /* URL needs to be on its own line. */ }
<Editable.Value tagName="figcaption" value={ caption } />
{ caption && caption.length > 0 && <figcaption><Editable.Value value={ caption } /></figcaption> }
</figure>
);
},
Expand Down
9 changes: 4 additions & 5 deletions blocks/library/heading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,12 @@ registerBlockType( 'core/heading', {

save( { attributes } ) {
const { align, nodeName, content } = attributes;
const Tag = nodeName.toLowerCase();

return (
<Editable.Value
tagName={ nodeName.toLowerCase() }
value={ content }
style={ { textAlign: align } }
/>
<Tag style={ { textAlign: align } } >
<Editable.Value value={ content } />
</Tag>
);
},
} );
2 changes: 1 addition & 1 deletion blocks/library/image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ registerBlockType( 'core/image', {
return (
<figure className={ align ? `align${ align }` : null } style={ figureStyle }>
{ href ? <a href={ href }>{ image }</a> : image }
<Editable.Value tagName="figcaption" value={ caption } />
{ caption && caption.length > 0 && <figcaption><Editable.Value value={ caption } /></figcaption> }
</figure>
);
},
Expand Down
8 changes: 2 additions & 6 deletions blocks/library/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,12 +361,8 @@ registerBlockType( 'core/list', {

save( { attributes } ) {
const { nodeName, values } = attributes;
const Tag = nodeName.toLowerCase();

return (
<Editable.Value
tagName={ nodeName.toLowerCase() }
value={ values }
/>
);
return <Tag><Editable.Value value={ values } /></Tag>;
},
} );
9 changes: 3 additions & 6 deletions blocks/library/paragraph/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,9 @@ registerBlockType( 'core/paragraph', {
};

return (
<Editable.Value
tagName="p"
value={ content }
style={ styles }
className={ className ? className : undefined }
/>
<p style={ styles } className={ className ? className : undefined }>
<Editable.Value value={ content } />
</p>
);
},
} );
Expand Down
2 changes: 1 addition & 1 deletion blocks/library/preformatted/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ registerBlockType( 'core/preformatted', {
save( { attributes } ) {
const { content } = attributes;

return <Editable.Value tagName="pre" value={ content } />;
return <pre><Editable.Value value={ content } /></pre>;
},
} );
6 changes: 3 additions & 3 deletions blocks/library/pullquote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ registerBlockType( 'core/pullquote', {

return (
<blockquote className={ `align${ align }` }>
{ value.map( ( [ tagName, , content ], i ) =>
<Editable.Value tagName={ tagName } value={ content } key={ i } />
<Editable.Value value={ value } />
{ citation && citation.length > 0 && (
<cite><Editable.Value value={ citation } /></cite>
) }
<Editable.Value tagName="cite" value={ citation } />
</blockquote>
);
},
Expand Down
6 changes: 3 additions & 3 deletions blocks/library/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ registerBlockType( 'core/quote', {
className={ style === 2 ? 'is-large' : '' }
style={ { textAlign: align ? align : null } }
>
{ value.map( ( [ tagName, , content ], i ) =>
<Editable.Value tagName={ tagName } value={ content } key={ i } />
<Editable.Value value={ value } />
{ citation && citation.length > 0 && (
<cite><Editable.Value value={ citation } /></cite>
) }
<Editable.Value tagName="cite" value={ citation } />
</blockquote>
);
},
Expand Down
9 changes: 3 additions & 6 deletions blocks/library/table/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,10 @@ registerBlockType( 'core/table', {

save( { attributes } ) {
const { content, align } = attributes;

return (
<Editable.Value
tagName="table"
value={ content }
className={ align ? `align${ align }` : null }
/>
<table className={ align ? `align${ align }` : null }>
<Editable.Value value={ content } />
</table>
);
},
} );
2 changes: 1 addition & 1 deletion blocks/library/text-columns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ registerBlockType( 'core/text-columns', {
<section className={ `align${ width } columns-${ columns }` }>
{ times( columns, ( index ) =>
<div className="wp-block-column" key={ `column-${ index }` }>
<Editable.Value tagName="p" value={ content } />
<p>{ content && content[ index ] && <Editable.Value value={ content[ index ].children } /> }</p>
</div>
) }
</section>
Expand Down
2 changes: 1 addition & 1 deletion blocks/library/verse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ registerBlockType( 'core/verse', {
},

save( { attributes, className } ) {
return <Editable.Value tagName="pre" value={ attributes.content } className={ className } />;
return <pre className={ className }><Editable.Value value={ attributes.content } /></pre>;
},
} );
2 changes: 1 addition & 1 deletion blocks/library/video/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ registerBlockType( 'core/video', {
return (
<figure className={ align ? `align${ align }` : null }>
{ src && <video controls src={ src } /> }
<Editable.Value tagName="figcaption" value={ caption } />
{ caption && caption.length > 0 && <figcaption><Editable.Value value={ caption } /></figcaption> }
</figure>
);
},
Expand Down
Loading

0 comments on commit e9b7111

Please sign in to comment.