diff --git a/components/autocomplete/index.js b/components/autocomplete/index.js index b08b10899105b..3263a3893d81e 100644 --- a/components/autocomplete/index.js +++ b/components/autocomplete/index.js @@ -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 ) { @@ -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 ); + } } } diff --git a/edit-post/components/sidebar/document-sidebar/index.js b/edit-post/components/sidebar/document-sidebar/index.js index 9bcd667a00f4a..dbe435e5e9088 100644 --- a/edit-post/components/sidebar/document-sidebar/index.js +++ b/edit-post/components/sidebar/document-sidebar/index.js @@ -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'; @@ -28,6 +29,7 @@ const DocumentSidebar = () => ( + diff --git a/edit-post/components/sidebar/post-author/check.js b/edit-post/components/sidebar/post-author/check.js new file mode 100644 index 0000000000000..821990714a384 --- /dev/null +++ b/edit-post/components/sidebar/post-author/check.js @@ -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 { children }; +} + +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 ); diff --git a/edit-post/components/sidebar/post-author/index.js b/edit-post/components/sidebar/post-author/index.js index c61f7e70ec2d5..30b99b67a8df3 100644 --- a/edit-post/components/sidebar/post-author/index.js +++ b/edit-post/components/sidebar/post-author/index.js @@ -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 ( - - - - - - ); +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 ( + + + +
+
+ {} } + autocompleters={ [ authorAutocompleter ] } + onFocus={ this.onFocus } + /> +
+
+
+
+
+ ); + /* 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 ); diff --git a/edit-post/components/sidebar/post-author/style.scss b/edit-post/components/sidebar/post-author/style.scss index a423d651051b8..855e5678ce8d0 100644 --- a/edit-post/components/sidebar/post-author/style.scss +++ b/edit-post/components/sidebar/post-author/style.scss @@ -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; } diff --git a/edit-post/components/sidebar/post-status/index.js b/edit-post/components/sidebar/post-status/index.js index 141795d047b22..1c6a2639e9747 100644 --- a/edit-post/components/sidebar/post-status/index.js +++ b/edit-post/components/sidebar/post-status/index.js @@ -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'; @@ -32,7 +31,6 @@ function PostStatus( { isOpened, onTogglePanel } ) { - diff --git a/editor/components/autocompleters/author.js b/editor/components/autocompleters/author.js new file mode 100644 index 0000000000000..31fc112683859 --- /dev/null +++ b/editor/components/autocompleters/author.js @@ -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 [ + { user.name }, + ]; + }, + allowNode() { + return true; + }, + + getOptionCompletion( user ) { + return { + action: 'insert-at-caret', + value: `${ user.name }`, + id: user.id, + }; + }, +}; diff --git a/editor/components/autocompleters/index.js b/editor/components/autocompleters/index.js index e367e83c199f0..ea436add7f9be 100644 --- a/editor/components/autocompleters/index.js +++ b/editor/components/autocompleters/index.js @@ -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'; diff --git a/editor/components/post-author/index.js b/editor/components/post-author/index.js index 46e3b4b3fe220..dde79b8e81b8e 100644 --- a/editor/components/post-author/index.js +++ b/editor/components/post-author/index.js @@ -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 @@ -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 ( - + autocompleters={ [ authorAutocompleter ] } + /> + ); /* eslint-enable jsx-a11y/no-onchange */ diff --git a/editor/components/rich-text/index.js b/editor/components/rich-text/index.js index d1d54bf312d3e..30546fc98d9b9 100644 --- a/editor/components/rich-text/index.js +++ b/editor/components/rich-text/index.js @@ -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 ); + } } /** @@ -858,6 +862,7 @@ export class RichText extends Component { formatters, autocompleters, format, + onSelect, } = this.props; const ariaProps = { ...pickAriaProps( this.props ), 'aria-multiline': !! MultilineTag }; @@ -895,7 +900,7 @@ export class RichText extends Component { { formatToolbar } ) } - + { ( { isExpanded, listBoxId, activeId } ) => (