Skip to content

Commit

Permalink
Merge pull request #466 from WordPress/add/query-children
Browse files Browse the repository at this point in the history
Manage Editable value as React element
  • Loading branch information
aduth authored Apr 24, 2017
2 parents b446899 + 82feb24 commit 6f0376f
Show file tree
Hide file tree
Showing 15 changed files with 224 additions and 95 deletions.
2 changes: 1 addition & 1 deletion blocks/api/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import * as query from 'hpq';
import * as query from './query';

export { query };
export { createBlock, switchToBlockType } from './factory';
Expand Down
13 changes: 13 additions & 0 deletions blocks/api/query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* External dependencies
*/
import { flow } from 'lodash';
import { html } from 'hpq';
import { Parser } from 'html-to-react';

export * from 'hpq';

const parser = new Parser();
export function children( selector ) {
return flow( html( selector ), parser.parse );
}
28 changes: 28 additions & 0 deletions blocks/api/test/query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { expect } from 'chai';

/**
* Internal dependencies
*/
import { parse, children } from '../query';

describe( 'query', () => {
describe( 'children()', () => {
it( 'should return a matcher function', () => {
const matcher = children();

expect( matcher ).to.be.a( '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 html = '<blockquote><p>A delicious sundae dessert</p></blockquote>';
const match = parse( html, children() );

expect( wp.element.renderToString( match ) ).to.equal( html );
} );
} );
} );
39 changes: 31 additions & 8 deletions blocks/components/editable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
*/
import classnames from 'classnames';
import { last } from 'lodash';
import { Parser as HtmlToReactParser } from 'html-to-react';

/**
* Internal dependencies
*/
import './style.scss';

const htmlToReactParser = new HtmlToReactParser();

export default class Editable extends wp.element.Component {
constructor() {
super( ...arguments );
Expand Down Expand Up @@ -50,8 +53,7 @@ export default class Editable extends wp.element.Component {
}

onInit() {
const { value = '' } = this.props;
this.editor.setContent( value );
this.setContent( this.props.value );
this.focus();
}

Expand All @@ -68,9 +70,9 @@ export default class Editable extends wp.element.Component {
if ( ! this.editor.isDirty() ) {
return;
}
const value = this.editor.getContent();

this.editor.save();
this.props.onChange( value );
this.props.onChange( this.getContent() );
}

onNewBlock() {
Expand Down Expand Up @@ -100,15 +102,21 @@ export default class Editable extends wp.element.Component {
return;
}
const before = getHtml( beforeNodes.slice( 0, beforeNodes.length - 1 ) );
const after = getHtml( childNodes.slice( splitIndex ) );

// Splitting into two blocks
this.editor.setContent( this.props.value || '' );
this.setContent( this.props.value );
const hasAfter = !! childNodes.slice( splitIndex )
.reduce( ( memo, node ) => memo + node.textContent, '' );

const after = hasAfter ? getHtml( childNodes.slice( splitIndex ) ) : '';

// The setTimeout fixes the focus jump to the original block
setTimeout( () => this.props.onSplit( before, hasAfter ? after : '' ) );
setTimeout( () => {
this.props.onSplit(
htmlToReactParser.parse( before ),
htmlToReactParser.parse( after )
);
} );
}

bindNode( ref ) {
Expand All @@ -117,13 +125,28 @@ export default class Editable extends wp.element.Component {

updateContent() {
const bookmark = this.editor.selection.getBookmark( 2, true );
this.editor.setContent( this.props.value );
this.setContent( this.props.value );
this.editor.selection.moveToBookmark( bookmark );
// Saving the editor on updates avoid unecessary onChanges calls
// These calls can make the focus jump
this.editor.save();
}

setContent( content ) {
if ( ! content ) {
content = '';
}

content = wp.element.renderToString( content );
this.editor.setContent( content );
}

getContent() {
const content = this.editor.getContent( { format: 'raw' } );

return htmlToReactParser.parse( content );
}

focus() {
if ( this.props.focus ) {
this.editor.focus();
Expand Down
6 changes: 3 additions & 3 deletions blocks/library/embed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { registerBlock, query } from 'api';
import Editable from 'components/editable';

const { attr, html } = query;
const { attr, children } = query;

registerBlock( 'core/embed', {
title: wp.i18n.__( 'Embed' ),
Expand All @@ -16,7 +16,7 @@ registerBlock( 'core/embed', {
attributes: {
url: attr( 'iframe', 'src' ),
title: attr( 'iframe', 'title' ),
caption: html( 'figcaption' )
caption: children( 'figcaption' )
},

edit( { attributes, isSelected, setAttributes } ) {
Expand Down Expand Up @@ -47,7 +47,7 @@ registerBlock( 'core/embed', {
return (
<figure>
{ iframe }
<figcaption dangerouslySetInnerHTML={ { __html: caption } } />
<figcaption>{ caption }</figcaption>
</figure>
);
}
Expand Down
10 changes: 5 additions & 5 deletions blocks/library/heading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { registerBlock, query } from 'api';
import Editable from 'components/editable';

const { html, prop } = query;
const { children, prop } = query;

registerBlock( 'core/heading', {
title: wp.i18n.__( 'Heading' ),
Expand All @@ -14,7 +14,7 @@ registerBlock( 'core/heading', {
category: 'common',

attributes: {
content: html( 'h1,h2,h3,h4,h5,h6' ),
content: children( 'h1,h2,h3,h4,h5,h6' ),
nodeName: prop( 'h1,h2,h3,h4,h5,h6', 'nodeName' ),
align: prop( 'h1,h2,h3,h4,h5,h6', 'style.textAlign' )
},
Expand Down Expand Up @@ -51,9 +51,9 @@ registerBlock( 'core/heading', {
const Tag = nodeName.toLowerCase();

return (
<Tag
style={ align ? { textAlign: align } : null }
dangerouslySetInnerHTML={ { __html: content } } />
<Tag style={ align ? { textAlign: align } : null }>
{ content }
</Tag>
);
},

Expand Down
6 changes: 3 additions & 3 deletions blocks/library/image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { registerBlock, query } from 'api';
import Editable from 'components/editable';

const { attr, html } = query;
const { attr, children } = query;

registerBlock( 'core/image', {
title: wp.i18n.__( 'Image' ),
Expand All @@ -16,7 +16,7 @@ registerBlock( 'core/image', {
attributes: {
url: attr( 'img', 'src' ),
alt: attr( 'img', 'alt' ),
caption: html( 'figcaption' )
caption: children( 'figcaption' )
},

edit( { attributes, setAttributes, focus, setFocus } ) {
Expand Down Expand Up @@ -49,7 +49,7 @@ registerBlock( 'core/image', {
return (
<figure>
{ img }
<figcaption dangerouslySetInnerHTML={ { __html: caption } } />
<figcaption>{ caption }</figcaption>
</figure>
);
}
Expand Down
22 changes: 13 additions & 9 deletions blocks/library/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import './style.scss';
import { registerBlock, query as hpq } from 'api';
import Editable from 'components/editable';

const { html, prop, query } = hpq;
const { children, prop, query } = hpq;

registerBlock( 'core/list', {
title: wp.i18n.__( 'List' ),
Expand All @@ -15,7 +15,7 @@ registerBlock( 'core/list', {
attributes: {
nodeName: prop( 'ol,ul', 'nodeName' ),
items: query( 'li', {
value: html()
value: children()
} )
},

Expand Down Expand Up @@ -56,9 +56,9 @@ registerBlock( 'core/list', {

edit( { attributes, focus, setFocus } ) {
const { nodeName = 'OL', items = [], align } = attributes;
const content = items.map( item => {
return `<li>${ item.value }</li>`;
} ).join( '' );
const content = items.map( ( item, i ) => {
return <li key={ i }>{ item.value }</li>;
} );

return (
<Editable
Expand All @@ -73,9 +73,13 @@ registerBlock( 'core/list', {

save( { attributes } ) {
const { nodeName = 'OL', items = [] } = attributes;
const children = items.map( ( item, index ) => (
<li key={ index } dangerouslySetInnerHTML={ { __html: item.value } } />
) );
return wp.element.createElement( nodeName.toLowerCase(), null, children );

return wp.element.createElement(
nodeName.toLowerCase(),
null,
items.map( ( item, index ) => (
<li key={ index }>{ item.value }</li>
) )
);
}
} );
35 changes: 13 additions & 22 deletions blocks/library/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,21 @@ import './style.scss';
import { registerBlock, query as hpq } from 'api';
import Editable from 'components/editable';

const { parse, html, query, attr } = hpq;

const fromValueToParagraphs = ( value ) => value ? value.map( ( paragraph ) => `<p>${ paragraph }</p>` ).join( '' ) : '';
const fromParagraphsToValue = ( paragraphs ) => parse( paragraphs, query( 'p', html() ) );
const { children, query, attr } = hpq;

registerBlock( 'core/quote', {
title: wp.i18n.__( 'Quote' ),
icon: 'format-quote',
category: 'common',

attributes: {
value: query( 'blockquote > p', html() ),
citation: html( 'footer' ),
value: query( 'blockquote > p', children() ),
citation: children( 'footer' ),
style: node => {
const value = attr( 'blockquote', 'class' )( node );
const match = value.match( /\bblocks-quote-style-(\d+)\b/ );
return match ? +match[ 1 ] : null;
},
}
},

controls: [ 1, 2 ].map( ( variation ) => ( {
Expand All @@ -42,29 +39,29 @@ registerBlock( 'core/quote', {
return (
<blockquote className={ `blocks-quote blocks-quote-style-${ style }` }>
<Editable
value={ fromValueToParagraphs( value ) }
value={ value }
onChange={
( paragraphs ) => setAttributes( {
value: fromParagraphsToValue( paragraphs )
( nextValue ) => setAttributes( {
value: nextValue
} )
}
focus={ focus && focus.editable === 'value' ? focus : null }
onFocus={ () => setFocus( { editable: 'value' } ) }
/>
{ ( citation || !! focus ) &&
{ ( citation || !! focus ) && (
<footer>
<Editable
value={ citation }
onChange={
( newValue ) => setAttributes( {
citation: newValue
( nextCitation ) => setAttributes( {
citation: nextCitation
} )
}
focus={ focus && focus.editable === 'citation' ? focus : null }
onFocus={ () => setFocus( { editable: 'citation' } ) }
/>
</footer>
}
) }
</blockquote>
);
},
Expand All @@ -76,15 +73,9 @@ registerBlock( 'core/quote', {
return (
<blockquote className={ `blocks-quote-style-${ style }` }>
{ value && value.map( ( paragraph, i ) => (
<p
key={ i }
dangerouslySetInnerHTML={ {
__html: paragraph
} } />
<p key={ i }>{ paragraph }</p>
) ) }
<footer dangerouslySetInnerHTML={ {
__html: citation
} } />
<footer>{ citation }</footer>
</blockquote>
);
}
Expand Down
Loading

0 comments on commit 6f0376f

Please sign in to comment.