From 7a93da4f8b8925b47b76421eea2b37452da32a1d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 17 Apr 2017 13:51:59 +0100 Subject: [PATCH 1/7] Visual Editor: Keep track of the focused block --- blocks/components/editable/index.js | 31 +++++++++++++++++++++++++++-- blocks/library/heading/index.js | 4 +++- blocks/library/image/index.js | 11 +++++++--- blocks/library/list/index.js | 4 +++- blocks/library/text/index.js | 4 +++- editor/modes/visual-editor/block.js | 18 ++++++++++++++--- editor/state.js | 20 +++++++++++++++++++ editor/test/state.js | 28 +++++++++++++++++++++++++- languages/gutenberg.pot | 2 +- 9 files changed, 109 insertions(+), 13 deletions(-) diff --git a/blocks/components/editable/index.js b/blocks/components/editable/index.js index 0ada78bff1301f..a3edee04e0fea6 100644 --- a/blocks/components/editable/index.js +++ b/blocks/components/editable/index.js @@ -17,6 +17,7 @@ export default class Editable extends wp.element.Component { this.onChange = this.onChange.bind( this ); this.onNewBlock = this.onNewBlock.bind( this ); this.bindNode = this.bindNode.bind( this ); + this.onFocus = this.onFocus.bind( this ); } componentDidMount() { @@ -44,12 +45,23 @@ export default class Editable extends wp.element.Component { this.editor = editor; editor.on( 'init', this.onInit ); editor.on( 'focusout', this.onChange ); - editor.on( 'NewBlock', this.onNewBlock ); + editor.on( 'NewBlock', this.onNewBlock ) + editor.on( 'focusin', this.onFocus ); } onInit() { const { value = '' } = this.props; this.editor.setContent( value ); + this.focus(); + } + + onFocus() { + if ( ! this.props.onFocus ) { + return; + } + + // TODO: We need a way to save the focus position ( bookmark maybe ) + this.props.onFocus(); } onChange() { @@ -107,6 +119,12 @@ export default class Editable extends wp.element.Component { this.editor.selection.moveToBookmark( bookmark ); } + focus() { + if ( this.props.focus ) { + this.editor.focus(); + } + } + componentWillUpdate( nextProps ) { if ( this.editor && this.props.tagName !== nextProps.tagName ) { this.editor.destroy(); @@ -122,7 +140,16 @@ export default class Editable extends wp.element.Component { componentDidUpdate( prevProps ) { if ( this.props.tagName !== prevProps.tagName ) { this.initialize(); - } else if ( this.props.value !== prevProps.value ) { + } + + if ( this.props.focus !== prevProps.focus && this.props.focus ) { + this.focus(); + } + + if ( + this.props.tagName === prevProps.tagName && + this.props.value !== prevProps.value + ) { this.updateContent(); } } diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index acb6c5d0de4f2e..26c2e2f2ec9538 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -31,13 +31,15 @@ registerBlock( 'core/heading', { } ) ) ], - edit( { attributes, setAttributes } ) { + edit( { attributes, setAttributes, focus, updateFocus } ) { const { content, tag, align } = attributes; return ( setAttributes( { content: value } ) } style={ align ? { textAlign: align } : null } /> diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 1705bbcdd0d8cf..8c93ec5546512d 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -19,21 +19,26 @@ registerBlock( 'core/image', { caption: html( 'figcaption' ) }, - edit( { attributes, isSelected, setAttributes } ) { + edit( { attributes, setAttributes, focus, updateFocus } ) { const { url, alt, caption } = attributes; + const focusCaption = () => updateFocus( { editable: 'caption' } ); + /* eslint-disable */ return (
- { - { caption || isSelected ? ( + { + { caption || !! focus ? ( setAttributes( { caption: value } ) } /> ) : null }
); + /* eslint-enable */ }, save( { attributes } ) { diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index 7b8112444a4f0c..f19fdedd34bc19 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -54,7 +54,7 @@ registerBlock( 'core/list', { } ], - edit( { attributes } ) { + edit( { attributes, focus, updateFocus } ) { const { listType = 'ol', items = [], align } = attributes; const content = items.map( item => { return `
  • ${ item.value }
  • `; @@ -65,6 +65,8 @@ registerBlock( 'core/list', { tagName={ listType } style={ align ? { textAlign: align } : null } value={ content } + focus={ focus } + onFocus={ updateFocus } className="blocks-list" /> ); }, diff --git a/blocks/library/text/index.js b/blocks/library/text/index.js index 540c8c01d232a9..9441ffc096119e 100644 --- a/blocks/library/text/index.js +++ b/blocks/library/text/index.js @@ -47,7 +47,7 @@ registerBlock( 'core/text', { } ], - edit( { attributes, setAttributes, insertBlockAfter } ) { + edit( { attributes, setAttributes, insertBlockAfter, focus, updateFocus } ) { const { content, align } = attributes; return ( @@ -56,6 +56,8 @@ registerBlock( 'core/text', { onChange={ ( paragraphs ) => setAttributes( { content: fromParagraphsToValue( paragraphs ) } ) } + focus={ focus } + onFocus={ updateFocus } style={ align ? { textAlign: align } : null } onSplit={ ( before, after ) => { setAttributes( { content: fromParagraphsToValue( before ) } ); diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 5284eb483644ef..336a1c0c6d3d5f 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -75,13 +75,13 @@ class VisualEditorBlock extends wp.element.Component { return null; } - const { isHovered, isSelected } = this.props; + const { isHovered, isSelected, focus } = this.props; const className = classnames( 'editor-visual-editor__block', { 'is-selected': isSelected, 'is-hovered': isHovered } ); - const { onSelect, onDeselect, onMouseEnter, onMouseLeave, onInsertAfter } = this.props; + const { onSelect, onDeselect, onMouseEnter, onMouseLeave, onInsertAfter, onFocus } = this.props; // Disable reason: Each block can receive focus but must be able to contain // block children. Tab keyboard navigation enabled by tabIndex assignment. @@ -112,9 +112,11 @@ class VisualEditorBlock extends wp.element.Component { ); @@ -127,7 +129,8 @@ export default connect( order: state.blocks.order.indexOf( ownProps.uid ), block: state.blocks.byUid[ ownProps.uid ], isSelected: state.selectedBlock === ownProps.uid, - isHovered: state.hoveredBlock === ownProps.uid + isHovered: state.hoveredBlock === ownProps.uid, + focus: state.focus.uid === ownProps.uid ? state.focus.config : null } ), ( dispatch, ownProps ) => ( { onChange( updates ) { @@ -165,12 +168,21 @@ export default connect( uid: ownProps.uid } ); }, + onInsertAfter( block ) { dispatch( { type: 'INSERT_BLOCK', after: ownProps.uid, block } ); + }, + + onFocus( config = {} ) { + dispatch( { + type: 'UPDATE_FOCUS', + uid: ownProps.uid, + config + } ); } } ) )( VisualEditorBlock ); diff --git a/editor/state.js b/editor/state.js index 6a1dc174172bbc..63c80112213248 100644 --- a/editor/state.js +++ b/editor/state.js @@ -138,6 +138,25 @@ export function hoveredBlock( state = null, action ) { return state; } +/** + * Reducer returning the focused block state. + * + * @param {Object} state Current state + * @param {Object} action Dispatched action + * @return {Object} Updated state + */ +export function focus( state = {}, action ) { + switch ( action.type ) { + case 'UPDATE_FOCUS': + return { + uid: action.uid, + config: action.config + }; + } + + return state; +} + /** * Reducer returning current editor mode, either "visual" or "text". * @@ -171,6 +190,7 @@ export function isSidebarOpened( state = false, action ) { export function createReduxStore() { const reducer = combineReducers( { blocks, + focus, selectedBlock, hoveredBlock, mode, diff --git a/editor/test/state.js b/editor/test/state.js index 24b04c37abb835..2e5c6a1f4c5922 100644 --- a/editor/test/state.js +++ b/editor/test/state.js @@ -9,6 +9,7 @@ import { values } from 'lodash'; */ import { blocks, + focus, hoveredBlock, selectedBlock, mode, @@ -320,6 +321,30 @@ describe( 'state', () => { } ); } ); + describe( 'focus()', () => { + it( 'should return an empty object by default', () => { + const state = focus( undefined, {} ); + expect( state ).to.eql( {} ); + } ); + + it( 'should update the focused block', () => { + const state = focus( null, { + type: 'UPDATE_FOCUS', + uid: 'chicken', + config: { + editable: 'ribs' + } + } ); + + expect( state ).to.eql( { + uid: 'chicken', + config: { + editable: 'ribs' + } + } ); + } ); + } ); + describe( 'createReduxStore()', () => { it( 'should return a redux store', () => { const store = createReduxStore(); @@ -337,7 +362,8 @@ describe( 'state', () => { 'selectedBlock', 'hoveredBlock', 'mode', - 'isSidebarOpened' + 'isSidebarOpened', + 'focus' ] ); } ); } ); diff --git a/languages/gutenberg.pot b/languages/gutenberg.pot index 88a6bcbc8b5f94..8c88632ce5da83 100644 --- a/languages/gutenberg.pot +++ b/languages/gutenberg.pot @@ -19,7 +19,7 @@ msgstr "" msgid "Image" msgstr "" -#: blocks/library/image/index.js:31 +#: blocks/library/image/index.js:33 msgid "Write caption…" msgstr "" From 5686bd88fef9faf541be7f3e48d356229dadf8f1 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 17 Apr 2017 16:39:54 +0100 Subject: [PATCH 2/7] Handling the focus in the quote block --- blocks/library/quote/index.js | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index a88a47bdf5cbb3..08668547b78bef 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -20,7 +20,7 @@ registerBlock( 'core/quote', { citation: html( 'footer' ) }, - edit( { attributes, setAttributes } ) { + edit( { attributes, setAttributes, focus, updateFocus } ) { const { value, citation } = attributes; return ( @@ -31,16 +31,24 @@ registerBlock( 'core/quote', { ( paragraphs ) => setAttributes( { value: fromParagraphsToValue( paragraphs ) } ) - } /> -
    - setAttributes( { - citation: newValue - } ) - } /> -
    + } + focus={ focus && focus.editable === 'value' ? focus : null } + onFocus={ () => updateFocus( { editable: 'value' } ) } + /> + { ( citation || !! focus ) && +
    + setAttributes( { + citation: newValue + } ) + } + focus={ focus && focus.editable === 'citation' ? focus : null } + onFocus={ () => updateFocus( { editable: 'citation' } ) } + /> +
    + } ); }, From 004ef08d38a020ab668746ac959664afc5c16eea Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 17 Apr 2017 18:11:36 +0100 Subject: [PATCH 3/7] Disabling specific ESLint rules --- blocks/library/image/index.js | 13 +++++++------ languages/gutenberg.pot | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 8c93ec5546512d..dd090f4ea222a6 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -21,24 +21,25 @@ registerBlock( 'core/image', { edit( { attributes, setAttributes, focus, updateFocus } ) { const { url, alt, caption } = attributes; - const focusCaption = () => updateFocus( { editable: 'caption' } ); - /* eslint-disable */ + // Disable reason: Clicking the image should set the focus to its caption + + /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/onclick-has-role, jsx-a11y/no-static-element-interactions */ return (
    - { + { { caption || !! focus ? ( setAttributes( { caption: value } ) } /> ) : null }
    ); - /* eslint-enable */ + /* eslint-enable jsx-a11y/click-events-have-key-events, jsx-a11y/onclick-has-role, jsx-a11y/no-static-element-interactions */ }, save( { attributes } ) { diff --git a/languages/gutenberg.pot b/languages/gutenberg.pot index 8c88632ce5da83..c016e1c2b37c42 100644 --- a/languages/gutenberg.pot +++ b/languages/gutenberg.pot @@ -19,7 +19,7 @@ msgstr "" msgid "Image" msgstr "" -#: blocks/library/image/index.js:33 +#: blocks/library/image/index.js:34 msgid "Write caption…" msgstr "" From 6db8d8e6d5208c1c33d64873a8cf9f0ef874002a Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 18 Apr 2017 11:16:57 +0100 Subject: [PATCH 4/7] Merge the focus and the selected contcepts --- blocks/library/image/index.js | 6 +- editor/modes/visual-editor/block.js | 30 ++++--- editor/state.js | 62 ++++++++------ editor/test/state.js | 120 +++++++++++++++++++++------- languages/gutenberg.pot | 2 +- 5 files changed, 147 insertions(+), 73 deletions(-) diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index dd090f4ea222a6..b1423cc1a0c654 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -22,12 +22,9 @@ registerBlock( 'core/image', { edit( { attributes, setAttributes, focus, updateFocus } ) { const { url, alt, caption } = attributes; - // Disable reason: Clicking the image should set the focus to its caption - - /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/onclick-has-role, jsx-a11y/no-static-element-interactions */ return (
    - { + { { caption || !! focus ? ( ); - /* eslint-enable jsx-a11y/click-events-have-key-events, jsx-a11y/onclick-has-role, jsx-a11y/no-static-element-interactions */ }, save( { attributes } ) { diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 336a1c0c6d3d5f..6b0eecba29da1c 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -75,13 +75,13 @@ class VisualEditorBlock extends wp.element.Component { return null; } - const { isHovered, isSelected, focus } = this.props; + const { isHovered, isSelected, isTyping, focus } = this.props; const className = classnames( 'editor-visual-editor__block', { - 'is-selected': isSelected, + 'is-selected': isSelected && ! isTyping, 'is-hovered': isHovered } ); - const { onSelect, onDeselect, onMouseEnter, onMouseLeave, onInsertAfter, onFocus } = this.props; + const { onSelect, onStartTyping, onMouseMove, onMouseLeave, onFocus, onInsertAfter } = this.props; // Disable reason: Each block can receive focus but must be able to contain // block children. Tab keyboard navigation enabled by tabIndex assignment. @@ -93,15 +93,15 @@ class VisualEditorBlock extends wp.element.Component { tabIndex="0" onFocus={ onSelect } onBlur={ this.maybeDeselect } - onKeyDown={ onDeselect } - onMouseEnter={ onMouseEnter } + onKeyDown={ onStartTyping } + onMouseMove={ onMouseMove } onMouseLeave={ onMouseLeave } className={ className } > - { ( isSelected || isHovered ) && } + { ( ( isSelected && ! isTyping ) || isHovered ) && }
    - { isSelected && } - { isSelected && settings.controls ? ( + { isSelected && ! isTyping && } + { isSelected && ! isTyping && settings.controls ? ( ( { ...control, @@ -111,7 +111,6 @@ class VisualEditorBlock extends wp.element.Component { ) : null }
    ( { order: state.blocks.order.indexOf( ownProps.uid ), block: state.blocks.byUid[ ownProps.uid ], - isSelected: state.selectedBlock === ownProps.uid, + isSelected: state.selectedBlock.uid === ownProps.uid, isHovered: state.hoveredBlock === ownProps.uid, - focus: state.focus.uid === ownProps.uid ? state.focus.config : null + focus: state.selectedBlock.uid === ownProps.uid ? state.selectedBlock.focus : null, + isTyping: state.selectedBlock.uid === ownProps.uid ? state.selectedBlock.typing : false, } ), ( dispatch, ownProps ) => ( { onChange( updates ) { @@ -154,7 +154,13 @@ export default connect( uid: ownProps.uid } ); }, - onMouseEnter() { + onStartTyping() { + dispatch( { + type: 'START_TYPING', + uid: ownProps.uid + } ); + }, + onMouseMove() { dispatch( { type: 'TOGGLE_BLOCK_HOVERED', hovered: true, diff --git a/editor/state.js b/editor/state.js index 63c80112213248..8bd9c486d76cb9 100644 --- a/editor/state.js +++ b/editor/state.js @@ -100,17 +100,49 @@ export const blocks = combineUndoableReducers( { * @param {Object} action Dispatched action * @return {Object} Updated state */ -export function selectedBlock( state = null, action ) { +export function selectedBlock( state = {}, action ) { switch ( action.type ) { case 'TOGGLE_BLOCK_SELECTED': - return action.selected ? action.uid : null; + if ( ! action.selected ) { + return state.uid === action.uid ? {} : state; + } + return action.uid === state.uid + ? state + : { uid: action.uid, typing: false, focus: {} }; case 'MOVE_BLOCK_UP': case 'MOVE_BLOCK_DOWN': - return action.uid; + return action.uid === state.uid + ? state + : { uid: action.uid, typing: false, focus: {} }; case 'INSERT_BLOCK': - return action.block.uid; + return { + uid: action.block.uid, + typing: false, + focus: {} + }; + + case 'UPDATE_FOCUS': + return { + uid: action.uid, + typing: state.uid === action.uid ? state.typing : false, + focus: action.config + }; + + case 'START_TYPING': + if ( action.uid !== state.uid ) { + return { + uid: action.uid, + typing: true, + focus: {} + }; + } + + return { + ...state, + typing: true + }; } return state; @@ -133,25 +165,8 @@ export function hoveredBlock( state = null, action ) { return null; } break; - } - - return state; -} - -/** - * Reducer returning the focused block state. - * - * @param {Object} state Current state - * @param {Object} action Dispatched action - * @return {Object} Updated state - */ -export function focus( state = {}, action ) { - switch ( action.type ) { - case 'UPDATE_FOCUS': - return { - uid: action.uid, - config: action.config - }; + case 'START_TYPING': + return null; } return state; @@ -190,7 +205,6 @@ export function isSidebarOpened( state = false, action ) { export function createReduxStore() { const reducer = combineReducers( { blocks, - focus, selectedBlock, hoveredBlock, mode, diff --git a/editor/test/state.js b/editor/test/state.js index 2e5c6a1f4c5922..5c7e89c25ef1f6 100644 --- a/editor/test/state.js +++ b/editor/test/state.js @@ -3,13 +3,13 @@ */ import { expect } from 'chai'; import { values } from 'lodash'; +import deepFreeze from 'deep-freeze'; /** * Internal dependencies */ import { blocks, - focus, hoveredBlock, selectedBlock, mode, @@ -227,7 +227,40 @@ describe( 'state', () => { selected: true } ); - expect( state ).to.equal( 'kumquat' ); + expect( state ).to.eql( { uid: 'kumquat', typing: false, focus: {} } ); + } ); + + it( 'should not update the state if already selected', () => { + const original = deepFreeze( { uid: 'kumquat', typing: true, focus: {} } ); + const state = selectedBlock( original, { + type: 'TOGGLE_BLOCK_SELECTED', + uid: 'kumquat', + selected: true + } ); + + expect( state ).to.equal( original ); + } ); + + it( 'should unselect the block if currently selected', () => { + const original = deepFreeze( { uid: 'kumquat', typing: true, focus: {} } ); + const state = selectedBlock( original, { + type: 'TOGGLE_BLOCK_SELECTED', + uid: 'kumquat', + selected: false + } ); + + expect( state ).to.eql( {} ); + } ); + + it( 'should not unselect the block if another block is selected', () => { + const original = deepFreeze( { uid: 'loquat', typing: true, focus: {} } ); + const state = selectedBlock( original, { + type: 'TOGGLE_BLOCK_SELECTED', + uid: 'kumquat', + selected: false + } ); + + expect( state ).to.equal( original ); } ); it( 'should return with inserted block', () => { @@ -239,7 +272,7 @@ describe( 'state', () => { } } ); - expect( state ).to.equal( 'ribs' ); + expect( state ).to.eql( { uid: 'ribs', typing: false, focus: {} } ); } ); it( 'should return with block moved up', () => { @@ -248,7 +281,7 @@ describe( 'state', () => { uid: 'ribs' } ); - expect( state ).to.equal( 'ribs' ); + expect( state ).to.eql( { uid: 'ribs', typing: false, focus: {} } ); } ); it( 'should return with block moved down', () => { @@ -257,7 +290,57 @@ describe( 'state', () => { uid: 'chicken' } ); - expect( state ).to.equal( 'chicken' ); + expect( state ).to.eql( { uid: 'chicken', typing: false, focus: {} } ); + } ); + + it( 'should not update the state if the block moved is already selected', () => { + const original = deepFreeze( { uid: 'ribs', typing: true, focus: {} } ); + const state = selectedBlock( original, { + type: 'MOVE_BLOCK_UP', + uid: 'ribs' + } ); + + expect( state ).to.equal( original ); + } ); + + it( 'should update the focus and selects the block', () => { + const state = selectedBlock( undefined, { + type: 'UPDATE_FOCUS', + uid: 'chicken', + config: { editable: 'citation' } + } ); + + expect( state ).to.eql( { uid: 'chicken', typing: false, focus: { editable: 'citation' } } ); + } ); + + it( 'should update the focus and merge the existing state', () => { + const original = deepFreeze( { uid: 'ribs', typing: true, focus: {} } ); + const state = selectedBlock( original, { + type: 'UPDATE_FOCUS', + uid: 'ribs', + config: { editable: 'citation' } + } ); + + expect( state ).to.eql( { uid: 'ribs', typing: true, focus: { editable: 'citation' } } ); + } ); + + it( 'should set the typing flag and selects the block', () => { + const state = selectedBlock( undefined, { + type: 'START_TYPING', + uid: 'chicken' + } ); + + expect( state ).to.eql( { uid: 'chicken', typing: true, focus: {} } ); + } ); + + it( 'should set the typing flag and merge the existing state', () => { + const original = deepFreeze( { uid: 'ribs', typing: false, focus: { editable: 'citation' } } ); + const state = selectedBlock( original, { + type: 'START_TYPING', + uid: 'ribs' + } ); + + expect( state ).to.eql( { uid: 'ribs', typing: true, focus: { editable: 'citation' } } ); } ); it( 'should insert after the specified block uid', () => { @@ -321,30 +404,6 @@ describe( 'state', () => { } ); } ); - describe( 'focus()', () => { - it( 'should return an empty object by default', () => { - const state = focus( undefined, {} ); - expect( state ).to.eql( {} ); - } ); - - it( 'should update the focused block', () => { - const state = focus( null, { - type: 'UPDATE_FOCUS', - uid: 'chicken', - config: { - editable: 'ribs' - } - } ); - - expect( state ).to.eql( { - uid: 'chicken', - config: { - editable: 'ribs' - } - } ); - } ); - } ); - describe( 'createReduxStore()', () => { it( 'should return a redux store', () => { const store = createReduxStore(); @@ -362,8 +421,7 @@ describe( 'state', () => { 'selectedBlock', 'hoveredBlock', 'mode', - 'isSidebarOpened', - 'focus' + 'isSidebarOpened' ] ); } ); } ); diff --git a/languages/gutenberg.pot b/languages/gutenberg.pot index c016e1c2b37c42..88a6bcbc8b5f94 100644 --- a/languages/gutenberg.pot +++ b/languages/gutenberg.pot @@ -19,7 +19,7 @@ msgstr "" msgid "Image" msgstr "" -#: blocks/library/image/index.js:34 +#: blocks/library/image/index.js:31 msgid "Write caption…" msgstr "" From c990b516fdadf5f348149600140464edbb32b71b Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 19 Apr 2017 14:00:20 +0100 Subject: [PATCH 5/7] Focus: rename `updateFocus` to `setFocus` and default value in state --- blocks/components/editable/index.js | 2 +- blocks/library/heading/index.js | 4 ++-- blocks/library/image/index.js | 4 ++-- blocks/library/list/index.js | 4 ++-- blocks/library/quote/index.js | 6 +++--- blocks/library/text/index.js | 4 ++-- editor/modes/visual-editor/block.js | 2 +- editor/state.js | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/blocks/components/editable/index.js b/blocks/components/editable/index.js index a3edee04e0fea6..c56c2af7c6fd44 100644 --- a/blocks/components/editable/index.js +++ b/blocks/components/editable/index.js @@ -45,7 +45,7 @@ export default class Editable extends wp.element.Component { this.editor = editor; editor.on( 'init', this.onInit ); editor.on( 'focusout', this.onChange ); - editor.on( 'NewBlock', this.onNewBlock ) + editor.on( 'NewBlock', this.onNewBlock ); editor.on( 'focusin', this.onFocus ); } diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index 26c2e2f2ec9538..e0891c0916ca2b 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -31,7 +31,7 @@ registerBlock( 'core/heading', { } ) ) ], - edit( { attributes, setAttributes, focus, updateFocus } ) { + edit( { attributes, setAttributes, focus, setFocus } ) { const { content, tag, align } = attributes; return ( @@ -39,7 +39,7 @@ registerBlock( 'core/heading', { tagName={ tag } value={ content } focus={ focus } - onFocus={ updateFocus } + onFocus={ setFocus } onChange={ ( value ) => setAttributes( { content: value } ) } style={ align ? { textAlign: align } : null } /> diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index b1423cc1a0c654..6b93a95e70f0bd 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -19,7 +19,7 @@ registerBlock( 'core/image', { caption: html( 'figcaption' ) }, - edit( { attributes, setAttributes, focus, updateFocus } ) { + edit( { attributes, setAttributes, focus, setFocus } ) { const { url, alt, caption } = attributes; return ( @@ -31,7 +31,7 @@ registerBlock( 'core/image', { placeholder={ wp.i18n.__( 'Write caption…' ) } value={ caption } focus={ focus } - onFocus={ updateFocus } + onFocus={ setFocus } onChange={ ( value ) => setAttributes( { caption: value } ) } /> ) : null }
    diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index f19fdedd34bc19..ea98f5ed0c1424 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -54,7 +54,7 @@ registerBlock( 'core/list', { } ], - edit( { attributes, focus, updateFocus } ) { + edit( { attributes, focus, setFocus } ) { const { listType = 'ol', items = [], align } = attributes; const content = items.map( item => { return `
  • ${ item.value }
  • `; @@ -66,7 +66,7 @@ registerBlock( 'core/list', { style={ align ? { textAlign: align } : null } value={ content } focus={ focus } - onFocus={ updateFocus } + onFocus={ setFocus } className="blocks-list" /> ); }, diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index 08668547b78bef..7d661d08032230 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -20,7 +20,7 @@ registerBlock( 'core/quote', { citation: html( 'footer' ) }, - edit( { attributes, setAttributes, focus, updateFocus } ) { + edit( { attributes, setAttributes, focus, setFocus } ) { const { value, citation } = attributes; return ( @@ -33,7 +33,7 @@ registerBlock( 'core/quote', { } ) } focus={ focus && focus.editable === 'value' ? focus : null } - onFocus={ () => updateFocus( { editable: 'value' } ) } + onFocus={ () => setFocus( { editable: 'value' } ) } /> { ( citation || !! focus ) &&
    @@ -45,7 +45,7 @@ registerBlock( 'core/quote', { } ) } focus={ focus && focus.editable === 'citation' ? focus : null } - onFocus={ () => updateFocus( { editable: 'citation' } ) } + onFocus={ () => setFocus( { editable: 'citation' } ) } />
    } diff --git a/blocks/library/text/index.js b/blocks/library/text/index.js index 9441ffc096119e..007e7f4a099fe8 100644 --- a/blocks/library/text/index.js +++ b/blocks/library/text/index.js @@ -47,7 +47,7 @@ registerBlock( 'core/text', { } ], - edit( { attributes, setAttributes, insertBlockAfter, focus, updateFocus } ) { + edit( { attributes, setAttributes, insertBlockAfter, focus, setFocus } ) { const { content, align } = attributes; return ( @@ -57,7 +57,7 @@ registerBlock( 'core/text', { content: fromParagraphsToValue( paragraphs ) } ) } focus={ focus } - onFocus={ updateFocus } + onFocus={ setFocus } style={ align ? { textAlign: align } : null } onSplit={ ( before, after ) => { setAttributes( { content: fromParagraphsToValue( before ) } ); diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 6b0eecba29da1c..ebd869645d1322 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -183,7 +183,7 @@ export default connect( } ); }, - onFocus( config = {} ) { + onFocus( config ) { dispatch( { type: 'UPDATE_FOCUS', uid: ownProps.uid, diff --git a/editor/state.js b/editor/state.js index 8bd9c486d76cb9..f9e35785522ca4 100644 --- a/editor/state.js +++ b/editor/state.js @@ -127,7 +127,7 @@ export function selectedBlock( state = {}, action ) { return { uid: action.uid, typing: state.uid === action.uid ? state.typing : false, - focus: action.config + focus: action.config || {} }; case 'START_TYPING': From e0cefb8db380b925a97ad4f85c92d21482939143 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 19 Apr 2017 16:52:11 +0100 Subject: [PATCH 6/7] Optimize onMouseMove calls --- editor/modes/visual-editor/block.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index ebd869645d1322..bfda6a43ba1ade 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -17,6 +17,7 @@ class VisualEditorBlock extends wp.element.Component { this.bindBlockNode = this.bindBlockNode.bind( this ); this.setAttributes = this.setAttributes.bind( this ); this.maybeDeselect = this.maybeDeselect.bind( this ); + this.maybeHover = this.maybeHover.bind( this ); this.previousOffset = null; } @@ -44,6 +45,13 @@ class VisualEditorBlock extends wp.element.Component { } ); } + maybeHover() { + const { isTyping, isHovered, onHover } = this.props; + if ( isTyping && ! isHovered ) { + onHover(); + } + } + maybeDeselect( event ) { // Annoyingly React does not support focusOut and we're forced to check // related target to ensure it's not a child when blur fires. @@ -81,7 +89,7 @@ class VisualEditorBlock extends wp.element.Component { 'is-hovered': isHovered } ); - const { onSelect, onStartTyping, onMouseMove, onMouseLeave, onFocus, onInsertAfter } = this.props; + const { onSelect, onStartTyping, onHover, onMouseLeave, onFocus, onInsertAfter } = this.props; // Disable reason: Each block can receive focus but must be able to contain // block children. Tab keyboard navigation enabled by tabIndex assignment. @@ -94,7 +102,8 @@ class VisualEditorBlock extends wp.element.Component { onFocus={ onSelect } onBlur={ this.maybeDeselect } onKeyDown={ onStartTyping } - onMouseMove={ onMouseMove } + onMouseEnter={ onHover } + onMouseMove={ this.maybeHover } onMouseLeave={ onMouseLeave } className={ className } > @@ -160,7 +169,7 @@ export default connect( uid: ownProps.uid } ); }, - onMouseMove() { + onHover() { dispatch( { type: 'TOGGLE_BLOCK_HOVERED', hovered: true, From 56af22cb3dd2aefc105b8297938f74ee6be33b5a Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 19 Apr 2017 17:49:04 +0100 Subject: [PATCH 7/7] Optimizing the updating focus call --- blocks/components/editable/index.js | 2 +- editor/modes/visual-editor/block.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blocks/components/editable/index.js b/blocks/components/editable/index.js index c56c2af7c6fd44..0edfba8f520053 100644 --- a/blocks/components/editable/index.js +++ b/blocks/components/editable/index.js @@ -142,7 +142,7 @@ export default class Editable extends wp.element.Component { this.initialize(); } - if ( this.props.focus !== prevProps.focus && this.props.focus ) { + if ( !! this.props.focus && ! prevProps.focus ) { this.focus(); } diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index bfda6a43ba1ade..703ca8bb70ff6f 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -124,7 +124,7 @@ class VisualEditorBlock extends wp.element.Component { attributes={ block.attributes } setAttributes={ this.setAttributes } insertBlockAfter={ onInsertAfter } - updateFocus={ onFocus } + setFocus={ onFocus } /> );