From cb815add5847694118d28bc40bd53cae541a10a1 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 1 Jun 2017 15:49:45 -0400 Subject: [PATCH] Surface alignment toolbar as block control --- blocks/alignment-toolbar/index.js | 40 +++++++++++++ blocks/block-controls/index.js | 3 +- blocks/editable/index.js | 56 +------------------ blocks/index.js | 2 + blocks/library/quote/index.js | 36 +++++++++--- blocks/library/text/index.js | 43 ++++++++++---- .../test/fixtures/core-text-align-right.html | 2 +- .../test/fixtures/core-text-align-right.json | 1 + .../core-text-align-right.serialized.html | 2 +- 9 files changed, 109 insertions(+), 76 deletions(-) create mode 100644 blocks/alignment-toolbar/index.js diff --git a/blocks/alignment-toolbar/index.js b/blocks/alignment-toolbar/index.js new file mode 100644 index 0000000000000..f0fa63c6a11e1 --- /dev/null +++ b/blocks/alignment-toolbar/index.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { __ } from 'i18n'; +import { Toolbar } from 'components'; + +const ALIGNMENT_CONTROLS = [ + { + icon: 'editor-alignleft', + title: __( 'Align left' ), + align: 'left', + }, + { + icon: 'editor-aligncenter', + title: __( 'Align center' ), + align: 'center', + }, + { + icon: 'editor-alignright', + title: __( 'Align right' ), + align: 'right', + }, +]; + +export default function AlignmentToolbar( { value, onChange } ) { + return ( + { + const { align } = control; + const isActive = ( value === align ); + + return { + ...control, + isActive, + onClick: () => onChange( isActive ? null : align ), + }; + } ) } + /> + ); +} diff --git a/blocks/block-controls/index.js b/blocks/block-controls/index.js index 8ed9ec31efa21..e554ef073f191 100644 --- a/blocks/block-controls/index.js +++ b/blocks/block-controls/index.js @@ -8,10 +8,11 @@ import { Fill } from 'react-slot-fill'; */ import { Toolbar } from 'components'; -export default function BlockControls( { controls } ) { +export default function BlockControls( { controls, children } ) { return ( + { children } ); } diff --git a/blocks/editable/index.js b/blocks/editable/index.js index 382a466afee7b..34116d99d0d15 100644 --- a/blocks/editable/index.js +++ b/blocks/editable/index.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { last, isEqual, capitalize, omitBy, forEach, merge, identity, find } from 'lodash'; +import { last, isEqual, omitBy, forEach, merge, identity, find } from 'lodash'; import { nodeListToReact } from 'dom-react'; import { Fill } from 'react-slot-fill'; import 'element-closest'; @@ -10,7 +10,6 @@ import 'element-closest'; /** * WordPress dependencies */ -import { Toolbar } from 'components'; import { BACKSPACE, DELETE } from 'utils/keycodes'; /** @@ -20,30 +19,6 @@ import './style.scss'; import FormatToolbar from './format-toolbar'; import TinyMCE from './tinymce'; -const alignmentMap = { - alignleft: 'left', - alignright: 'right', - aligncenter: 'center', -}; - -const ALIGNMENT_CONTROLS = [ - { - icon: 'editor-alignleft', - title: wp.i18n.__( 'Align left' ), - align: 'left', - }, - { - icon: 'editor-aligncenter', - title: wp.i18n.__( 'Align center' ), - align: 'center', - }, - { - icon: 'editor-alignright', - title: wp.i18n.__( 'Align right' ), - align: 'right', - }, -]; - function createElement( type, props, ...children ) { if ( props[ 'data-mce-bogus' ] === 'all' ) { return null; @@ -78,7 +53,6 @@ export default class Editable extends wp.element.Component { this.state = { formats: {}, - alignment: null, bookmark: null, empty: ! props.value || ! props.value.length, }; @@ -296,12 +270,10 @@ export default class Editable extends wp.element.Component { } const activeFormats = this.editor.formatter.matchAll( [ 'bold', 'italic', 'strikethrough' ] ); activeFormats.forEach( ( activeFormat ) => formats[ activeFormat ] = true ); - const alignments = this.editor.formatter.matchAll( [ 'alignleft', 'aligncenter', 'alignright' ] ); - const alignment = alignments.length > 0 ? alignmentMap[ alignments[ 0 ] ] : null; const focusPosition = this.getRelativePosition( element ); const bookmark = this.editor.selection.getBookmark( 2, true ); - this.setState( { alignment, bookmark, formats, focusPosition } ); + this.setState( { bookmark, formats, focusPosition } ); } updateContent() { @@ -400,20 +372,6 @@ export default class Editable extends wp.element.Component { this.editor.setDirty( true ); } - isAlignmentActive( align ) { - return this.state.alignment === align; - } - - toggleAlignment( align ) { - this.editor.focus(); - - if ( this.isAlignmentActive( align ) ) { - this.editor.execCommand( 'JustifyNone' ); - } else { - this.editor.execCommand( 'Justify' + capitalize( align ) ); - } - } - render() { const { tagName, @@ -421,7 +379,6 @@ export default class Editable extends wp.element.Component { value, focus, className, - showAlignments = false, inlineToolbar = false, formattingControls, placeholder, @@ -446,15 +403,6 @@ export default class Editable extends wp.element.Component {
{ focus && - { showAlignments && - ( { - ...control, - onClick: () => this.toggleAlignment( control.align ), - isActive: this.isAlignmentActive( control.align ), - } ) ) } - /> - } { ! inlineToolbar && formatToolbar } } diff --git a/blocks/index.js b/blocks/index.js index 5b40f139bc29b..c73c2217117d5 100644 --- a/blocks/index.js +++ b/blocks/index.js @@ -13,5 +13,7 @@ import './library'; // Blocks are inferred from the HTML source of a post through a parsing mechanism // and then stored as objects in state, from which it is then rendered for editing. export * from './api'; +export { default as AlignmentToolbar } from './alignment-toolbar'; +export { default as BlockControls } from './block-controls'; export { default as Editable } from './editable'; export { default as MediaUploadButton } from './media-upload-button'; diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index e75a009503d7f..bb85066968946 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -8,6 +8,8 @@ import { switchChildrenNodeName } from 'element'; */ import './style.scss'; import { registerBlockType, createBlock, query as hpq } from '../../api'; +import AlignmentToolbar from '../../alignment-toolbar'; +import BlockControls from '../../block-controls'; import Editable from '../../editable'; const { children, query } = hpq; @@ -111,11 +113,24 @@ registerBlockType( 'core/quote', { }, edit( { attributes, setAttributes, focus, setFocus, mergeBlocks } ) { - const { value, citation, style = 1 } = attributes; + const { align, value, citation, style = 1 } = attributes; const focusedEditable = focus ? focus.editable || 'value' : null; - return ( -
+ return [ + focus && ( + + { + setAttributes( { align: nextAlign } ); + } } + /> + + ), +
setFocus( { editable: 'value' } ) } onMerge={ mergeBlocks } - showAlignments + style={ { textAlign: align } } /> { ( ( citation && citation.length > 0 ) || !! focus ) && ( ) } -
- ); +
, + ]; }, save( { attributes } ) { - const { value, citation, style = 1 } = attributes; + const { align, value, citation, style = 1 } = attributes; return (
{ value && value.map( ( paragraph, i ) => ( -

{ paragraph }

+

+ { paragraph } +

) ) } { citation && citation.length > 0 && (
{ citation }
diff --git a/blocks/library/text/index.js b/blocks/library/text/index.js index e98587fabb174..1f679feed9cf6 100644 --- a/blocks/library/text/index.js +++ b/blocks/library/text/index.js @@ -1,7 +1,14 @@ +/** + * WordPress dependencies + */ +import { Children, cloneElement } from 'element'; + /** * Internal dependencies */ import { registerBlockType, createBlock, query } from '../../api'; +import AlignmentToolbar from '../../alignment-toolbar'; +import BlockControls from '../../block-controls'; import Editable from '../../editable'; const { children } = query; @@ -17,10 +24,6 @@ registerBlockType( 'core/text', { content: children(), }, - defaultAttributes: { - content:

, - }, - merge( attributes, attributesToMerge ) { return { content: wp.element.concatChildren( attributes.content, attributesToMerge.content ), @@ -28,10 +31,21 @@ registerBlockType( 'core/text', { }, edit( { attributes, setAttributes, insertBlockAfter, focus, setFocus, mergeBlocks } ) { - const { content } = attributes; + const { align, content } = attributes; - return ( + return [ + focus && ( + + { + setAttributes( { align: nextAlign } ); + } } + /> + + ), { setAttributes( { @@ -47,13 +61,20 @@ registerBlockType( 'core/text', { } ) ); } } onMerge={ mergeBlocks } - showAlignments - /> - ); + style={ { textAlign: align } } + />, + ]; }, save( { attributes } ) { - const { content } = attributes; - return content; + const { align, content } = attributes; + + if ( ! align ) { + return content; + } + + return Children.map( content, ( paragraph ) => ( + cloneElement( paragraph, { style: { textAlign: align } } ) + ) ); }, } ); diff --git a/blocks/test/fixtures/core-text-align-right.html b/blocks/test/fixtures/core-text-align-right.html index e838100afca72..d3d0c922ce2bf 100644 --- a/blocks/test/fixtures/core-text-align-right.html +++ b/blocks/test/fixtures/core-text-align-right.html @@ -1,3 +1,3 @@ - +

... like this one, which is separate from the above and right aligned.

diff --git a/blocks/test/fixtures/core-text-align-right.json b/blocks/test/fixtures/core-text-align-right.json index c4854077e8886..3c1eeb3e6ee8b 100644 --- a/blocks/test/fixtures/core-text-align-right.json +++ b/blocks/test/fixtures/core-text-align-right.json @@ -3,6 +3,7 @@ "uid": "_uid_0", "name": "core/text", "attributes": { + "align": "right", "content": [ { "type": "p", diff --git a/blocks/test/fixtures/core-text-align-right.serialized.html b/blocks/test/fixtures/core-text-align-right.serialized.html index 5a483bb238e29..5bbeb051d3186 100644 --- a/blocks/test/fixtures/core-text-align-right.serialized.html +++ b/blocks/test/fixtures/core-text-align-right.serialized.html @@ -1,4 +1,4 @@ - +

... like this one, which is separate from the above and right aligned.