Skip to content

Commit

Permalink
Merge pull request #2948 from WordPress/fix/1390-title-unselect-blur
Browse files Browse the repository at this point in the history
Title: Unselect title by blur event
  • Loading branch information
aduth authored Oct 20, 2017
2 parents b538874 + 8ef869d commit ee9de2e
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 23 deletions.
53 changes: 41 additions & 12 deletions components/clipboard-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,35 @@
*/
import Clipboard from 'clipboard';
import classnames from 'classnames';
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { findDOMNode, Component } from '@wordpress/element';
import { Component } from '@wordpress/element';

/**
* Internal dependencies
*/
import { Button } from '../';

class ClipboardButton extends Component {
constructor() {
super( ...arguments );

this.bindContainer = this.bindContainer.bind( this );
this.onCopy = this.onCopy.bind( this );
this.getText = this.getText.bind( this );
}

componentDidMount() {
const { text, onCopy = noop } = this.props;
const button = findDOMNode( this.button );
this.clipboard = new Clipboard( button, {
text: () => text,
const { container, getText, onCopy } = this;
const button = container.firstChild;

this.clipboard = new Clipboard( button, {
text: getText,
container,
} );

this.clipboard.on( 'success', onCopy );
}

Expand All @@ -30,17 +40,36 @@ class ClipboardButton extends Component {
delete this.clipboard;
}

bindContainer( container ) {
this.container = container;
}

onCopy( args ) {
// Clearing selection will move focus back to the triggering button,
// ensuring that it is not reset to the body, and further that it is
// kept within the rendered node.
args.clearSelection();

const { onCopy } = this.props;
if ( onCopy ) {
onCopy();
}
}

getText() {
return this.props.text;
}

render() {
const { className, children } = this.props;
const classes = classnames( 'components-clipboard-button', className );

return (
<Button
ref={ ref => this.button = ref }
className={ classes }
>
{ children }
</Button>
<div ref={ this.bindContainer }>
<Button className={ classes }>
{ children }
</Button>
</div>
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion editor/post-permalink/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class PostPermalink extends Component {
this.onCopy = this.onCopy.bind( this );
}

componentWillUnmout() {
componentWillUnmount() {
clearTimeout( this.dismissCopyConfirmation );
}

Expand Down
30 changes: 20 additions & 10 deletions editor/post-title/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/
import { connect } from 'react-redux';
import Textarea from 'react-autosize-textarea';
import clickOutside from 'react-click-outside';
import classnames from 'classnames';

/**
Expand Down Expand Up @@ -32,12 +31,16 @@ class PostTitle extends Component {
constructor() {
super( ...arguments );

this.bindTextarea = this.bindTextarea.bind( this );
this.bindContainer = this.bindNode.bind( this, 'container' );
this.bindTextarea = this.bindNode.bind( this, 'textarea' );
this.onChange = this.onChange.bind( this );
this.onSelect = this.onSelect.bind( this );
this.onUnselect = this.onUnselect.bind( this );
this.onSelectionChange = this.onSelectionChange.bind( this );
this.onKeyDown = this.onKeyDown.bind( this );
this.blurIfOutside = this.blurIfOutside.bind( this );

this.nodes = {};

this.state = {
isSelected: false,
Expand All @@ -52,12 +55,12 @@ class PostTitle extends Component {
document.removeEventListener( 'selectionchange', this.onSelectionChange );
}

bindTextarea( ref ) {
this.textareaContainer = ref;
bindNode( name, node ) {
this.nodes[ name ] = node;
}

onSelectionChange() {
const textarea = this.textareaContainer.textarea;
const textarea = this.nodes.textarea.textarea;
if (
document.activeElement === textarea &&
textarea.selectionStart !== textarea.selectionEnd
Expand All @@ -80,8 +83,10 @@ class PostTitle extends Component {
this.setState( { isSelected: false } );
}

handleClickOutside() {
this.setState( { isSelected: false } );
blurIfOutside( event ) {
if ( ! this.nodes.container.contains( event.relatedTarget ) ) {
this.onUnselect();
}
}

onKeyDown( event ) {
Expand All @@ -97,7 +102,13 @@ class PostTitle extends Component {
const className = classnames( 'editor-post-title', { 'is-selected': isSelected } );

return (
<div className={ className }>
<div
ref={ this.bindContainer }
onFocus={ this.onSelect }
onBlur={ this.blurIfOutside }
className={ className }
tabIndex={ -1 /* Necessary for Firefox to include relatedTarget in blur event */ }
>
{ isSelected && <PostPermalink /> }
<h1>
<Textarea
Expand All @@ -106,7 +117,6 @@ class PostTitle extends Component {
value={ title }
onChange={ this.onChange }
placeholder={ __( 'Add title' ) }
onFocus={ this.onSelect }
onClick={ this.onSelect }
onKeyDown={ this.onKeyDown }
onKeyPress={ this.onUnselect }
Expand All @@ -130,4 +140,4 @@ export default connect(
},
clearSelectedBlock,
}
)( clickOutside( PostTitle ) );
)( PostTitle );

0 comments on commit ee9de2e

Please sign in to comment.