Skip to content

Commit

Permalink
TinyMCE per block: Having a more controlled output markup (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad authored Mar 3, 2017
1 parent a11f577 commit 43e9b0c
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 116 deletions.
2 changes: 1 addition & 1 deletion tinymce-per-block/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<body>
<div class="editor"></div>
<script>
window.content = '<!-- wp:heading -->1.0 Is The Loneliest Number<!-- /wp --><!-- wp:quote cite:Jobs -->Design is not just what it looks like and feels like. Design is how it works.<!-- /wp --><!-- wp:paragraph -->Many entrepreneurs idolize Steve Jobs. He’s such a perfectionist , they say. Nothing leaves the doors of 1 Infinite Loop in Cupertino without a polish and finish that makes geeks everywhere drool. No compromise!<!-- /wp --><!-- wp:text -->A beautiful thing about Apple is how quickly they obsolete their own products. I imagine this also makes the discipline of getting things out there easier. Like I mentioned before, the longer it’s been since the last release the more pressure there is, but if you know that if your bit of code doesn’t make this version but there’s the +0.1 coming out in 6 weeks, then it’s not that bad. It’s like flights from San Francisco to LA, if you miss one you know there’s another one an hour later so it’s not a big deal. Amazon has done a fantastic job of this with the Kindle as well, with a new model every year.<!-- /wp -->\n\n<!-- wp:text -->I like Apple for the opposite reason: <strong>they’re not afraid of getting a rudimentary 1.0 out into the world</strong>.<!-- /wp --><!-- wp:image --><img src="https://matiasventura.files.wordpress.com/2017/02/blue.png?w=720"><!-- /wp --><!-- wp:paragraph -->Many entrepreneurs idolize Steve Jobs. He’s such a perfectionist , they say. Nothing leaves the doors of 1 Infinite Loop in Cupertino without a polish and finish that makes geeks everywhere drool. No compromise!<!-- /wp -->';
window.content = '<!-- wp:heading size:h2 --><h2>1.0 Is The Loneliest Number</h2><!-- /wp --><!-- wp:quote cite:Jobs --><p>Design is not just what it looks like and feels like. Design is how it works.</p><!-- /wp --><!-- wp:paragraph --><p>Many entrepreneurs idolize Steve Jobs. He’s such a perfectionist , they say. Nothing leaves the doors of 1 Infinite Loop in Cupertino without a polish and finish that makes geeks everywhere drool. No compromise!</p><!-- /wp --><!-- wp:text -->A beautiful thing about Apple is how quickly they obsolete their own products. I imagine this also makes the discipline of getting things out there easier. Like I mentioned before, the longer it’s been since the last release the more pressure there is, but if you know that if your bit of code doesn’t make this version but there’s the +0.1 coming out in 6 weeks, then it’s not that bad. It’s like flights from San Francisco to LA, if you miss one you know there’s another one an hour later so it’s not a big deal. Amazon has done a fantastic job of this with the Kindle as well, with a new model every year.<!-- /wp --><!-- wp:text -->I like Apple for the opposite reason: <strong>they’re not afraid of getting a rudimentary 1.0 out into the world</strong>.<!-- /wp --><!-- wp:image --><img src="https://matiasventura.files.wordpress.com/2017/02/blue.png?w=720"><!-- /wp --><!-- wp:paragraph --><p>Many entrepreneurs idolize Steve Jobs. He’s such a perfectionist , they say. Nothing leaves the doors of 1 Infinite Loop in Cupertino without a polish and finish that makes geeks everywhere drool. No compromise!</p><!-- /wp -->';
</script>

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Merriweather:300,300i,400,400i,700,700i">
Expand Down
7 changes: 3 additions & 4 deletions tinymce-per-block/src/blocks/heading-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ export default class HeadingBlockForm extends Component {
};

setSize = ( size ) => () => {
this.props.setAttributes( { size } );
this.props.change( { size } );
};

render() {
const { block, isFocused } = this.props;
const className = block.attrs.size ? block.attrs.size : 'h2';
const sizes = [
{ id: 'h1', icon: EditorHeading1Icon },
{ id: 'h2', icon: EditorHeading2Icon },
Expand All @@ -49,7 +48,7 @@ export default class HeadingBlockForm extends Component {
key={ id }
onClick={ this.setSize( id ) }
className={ classNames( 'block-list__block-control', {
'is-selected': className === id
'is-selected': block.size === id
} ) }
>
<Icon />
Expand All @@ -62,7 +61,7 @@ export default class HeadingBlockForm extends Component {
</div>
</div>
) }
<div className={ `heading-block__form ${ className }` }>
<div className={ `heading-block__form ${ block.size }` }>
<InlineTextBlockForm
ref={ this.bindForm }
{ ...this.props }
Expand Down
32 changes: 32 additions & 0 deletions tinymce-per-block/src/blocks/heading-block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import { registerBlock } from 'wp-blocks';
import { EditorHeadingIcon } from 'dashicons';

import { parse } from 'parsers/block';
import { serialize } from 'serializers/block';

/**
* Internal dependencies
*/
Expand All @@ -13,4 +16,33 @@ registerBlock( 'heading', {
title: 'Heading',
form: form,
icon: EditorHeadingIcon,
parse: ( rawBlock ) => {
const nodeNames = [ 'h1', 'h2', 'h3' ];
if (
rawBlock.children.length !== 1 ||
nodeNames.indexOf( rawBlock.children[ 0 ].name ) === -1
) {
return false;
}

return {
blockType: 'heading',
content: serialize( rawBlock.children[ 0 ].children ),
size: rawBlock.children[ 0 ].name
};
},
serialize: ( block ) => {
const elementName = block.size ? block.size : 'h2';
const rawHtml = `<${ elementName }>` + block.content + `</${ elementName }>`;

return {
type: 'WP_Block',
blockType: 'heading',
attrs: { size: elementName },
startText: '<!-- wp:heading -->',
endText: '<!-- /wp -->',
rawContent: '<!-- wp:heading -->' + rawHtml + '<!-- /wp -->',
children: parse( rawHtml )
};
}
} );
33 changes: 9 additions & 24 deletions tinymce-per-block/src/blocks/image-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* External dependencies
*/
import { createElement, Component } from 'wp-elements';
import { find } from 'lodash';
import {
ImageNoAlignIcon,
ImageAlignRightIcon,
Expand All @@ -25,35 +24,21 @@ export default class ImageBlockForm extends Component {
}

setImageAlignment = ( id ) => () => {
this.props.setAttributes( { align: id } );
this.props.change( { align: id } );
};

render() {
const { block, setAttributes, moveDown, moveUp, remove, appendBlock, isFocused } = this.props;
const { attrs, children } = block;
const image = find( children, ( { name } ) => 'img' === name );
if ( ! image ) {
return null;
}
const caption = attrs.caption || '';
const { block, change, moveDown, moveUp, remove, appendBlock, isFocused } = this.props;
const removePrevious = () => {
if ( ! caption ) {
if ( ! block.caption ) {
remove();
}
};
const splitValue = ( left, right ) => {
setAttributes( { caption: left } );
change( { caption: left } );
appendBlock( {
type: 'WP_Block',
blockType: 'paragraph',
attrs: {},
startText: '<!-- wp:paragraph -->',
endText: '<!-- /wp -->',
rawContent: '<!-- wp:paragraph -->' + right + '<!-- /wp -->',
children: [ {
type: 'Text',
value: right
} ]
content: right
} );
};
const imageAlignments = [
Expand All @@ -62,7 +47,7 @@ export default class ImageBlockForm extends Component {
{ id: 'align-right', icon: ImageAlignRightIcon },
{ id: 'align-full-width', icon: ImageFullWidthIcon },
];
const alignValue = attrs.align || 'no-align';
const alignValue = block.align || 'no-align';

return (
<div className={ classNames( 'image-caption-block', alignValue ) }>
Expand All @@ -85,7 +70,7 @@ export default class ImageBlockForm extends Component {
</div>
}
<img
src={ image.attrs.src }
src={ block.src }
className="image-caption-block__display"
/>
<div className="image-caption-block__caption">
Expand All @@ -95,8 +80,8 @@ export default class ImageBlockForm extends Component {
removePrevious={ removePrevious }
moveDown={ moveDown }
splitValue={ splitValue }
value={ caption }
onChange={ ( value ) => setAttributes( { caption: value } ) }
value={ block.caption }
onChange={ ( value ) => change( { caption: value } ) }
placeholder="Enter a caption"
/>
</div>
Expand Down
32 changes: 31 additions & 1 deletion tinymce-per-block/src/blocks/image-block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import { registerBlock } from 'wp-blocks';
import { FormatImageIcon } from 'dashicons';

import { parse } from 'parsers/block';

/**
* Internal dependencies
*/
Expand All @@ -12,5 +14,33 @@ import form from './form';
registerBlock( 'image', {
title: 'Image',
icon: FormatImageIcon,
form
form,
parse: ( rawBlock ) => {
if (
rawBlock.children.length !== 1 ||
rawBlock.children[ 0 ].name !== 'img'
) {
return false;
}

return {
blockType: 'image',
src: rawBlock.children[ 0 ].attrs.src,
caption: rawBlock.children[ 0 ].attrs.caption || '',
align: rawBlock.children[ 0 ].attrs.align || 'no-align'
};
},
serialize: ( block ) => {
const rawHtml = `<img src="${ block.src }">`;

return {
type: 'WP_Block',
blockType: 'image',
attrs: { /* caption: block.caption , align: block.align */ },
startText: '<!-- wp:image -->',
endText: '<!-- /wp -->',
rawContent: '<!-- wp:image -->' + rawHtml + '<!-- /wp -->',
children: parse( rawHtml )
};
}
} );
18 changes: 10 additions & 8 deletions tinymce-per-block/src/blocks/inline-text-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { createElement, Component } from 'wp-elements';
import { EditableComponent } from 'wp-blocks';

import { parse } from 'parsers/block';
import { serialize } from 'serializers/block';

export default class InlineTextBlockForm extends Component {
Expand All @@ -21,9 +22,11 @@ export default class InlineTextBlockForm extends Component {
return children;
};

const { block: { children }, remove, setChildren } = this.props;
const { block: { content }, remove, change } = this.props;
remove( index );
setTimeout( () => setChildren( getLeaves( children ).concat( getLeaves( block.children ) ) ) );
setTimeout( () => change(
{ content: serialize( getLeaves( parse( content ) ).concat( getLeaves( parse( block.content ) ) ) ) }
) );
setTimeout( () => this.editable.updateContent() );
}

Expand All @@ -36,17 +39,16 @@ export default class InlineTextBlockForm extends Component {
};

render() {
const { block, setChildren, moveUp, moveDown, appendBlock,
const { block, change, moveUp, moveDown, appendBlock,
mergeWithPrevious, remove, setToolbarState, focus, focusConfig } = this.props;
const { children } = block;

const splitValue = ( left, right ) => {
setChildren( left );
change( { content: left } );
setTimeout( () => this.editable.updateContent() );
if ( right ) {
appendBlock( {
...block,
children: right
content: right
} );
} else {
appendBlock();
Expand All @@ -56,13 +58,13 @@ export default class InlineTextBlockForm extends Component {
return (
<EditableComponent
ref={ this.bindEditable }
content={ serialize( children ) }
content={ block.content }
moveUp={ moveUp }
moveDown={ moveDown }
splitValue={ splitValue }
mergeWithPrevious={ mergeWithPrevious }
remove={ remove }
onChange={ ( value ) => setChildren( value ) }
onChange={ ( value ) => change( { content: value } ) }
setToolbarState={ setToolbarState }
focusConfig={ focusConfig }
onFocusChange={ focus }
Expand Down
8 changes: 4 additions & 4 deletions tinymce-per-block/src/blocks/paragraph-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ export default class ParagraphBlockForm extends Component {
this.toolbar && this.toolbar.setToolbarState( ...args );
};

setAlignment = ( textAlign ) => {
this.props.setAttributes( { textAlign } );
setAlignment = ( align ) => {
this.props.change( { align } );
};

render() {
const { block, isFocused } = this.props;
const selectedTextAlign = block.attrs.textAlign || 'left';
const selectedTextAlign = block.align || 'left';
const style = {
textAlign: selectedTextAlign
};
Expand All @@ -39,7 +39,7 @@ export default class ParagraphBlockForm extends Component {
{ isFocused &&
<div className="block-list__block-controls">
<div className="block-list__block-controls-group">
<AlignmentToolbar value={ block.attrs.textAlign } onChange={ this.setAlignment } />
<AlignmentToolbar value={ block.align } onChange={ this.setAlignment } />
</div>

<div className="block-list__block-controls-group">
Expand Down
32 changes: 31 additions & 1 deletion tinymce-per-block/src/blocks/paragraph-block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,39 @@ import { EditorParagraphIcon } from 'dashicons';
* Internal dependencies
*/
import form from './form';
import { parse } from 'parsers/block';
import { serialize } from 'serializers/block';

registerBlock( 'paragraph', {
title: 'Paragraph',
form: form,
icon: EditorParagraphIcon
icon: EditorParagraphIcon,
parse: ( rawBlock ) => {
if (
rawBlock.children.length !== 1 ||
rawBlock.children[ 0 ].name !== 'p'
) {
return false;
}

return {
blockType: 'paragraph',
align: rawBlock.attrs.align || 'no-align',
content: serialize( rawBlock.children ),
};
},
serialize: ( block ) => {
const children = parse( block.content );
const rawHtml = serialize( children );

return {
type: 'WP_Block',
blockType: 'paragraph',
attrs: { /* align: block.align */ },
startText: '<!-- wp:paragraph -->',
endText: '<!-- /wp -->',
rawContent: '<!-- wp:paragraph -->' + rawHtml + '<!-- /wp -->',
children
};
}
} );
Loading

0 comments on commit 43e9b0c

Please sign in to comment.