Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post author dropdown: enable search #5921

Closed
wants to merge 10 commits into from
12 changes: 8 additions & 4 deletions components/autocomplete/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,9 @@ export class Autocomplete extends Component {
}

select( option ) {
const { onReplace } = this.props;
const { onReplace, onSelect } = this.props;
const { open, range, query } = this.state;
const { getOptionCompletion } = open || {};

this.reset();

if ( getOptionCompletion ) {
Expand All @@ -258,13 +257,18 @@ export class Autocomplete extends Component {
this.insertCompletion( range, value );
} else if ( 'backcompat' === action ) {
// NOTE: This block should be removed once we no longer support the old completer interface.
const onSelect = value;
const onSelectValue = value;
const deprecatedOptionObject = option.value;
const selectionResult = onSelect( deprecatedOptionObject.value, range, query );
const selectionResult = onSelectValue( deprecatedOptionObject.value, range, query );
if ( selectionResult !== undefined ) {
this.insertCompletion( range, selectionResult );
}
}

// Call the Autocomplete component's onSelect method if available.
if ( onSelect ) {
onSelect( completion );
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions edit-post/components/sidebar/document-sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { __ } from '@wordpress/i18n';
* Internal Dependencies
*/
import PostStatus from '../post-status';
import PostAuthor from '../post-author';
import PostExcerpt from '../post-excerpt';
import PostTaxonomies from '../post-taxonomies';
import FeaturedImage from '../featured-image';
Expand All @@ -28,6 +29,7 @@ const DocumentSidebar = () => (
<SettingsHeader sidebarName={ SIDEBAR_NAME } />
<Panel>
<PostStatus />
<PostAuthor />
<LastRevision />
<PostTaxonomies />
<FeaturedImage />
Expand Down
36 changes: 36 additions & 0 deletions edit-post/components/sidebar/post-author/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* External dependencies
*/
import { get } from 'lodash';

/**
* WordPress dependencies
*/
import { withInstanceId } from '@wordpress/components';
import { compose } from '@wordpress/element';
import { withSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import PostTypeSupportCheck from '../../../../editor/components/post-type-support-check';

export function PostAuthorCheck( { hasAssignAuthorAction, authors, children } ) {
if ( ! hasAssignAuthorAction || authors.length < 1 ) {
return null;
}

return <PostTypeSupportCheck supportKeys="author">{ children }</PostTypeSupportCheck>;
}

export default compose( [
withSelect( ( select ) => {
const post = select( 'core/editor' ).getCurrentPost();
return {
hasAssignAuthorAction: get( post, [ '_links', 'wp:action-assign-author' ], false ),
postType: select( 'core/editor' ).getCurrentPostType(),
authors: select( 'core' ).getAuthors(),
};
} ),
withInstanceId,
] )( PostAuthorCheck );
100 changes: 89 additions & 11 deletions edit-post/components/sidebar/post-author/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,100 @@
/**
* WordPress dependencies
*/
import { PanelRow } from '@wordpress/components';
import { PostAuthor as PostAuthorForm, PostAuthorCheck } from '@wordpress/editor';
import { __ } from '@wordpress/i18n';
import { PanelBody, PanelRow, withInstanceId } from '@wordpress/components';
import { Component, compose } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
import { authorAutocompleter } from '../../../../editor/components/autocompleters';
import RichText from '../../../../editor/components/rich-text';

/**
* Internal dependencies
*/
import PostAuthorCheck from './check';
import './style.scss';
const PANEL_NAME = 'author-panel';

export function PostAuthor() {
return (
<PostAuthorCheck>
<PanelRow>
<PostAuthorForm />
</PanelRow>
</PostAuthorCheck>
);
export class PostAuthor extends Component {
constructor() {
super( ...arguments );
this.onSelect = this.onSelect.bind( this );
this.onFocus = this.onFocus.bind( this );
this.state = {
theAuthor: false,
};
const { postAuthor } = this.props;
wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } )
.then( ( response ) => {
this.setState( { theAuthor: response } );
} );
}

// When an author is selected, set the post author.
onSelect( value ) {
if ( ! value ) {
return;
}
const { onUpdateAuthor } = this.props;
onUpdateAuthor( Number( value.id ) );
}

onFocus( editor ) {
if ( ! editor.dom ) {
return;
}
const range = editor.dom.createRng();
range.selectNodeContents( editor.getBody() );
editor.selection.setRng( range );
}

render() {
const { isOpened, onTogglePanel } = this.props;
const theAuthor = this.state.theAuthor;

/* eslint-disable jsx-a11y/no-onchange */
return (
<PostAuthorCheck>
<PanelBody title={ __( 'Author' ) } opened={ isOpened } onToggle={ onTogglePanel }>
<PanelRow>
<div className="components-form-token-field">
<div className="components-form-token-field__input-container">
<RichText
tagName="p"
className="editor-post-author__select wp-block-paragraph"
value={ theAuthor ? theAuthor.name : '' }
aria-autocomplete="list"
onSelect={ this.onSelect }
onChange={ () => {} }
autocompleters={ [ authorAutocompleter ] }
onFocus={ this.onFocus }
/>
</div>
</div>
</PanelRow>
</PanelBody>
</PostAuthorCheck>
);
/* eslint-enable jsx-a11y/no-onchange */
}
}

export default PostAuthor;
export default compose( [
withSelect( ( select ) => {
return {
postAuthor: select( 'core/editor' ).getEditedPostAttribute( 'author' ),
authors: select( 'core' ).getAuthors(),
isOpened: select( 'core/edit-post' ).isEditorSidebarPanelOpened( PANEL_NAME ),

};
} ),
withDispatch( ( dispatch ) => ( {
onUpdateAuthor( author ) {
dispatch( 'core/editor' ).editPost( { author } );
},
onTogglePanel() {
return dispatch( 'core/edit-post' ).toggleGeneralSidebarEditorPanel( PANEL_NAME );
},
} ) ),
withInstanceId,
] )( PostAuthor );
11 changes: 11 additions & 0 deletions edit-post/components/sidebar/post-author/style.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
.editor-post-author__select {
margin: -5px 0;
border: none;
width: 150px;
padding: 4px;
display: inline-block;
width: auto;
max-width: 100%;
line-height: 24px;
background: inherit;
font-size: 13px;
color: #23282d;
box-shadow: none;
}
2 changes: 0 additions & 2 deletions edit-post/components/sidebar/post-status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import PostVisibility from '../post-visibility';
import PostTrash from '../post-trash';
import PostSchedule from '../post-schedule';
import PostSticky from '../post-sticky';
import PostAuthor from '../post-author';
import PostFormat from '../post-format';
import PostPendingStatus from '../post-pending-status';
import PluginPostStatusInfo from '../plugin-post-status-info';
Expand All @@ -32,7 +31,6 @@ function PostStatus( { isOpened, onTogglePanel } ) {
<PostFormat />
<PostSticky />
<PostPendingStatus />
<PostAuthor />
<PluginPostStatusInfo.Slot />
<PostTrash />
</PanelBody>
Expand Down
37 changes: 37 additions & 0 deletions editor/components/autocompleters/author.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* An author autocompleter.
*
* @type {Completer}
*/
export default {
name: 'users',
className: 'blocks-autocompleters__user',
triggerPrefix: '',
options( search ) {
let payload = '';
if ( search ) {
payload = '?search=' + encodeURIComponent( search );
}
return wp.apiRequest( { path: '/wp/v2/users' + payload } );
},
isDebounced: true,
getOptionKeywords( user ) {
return [ user.slug, user.name ];
},
getOptionLabel( user ) {
return [
<span key="name" className="blocks-autocompleters__user-name">{ user.name }</span>,
];
},
allowNode() {
return true;
},

getOptionCompletion( user ) {
return {
action: 'insert-at-caret',
value: `${ user.name }`,
id: user.id,
};
},
};
1 change: 1 addition & 0 deletions editor/components/autocompleters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ import './style.scss';

export { default as blockAutocompleter } from './block';
export { default as userAutocompleter } from './user';
export { default as authorAutocompleter } from './author';
41 changes: 26 additions & 15 deletions editor/components/post-author/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { __ } from '@wordpress/i18n';
import { withInstanceId } from '@wordpress/components';
import { Component, compose } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
import { authorAutocompleter } from '../../../editor/components/autocompleters';
import RichText from '../../../editor/components/rich-text';

/**
* Internal dependencies
Expand All @@ -14,36 +16,45 @@ import PostAuthorCheck from './check';
export class PostAuthor extends Component {
constructor() {
super( ...arguments );

this.setAuthorId = this.setAuthorId.bind( this );
this.state = {
theAuthor: false,
};
const { postAuthor } = this.props;
wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } )
.then( ( response ) => {
this.setState( { theAuthor: response } );
} );
}

setAuthorId( event ) {
// When an author is selected, set the post author.
setAuthorId( value ) {
if ( ! value ) {
return;
}
const { onUpdateAuthor } = this.props;
const { value } = event.target;
onUpdateAuthor( Number( value ) );
onUpdateAuthor( Number( value.id ) );
}

render() {
const { postAuthor, instanceId, authors } = this.props;
const { instanceId } = this.props;
const selectId = 'post-author-selector-' + instanceId;
const theAuthor = this.state.theAuthor;

// Disable reason: A select with an onchange throws a warning

/* eslint-disable jsx-a11y/no-onchange */
return (
<PostAuthorCheck>
<label htmlFor={ selectId }>{ __( 'Author' ) }</label>
<select
id={ selectId }
value={ postAuthor }
<RichText
tagName="p"
className="editor-post-author__select wp-block-paragraph"
value={ theAuthor ? theAuthor.name : '' }
aria-autocomplete="list"
onChange={ this.setAuthorId }
className="editor-post-author__select"
>
{ authors.map( ( author ) => (
<option key={ author.id } value={ author.id }>{ author.name }</option>
) ) }
</select>
autocompleters={ [ authorAutocompleter ] }
/>

</PostAuthorCheck>
);
/* eslint-enable jsx-a11y/no-onchange */
Expand Down
7 changes: 6 additions & 1 deletion editor/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ export class RichText extends Component {
if ( this.props.setFocusedElement ) {
this.props.setFocusedElement( this.props.instanceId );
}

if ( this.props.onFocus ) {
this.props.onFocus( this.editor );
}
}

/**
Expand Down Expand Up @@ -858,6 +862,7 @@ export class RichText extends Component {
formatters,
autocompleters,
format,
onSelect,
} = this.props;

const ariaProps = { ...pickAriaProps( this.props ), 'aria-multiline': !! MultilineTag };
Expand Down Expand Up @@ -895,7 +900,7 @@ export class RichText extends Component {
{ formatToolbar }
</div>
) }
<Autocomplete onReplace={ this.props.onReplace } completers={ autocompleters }>
<Autocomplete onReplace={ this.props.onReplace } completers={ autocompleters } onSelect={ onSelect }>
{ ( { isExpanded, listBoxId, activeId } ) => (
<Fragment>
<TinyMCE
Expand Down