diff --git a/blocks/editable/format-toolbar/index.js b/blocks/editable/format-toolbar/index.js index f083ba449c1c5f..3397ca7da36b3b 100644 --- a/blocks/editable/format-toolbar/index.js +++ b/blocks/editable/format-toolbar/index.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { isUndefined } from 'lodash'; - /** * WordPress dependencies */ @@ -41,28 +36,28 @@ const FORMATTING_CONTROLS = [ const DEFAULT_CONTROLS = [ 'bold', 'italic', 'strikethrough', 'link' ]; class FormatToolbar extends Component { - constructor( props ) { + constructor() { super( ...arguments ); + this.state = { - linkValue: props.formats.link ? props.formats.link.value : '', + isAddingLink: false, isEditingLink: false, + newLinkValue: '', }; + this.addLink = this.addLink.bind( this ); this.editLink = this.editLink.bind( this ); this.dropLink = this.dropLink.bind( this ); this.submitLink = this.submitLink.bind( this ); - this.updateLinkValue = this.updateLinkValue.bind( this ); this.onKeyDown = this.onKeyDown.bind( this ); + this.onChangeLinkValue = this.onChangeLinkValue.bind( this ); } componentDidMount() { document.addEventListener( 'keydown', this.onKeyDown ); } - componentWillUnmout() { - if ( this.editTimeout ) { - clearTimeout( this.editTimeout ); - } + componentWillUnmount() { document.removeEventListener( 'keydown', this.onKeyDown ); } @@ -76,21 +71,19 @@ class FormatToolbar extends Component { } componentWillReceiveProps( nextProps ) { - // Update the link value if the focused link node changes - if ( - isUndefined( nextProps.formats.link ) !== isUndefined( this.props.formats.link ) || - ( - nextProps.formats.link && this.props.formats.link && - nextProps.formats.link.node !== this.props.formats.link.node - ) - ) { + if ( this.props.selectedNodeId !== nextProps.selectedNodeId ) { this.setState( { - linkValue: nextProps.formats.link ? nextProps.formats.link.value : '', + isAddingLink: false, isEditingLink: false, + newLinkValue: '', } ); } } + onChangeLinkValue( value ) { + this.setState( { newLinkValue: value } ); + } + toggleFormat( format ) { return () => { this.props.onChange( { @@ -100,45 +93,30 @@ class FormatToolbar extends Component { } addLink() { - if ( ! this.props.formats.link ) { - this.props.onChange( { link: { value: '' } } ); - - // Debounce the call to avoid the reset in willReceiveProps - this.editTimeout = setTimeout( () => this.setState( { isEditingLink: true } ) ); - } + this.setState( { isEditingLink: false, isAddingLink: true, newLinkValue: '' } ); } dropLink() { this.props.onChange( { link: undefined } ); + this.setState( { isEditingLink: false, isAddingLink: false, newLinkValue: '' } ); } editLink( event ) { event.preventDefault(); - this.setState( { - isEditingLink: true, - } ); + this.setState( { isEditingLink: false, isAddingLink: true, newLinkValue: this.props.formats.link.value } ); } submitLink( event ) { event.preventDefault(); - this.props.onChange( { link: { value: this.state.linkValue } } ); - this.setState( { - isEditingLink: false, - } ); - if ( - this.props.formats.link.value === '' && - !! this.state.linkValue.length - ) { + this.props.onChange( { link: { value: this.state.newLinkValue } } ); + if ( this.state.isAddingLink ) { this.props.speak( __( 'Link inserted.' ), 'assertive' ); } } - updateLinkValue( linkValue ) { - this.setState( { linkValue } ); - } - render() { const { formats, focusPosition, enabledControls = DEFAULT_CONTROLS } = this.props; + const { isAddingLink, isEditingLink, newLinkValue } = this.state; const linkStyle = focusPosition ? { position: 'absolute', ...focusPosition } : null; @@ -156,7 +134,7 @@ class FormatToolbar extends Component { icon: 'admin-links', title: __( 'Link' ), onClick: this.addLink, - isActive: !! formats.link, + isActive: isAddingLink || !! formats.link, } ); } @@ -164,25 +142,25 @@ class FormatToolbar extends Component {
- { !! formats.link && this.state.isEditingLink && + { ( isAddingLink || isEditingLink ) &&
- + } - { !! formats.link && ! this.state.isEditingLink && + { !! formats.link && ! isAddingLink && ! isEditingLink &&
- { this.state.linkValue && decodeURI( this.state.linkValue ) } + { formats.link.value && decodeURI( formats.link.value ) } diff --git a/blocks/editable/index.js b/blocks/editable/index.js index b46aa4d1efc418..1c97d23d98d9bb 100644 --- a/blocks/editable/index.js +++ b/blocks/editable/index.js @@ -83,8 +83,8 @@ export default class Editable extends Component { this.state = { formats: {}, - bookmark: null, empty: ! value || ! value.length, + selectedNodeId: 0, }; } @@ -214,8 +214,9 @@ export default class Editable extends Component { this.props.onChange( this.savedContent ); } - getRelativePosition( node ) { - const position = node.getBoundingClientRect(); + getFocusPosition() { + const range = this.editor.selection.getRng(); + const position = range.getBoundingClientRect(); // Find the parent "relative" positioned container const container = this.props.inlineToolbar @@ -415,7 +416,7 @@ export default class Editable extends Component { ); } - onNodeChange( { element, parents } ) { + onNodeChange( { parents } ) { const formats = {}; const link = find( parents, ( node ) => node.nodeName.toLowerCase() === 'a' ); if ( link ) { @@ -424,9 +425,8 @@ export default class Editable extends Component { const activeFormats = this.editor.formatter.matchAll( [ 'bold', 'italic', 'strikethrough' ] ); activeFormats.forEach( ( activeFormat ) => formats[ activeFormat ] = true ); - const focusPosition = this.getRelativePosition( element ); - const bookmark = this.editor.selection.getBookmark( 2, true ); - this.setState( { bookmark, formats, focusPosition } ); + const focusPosition = this.getFocusPosition(); + this.setState( { formats, focusPosition, selectedNodeId: this.state.selectedNodeId + 1 } ); } updateContent() { @@ -497,28 +497,33 @@ export default class Editable extends Component { return !! this.state.formats[ format ]; } + removeFormat( format ) { + this.editor.focus(); + this.editor.formatter.remove( format ); + } + applyFormat( format, args, node ) { + this.editor.focus(); + this.editor.formatter.apply( format, args, node ); + } + changeFormats( formats ) { forEach( formats, ( formatValue, format ) => { if ( format === 'link' ) { - if ( this.state.bookmark ) { - this.editor.selection.moveToBookmark( this.state.bookmark ); - } - if ( formatValue !== undefined ) { const anchor = this.editor.dom.getParent( this.editor.selection.getNode(), 'a' ); if ( ! anchor ) { - this.editor.formatter.remove( 'link' ); + this.removeFormat( 'link' ); } - this.editor.formatter.apply( 'link', { href: formatValue.value }, anchor ); + this.applyFormat( 'link', { href: formatValue.value }, anchor ); } else { this.editor.execCommand( 'Unlink' ); } } else { const isActive = this.isFormatActive( format ); if ( isActive && ! formatValue ) { - this.editor.formatter.remove( format ); + this.removeFormat( format ); } else if ( ! isActive && formatValue ) { - this.editor.formatter.apply( format ); + this.applyFormat( format ); } } } ); @@ -552,6 +557,7 @@ export default class Editable extends Component { const formatToolbar = (