Skip to content

Commit

Permalink
TinyMCE per block: Handle focus as state instead of using imperative …
Browse files Browse the repository at this point in the history
…API (#167)
  • Loading branch information
youknowriad authored Mar 2, 2017
1 parent a2e6695 commit a11f577
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 74 deletions.
1 change: 0 additions & 1 deletion tinymce-per-block/src/blocks/heading-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import EditableFormatToolbar from 'controls/editable-format-toolbar';
export default class HeadingBlockForm extends Component {
bindForm = ( ref ) => {
this.form = ref;
this.focus = ( ...args ) => this.form.focus( ...args );
this.merge = ( ...args ) => this.form.merge( ...args );
};

Expand Down
4 changes: 0 additions & 4 deletions tinymce-per-block/src/blocks/image-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export default class ImageBlockForm extends Component {
this.props.remove();
}

focus( position ) {
this.caption.focus( position );
}

bindCaption = ( ref ) => {
this.caption = ref;
}
Expand Down
11 changes: 5 additions & 6 deletions tinymce-per-block/src/blocks/inline-text-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import { EditableComponent } from 'wp-blocks';
import { serialize } from 'serializers/block';

export default class InlineTextBlockForm extends Component {
focus( position ) {
this.editable.focus( position );
}

merge = ( block, index ) => {
const acceptedBlockTypes = [ 'quote', 'paragraph', 'heading' ];
if ( acceptedBlockTypes.indexOf( block.blockType ) === -1 ) {
Expand Down Expand Up @@ -40,7 +36,8 @@ export default class InlineTextBlockForm extends Component {
};

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

const splitValue = ( left, right ) => {
Expand All @@ -66,9 +63,11 @@ export default class InlineTextBlockForm extends Component {
mergeWithPrevious={ mergeWithPrevious }
remove={ remove }
onChange={ ( value ) => setChildren( value ) }
setToolbarState={ setToolbarState }
focusConfig={ focusConfig }
onFocusChange={ focus }
inline
single
setToolbarState={ setToolbarState }
/>
);
}
Expand Down
1 change: 0 additions & 1 deletion tinymce-per-block/src/blocks/paragraph-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import InlineTextBlockForm from '../inline-text-block/form';
export default class ParagraphBlockForm extends Component {
bindForm = ( ref ) => {
this.form = ref;
this.focus = ( ...args ) => this.form.focus( ...args );
this.merge = ( ...args ) => this.form.merge( ...args );
};

Expand Down
20 changes: 12 additions & 8 deletions tinymce-per-block/src/blocks/quote-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export default class QuoteBlockForm extends Component {
this.cite = ref;
};

focus( position ) {
this.content.focus( position );
}

merge = ( block, index ) => {
const acceptedBlockTypes = [ 'quote', 'paragraph', 'heading' ];
if ( acceptedBlockTypes.indexOf( block.blockType ) === -1 ) {
Expand All @@ -38,15 +34,15 @@ export default class QuoteBlockForm extends Component {
const { block: { children }, remove, setChildren } = this.props;
remove( index );
setTimeout( () => setChildren( getLeaves( children ).concat( getLeaves( block.children ) ) ) );
setTimeout( () => this.editable.updateContent() );
setTimeout( () => this.content.updateContent() );
}

moveToCite = () => {
this.cite.focus( 0 );
this.props.focus( { input: 'cite', start: true } );
};

moveToContent = () => {
this.content.focus();
this.props.focus( { input: 'content', end: true } );
};

bindFormatToolbar = ( ref ) => {
Expand All @@ -59,7 +55,7 @@ export default class QuoteBlockForm extends Component {

render() {
const { block, setChildren, setAttributes, moveUp,
moveDown, remove, mergeWithPrevious, appendBlock, isFocused } = this.props;
moveDown, remove, mergeWithPrevious, appendBlock, isFocused, focusConfig, focus } = this.props;
const { children } = block;
const cite = block.attrs.cite || '';
const splitValue = ( left, right ) => {
Expand All @@ -77,6 +73,10 @@ export default class QuoteBlockForm extends Component {
} ]
} );
};
let focusInput = focusConfig && focusConfig.input;
if ( ! focusInput && focusConfig ) {
focusInput = focusConfig.end ? 'cite' : 'content';
}

return (
<div>
Expand All @@ -100,6 +100,8 @@ export default class QuoteBlockForm extends Component {
remove={ remove }
onChange={ ( value ) => setChildren( value ) }
setToolbarState={ this.setToolbarState }
focusConfig={ focusInput === 'content' ? focusConfig : null }
onFocusChange={ ( config ) => focus( Object.assign( { input: 'content' }, config ) ) }
inline
/>
</div>
Expand All @@ -112,6 +114,8 @@ export default class QuoteBlockForm extends Component {
value={ cite }
splitValue={ splitValue }
onChange={ ( value ) => setAttributes( { cite: value } ) }
focusConfig={ focusInput === 'cite' ? focusConfig : null }
onFocusChange={ ( config ) => focus( Object.assign( { input: 'cite' }, config ) ) }
placeholder="Enter a cite"
/>
</div>
Expand Down
13 changes: 7 additions & 6 deletions tinymce-per-block/src/blocks/text-block/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import EditableFormatToolbar from 'controls/editable-format-toolbar';
import BlockArrangement from 'controls/block-arrangement';

export default class TextBlockForm extends Component {
focus( position ) {
this.editable.focus( position );
}

merge = ( block, index ) => {
const acceptedBlockTypes = [ 'text', 'quote', 'paragraph', 'heading' ];
if ( acceptedBlockTypes.indexOf( block.blockType ) === -1 ) {
Expand All @@ -22,6 +18,7 @@ export default class TextBlockForm extends Component {
const { block: { children }, remove, setChildren } = this.props;
remove( index );
setTimeout( () => setChildren( children.concat( block.children ) ) );
setTimeout( () => this.editable.updateContent() );
}

bindEditable = ( ref ) => {
Expand All @@ -41,7 +38,8 @@ export default class TextBlockForm extends Component {
};

render() {
const { block, isFocused, setChildren, moveUp, moveDown, appendBlock, mergeWithPrevious, remove } = this.props;
const { block, isFocused, setChildren, moveUp, moveDown, appendBlock,
mergeWithPrevious, remove, focusConfig, focus } = this.props;
const { children } = block;
const splitValue = ( left, right ) => {
setChildren( left );
Expand Down Expand Up @@ -83,7 +81,10 @@ export default class TextBlockForm extends Component {
mergeWithPrevious={ mergeWithPrevious }
remove={ remove }
setToolbarState={ this.setToolbarState }
onChange={ ( value ) => setChildren( value ) } />
onChange={ ( value ) => setChildren( value ) }
focusConfig={ focusConfig }
onFocusChange={ focus }
/>
</div>
</div>
);
Expand Down
27 changes: 22 additions & 5 deletions tinymce-per-block/src/external/wp-blocks/editable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default class EditableComponent extends Component {
static defaultProps = {
onChange: () => {},
splitValue: () => {},
onFocusChange: () => {},
initialContent: '',
inline: false,
single: false,
Expand All @@ -62,13 +63,22 @@ export default class EditableComponent extends Component {
}
}

focus( position ) {
componentDidUpdate( prevProps ) {
if ( this.props.focusConfig !== prevProps.focusConfig && this.props.focusConfig ) {
this.focus();
}
}

focus() {
this.editor.focus();
if ( position !== undefined ) {
this.editor.selection.setCursorLocation( undefined, position );
} else {
const { start = false, end = false, bookmark = false } = this.props.focusConfig;
if ( start ) {
this.editor.selection.setCursorLocation( undefined, 0 );
} else if ( end ) {
this.editor.selection.select( this.editor.getBody(), true );
this.editor.selection.collapse( false );
} else if ( bookmark ) {
// this.editor.selection.moveToBookmark( bookmark );
}
}

Expand Down Expand Up @@ -98,7 +108,8 @@ export default class EditableComponent extends Component {
}
} else if ( event.keyCode === 40 ) {
const bookmark = this.editor.selection.getBookmark();
this.focus();
this.editor.selection.select( this.editor.getBody(), true );
this.editor.selection.collapse( false );
const finalBookmark = this.editor.selection.getBookmark( 2, true );
this.editor.selection.moveToBookmark( bookmark );
if ( isEqual( this.editor.selection.getBookmark( 2, true ), finalBookmark ) ) {
Expand Down Expand Up @@ -162,6 +173,11 @@ export default class EditableComponent extends Component {
} );
};

onFocus = () => {
const bookmark = this.editor.selection.getBookmark( 2, true );
this.props.onFocusChange( { bookmark } );
};

onSetup = ( editor ) => {
this.editor = editor;

Expand All @@ -170,6 +186,7 @@ export default class EditableComponent extends Component {
editor.on( 'keydown', this.onKeyDown );
editor.on( 'paste', this.onPaste );
editor.on( 'nodechange', this.syncToolbar );
editor.on( 'focusin', this.onFocus );
};

onInit = () => {
Expand Down
26 changes: 17 additions & 9 deletions tinymce-per-block/src/external/wp-blocks/input/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ export default class EnhancedInput extends Component {
splitValue: () => {},
removePrevious: () => {},
onChange: () => {},
onFocusChange: () => {},
moveUp: () => {},
moveDown: () => {}
moveDown: () => {},
};

bindInput = ( ref ) => {
Expand All @@ -22,15 +23,18 @@ export default class EnhancedInput extends Component {
this.mirror = ref;
};

focus = ( position ) => {
focus() {
const { start = false } = this.props.focusConfig;
this.input.focus();
if ( position !== undefined ) {
this.input.setSelectionRange( position, position );
if (  start ) {
this.input.setSelectionRange( 0, 0 );
}
}

componentDidMount() {
this.render();
componentDidUpdate( prevProps ) {
if ( this.props.focusConfig !== prevProps.focusConfig && this.props.focusConfig ) {
this.focus();
}
}

onKeyDown = ( event ) => {
Expand All @@ -40,8 +44,7 @@ export default class EnhancedInput extends Component {
event.stopPropagation();
const textBeforeSelection = value.slice( 0, this.input.selectionStart );
const textAfterSelection = value.slice( this.input.selectionEnd );
const selection = value.slice( this.selectionStart, this.selectionEnd );
splitValue( textBeforeSelection, textAfterSelection, selection );
splitValue( textBeforeSelection, textAfterSelection );
} else if (
event.keyCode === 8 &&
this.input.selectionStart === this.input.selectionEnd &&
Expand All @@ -62,9 +65,13 @@ export default class EnhancedInput extends Component {
this.props.onChange( event.target.value );
};

onFocus = () => {
this.props.onFocusChange( { position: this.input.selectionStart } );
};

render() {
// Keeping splitValue to exclude it from props
const ignoredProps = [ 'value', 'splitValue', 'removePrevious', 'moveDown', 'moveUp' ];
const ignoredProps = [ 'value', 'splitValue', 'removePrevious', 'moveDown', 'moveUp', 'focusConfig', 'onFocusChange' ];
const { value } = this.props;
const props = omit( this.props, ignoredProps );

Expand All @@ -87,6 +94,7 @@ export default class EnhancedInput extends Component {
value={ value }
onKeyDown={ this.onKeyDown }
onChange={ this.onChange }
onFocus={ this.onFocus }
/>
</div>
);
Expand Down
29 changes: 10 additions & 19 deletions tinymce-per-block/src/renderers/block/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@ import { getBlock } from 'wp-blocks';
import isEqualShallow from 'is-equal-shallow';

export default class BlockListBlock extends Component {
maybeFocusOut = ( event ) => {
if ( ! this.blockNode ) {
return;
}

if ( ! this.blockNode.contains( event.relatedTarget ) ) {
this.props.onBlur( event );
}
};

setRef = ( blockNode ) => {
this.blockNode = blockNode;
};
Expand All @@ -25,16 +15,12 @@ export default class BlockListBlock extends Component {
this.form = form;
}

focus = ( position ) => {
this.form.focus && this.form.focus( position );
};

merge = ( block, index ) => {
this.form.merge && this.form.merge( block, index );
}

render() {
const { block, isFocused } = this.props;
const { block, isFocused, focusConfig } = this.props;
const blockDefinition = getBlock( block.blockType );
if ( ! blockDefinition ) {
return null;
Expand Down Expand Up @@ -89,10 +75,10 @@ export default class BlockListBlock extends Component {
type: 'mergeWithPrevious'
} );
},
focus( position ) {
focus( config ) {
executeCommand( {
type: 'focus',
position
config
} );
},
moveUp() {
Expand All @@ -112,10 +98,15 @@ export default class BlockListBlock extends Component {
ref={ this.setRef }
tabIndex={ tabIndex }
onFocus={ onFocus }
onBlur={ this.maybeFocusOut }
className={ classes }
>
<Form ref={ this.bindForm } block={ block } { ...state } isFocused={ isFocused } />
<Form
ref={ this.bindForm }
block={ block }
{ ...state }
isFocused={ isFocused }
focusConfig={ focusConfig }
/>
</div>
);
}
Expand Down
Loading

0 comments on commit a11f577

Please sign in to comment.