From 3296a24c2a084e7d2962aa87a2a42a1db755ddfd Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Sun, 22 Apr 2018 20:13:31 -0400 Subject: [PATCH 1/5] author dropdown with autocomplete, take 1 --- blocks/autocompleters/author.js | 33 ++++++++++++++ blocks/autocompleters/index.js | 1 + editor/components/post-author/index.js | 63 ++++++++++++-------------- 3 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 blocks/autocompleters/author.js diff --git a/blocks/autocompleters/author.js b/blocks/autocompleters/author.js new file mode 100644 index 00000000000000..037ce250dc3975 --- /dev/null +++ b/blocks/autocompleters/author.js @@ -0,0 +1,33 @@ +/** +* A user mentions completer. +* +* @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 }, + { user.slug }, + ]; + }, + allowNode() { + return true; + }, + getOptionCompletion( user ) { + return `${ user.name }`; + }, +}; diff --git a/blocks/autocompleters/index.js b/blocks/autocompleters/index.js index e367e83c199f07..ea436add7f9bea 100644 --- a/blocks/autocompleters/index.js +++ b/blocks/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 13217619eaf554..aa3966e332e773 100644 --- a/editor/components/post-author/index.js +++ b/editor/components/post-author/index.js @@ -1,15 +1,17 @@ /** * External dependencies */ -import { get, filter } from 'lodash'; +import { get, filter, throttle, union } from 'lodash'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { withAPIData, withInstanceId } from '@wordpress/components'; +import { withAPIData, withInstanceId, Autocomplete } from '@wordpress/components'; import { Component, compose } from '@wordpress/element'; import { withSelect, withDispatch } from '@wordpress/data'; +import { authorAutocompleter } from '../../../blocks/autocompleters'; +import RichText from '../../../blocks/rich-text'; /** * Internal dependencies @@ -19,32 +21,33 @@ import PostAuthorCheck from './check'; export class PostAuthor extends Component { constructor() { super( ...arguments ); - this.setAuthorId = this.setAuthorId.bind( this ); + this.state = { + theAuthor: false, + }; + const { postAuthor, instanceId } = this.props; + wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } ) + .then( ( response ) => { + console.log( 'two', 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 ) ); } - getAuthors() { - // While User Levels are officially deprecated, the behavior of the - // existing users dropdown on `who=authors` tests `user_level != 0` - // - // See: https://github.com/WordPress/WordPress/blob/a193916/wp-includes/class-wp-user-query.php#L322-L327 - // See: https://codex.wordpress.org/Roles_and_Capabilities#User_Levels - const { users } = this.props; - return filter( users.data, ( user ) => { - return get( user, [ 'capabilities', 'level_1' ], false ); - } ); - } render() { const { postAuthor, instanceId } = this.props; - const authors = this.getAuthors(); const selectId = 'post-author-selector-' + instanceId; + const theAuthor = this.state.theAuthor; + console.log( theAuthor ? theAuthor.name : '' ); // Disable reason: A select with an onchange throws a warning @@ -52,16 +55,15 @@ export class PostAuthor extends Component { return ( - + + ); /* eslint-enable jsx-a11y/no-onchange */ @@ -79,10 +81,5 @@ export default compose( [ dispatch( 'core/editor' ).editPost( { author } ); }, } ) ), - withAPIData( () => { - return { - users: '/wp/v2/users?context=edit&per_page=100', - }; - } ), withInstanceId, ] )( PostAuthor ); From c0811f1e102c5225ddbe68c6549a27e364c67103 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Sun, 20 May 2018 16:54:59 -0400 Subject: [PATCH 2/5] author autocomplete, take 1 --- .../sidebar/document-sidebar/index.js | 3 + .../components/sidebar/post-author/check.js | 36 +++++++ .../components/sidebar/post-author/index.js | 100 ++++++++++++++++-- .../components/sidebar/post-author/style.scss | 11 ++ .../components/sidebar/post-status/index.js | 2 - .../components}/autocompleters/author.js | 10 +- editor/components/post-author/index.js | 4 +- 7 files changed, 150 insertions(+), 16 deletions(-) create mode 100644 edit-post/components/sidebar/post-author/check.js rename {blocks => editor/components}/autocompleters/author.js (81%) diff --git a/edit-post/components/sidebar/document-sidebar/index.js b/edit-post/components/sidebar/document-sidebar/index.js index 9bcd667a00f4a3..f28fa1cf11e976 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'; @@ -18,6 +19,7 @@ import MetaBoxes from '../../meta-boxes'; import SettingsHeader from '../settings-header'; import Sidebar from '../'; + const SIDEBAR_NAME = 'edit-post/document'; const DocumentSidebar = () => ( @@ -28,6 +30,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 00000000000000..821990714a384d --- /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 c61f7e70ec2d56..3854f4ef05e186 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 } from '@wordpress/components'; +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 */ +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.onChange = this.onChange.bind( this ); + this.onBlur = this.onBlur.bind( this ); + this.state = { + theAuthor: false, + }; + const { postAuthor, instanceId } = this.props; + wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } ) + .then( ( response ) => { + console.log( 'two', response ); + this.setState( { theAuthor: response } ); + } ); + } + + // When an author is selected, set the post author. + onChange( value ) { + if ( ! value ) { + return; + } + console.log( 'setAuthorId', value ) + const { onUpdateAuthor } = this.props; + onUpdateAuthor( Number( value.id ) ); + } + + onBlur( e ) { + console.log( 'onBlur', e ); + } + + + render() { + const { postAuthor, instanceId, authors, isOpened, onTogglePanel } = this.props; + const selectId = 'post-author-selector-' + instanceId; + const theAuthor = this.state.theAuthor; + console.log( 'render', theAuthor ? theAuthor.name : '' ); + + + /* eslint-disable jsx-a11y/no-onchange */ + return ( + + + +
+
+ +
+
+
+
+
+ ); + /* 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 a423d651051b82..855e5678ce8d09 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 141795d047b221..1c6a2639e9747b 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/blocks/autocompleters/author.js b/editor/components/autocompleters/author.js similarity index 81% rename from blocks/autocompleters/author.js rename to editor/components/autocompleters/author.js index 037ce250dc3975..929717161bce37 100644 --- a/blocks/autocompleters/author.js +++ b/editor/components/autocompleters/author.js @@ -1,5 +1,5 @@ /** -* A user mentions completer. +* An author autocompleter. * * @type {Completer} */ @@ -27,7 +27,15 @@ export default { allowNode() { return true; }, + onFocus() { + console.log( 'onFocus' ); + }, + onBlur() { + console.log( 'onBlur' ); + }, getOptionCompletion( user ) { + // After selection. + console.log( user ); return `${ user.name }`; }, }; diff --git a/editor/components/post-author/index.js b/editor/components/post-author/index.js index a37f194ae12661..6138ac1695168a 100644 --- a/editor/components/post-author/index.js +++ b/editor/components/post-author/index.js @@ -5,8 +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 '../../../blocks/autocompleters'; -import RichText from '../../../blocks/rich-text'; +import { authorAutocompleter } from '../../../editor/components/autocompleters'; +import RichText from '../../../editor/components/rich-text'; /** * Internal dependencies From bce05aa9510159b75818452e1e752e64bd71930a Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Sun, 20 May 2018 17:56:20 -0400 Subject: [PATCH 3/5] Author autocomplete, working version --- components/autocomplete/index.js | 9 ++++++-- .../components/sidebar/post-author/index.js | 22 ++++++++++--------- editor/components/autocompleters/author.js | 16 +++++--------- editor/components/rich-text/index.js | 3 ++- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/components/autocomplete/index.js b/components/autocomplete/index.js index b08b10899105b3..a9bed98f78918b 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 ) { @@ -265,7 +264,13 @@ export class Autocomplete extends Component { this.insertCompletion( range, selectionResult ); } } + + // Call the Autocomplete component's onSelect method if available. + if ( onSelect ) { + onSelect( completion ); + } } + } reset() { diff --git a/edit-post/components/sidebar/post-author/index.js b/edit-post/components/sidebar/post-author/index.js index 3854f4ef05e186..ca3c774d170525 100644 --- a/edit-post/components/sidebar/post-author/index.js +++ b/edit-post/components/sidebar/post-author/index.js @@ -19,7 +19,7 @@ const PANEL_NAME = 'author-panel'; export class PostAuthor extends Component { constructor() { super( ...arguments ); - this.onChange = this.onChange.bind( this ); + this.onSelect = this.onSelect.bind( this ); this.onBlur = this.onBlur.bind( this ); this.state = { theAuthor: false, @@ -33,7 +33,7 @@ export class PostAuthor extends Component { } // When an author is selected, set the post author. - onChange( value ) { + onSelect( value ) { if ( ! value ) { return; } @@ -42,8 +42,8 @@ export class PostAuthor extends Component { onUpdateAuthor( Number( value.id ) ); } - onBlur( e ) { - console.log( 'onBlur', e ); + onBlur( content ) { + //this.onSelect( content[1] ) } @@ -62,12 +62,14 @@ export class PostAuthor extends Component {
{} } + autocompleters={ [ authorAutocompleter ] } + onBlur={ this.onBlur } />
diff --git a/editor/components/autocompleters/author.js b/editor/components/autocompleters/author.js index 929717161bce37..31fc1126838595 100644 --- a/editor/components/autocompleters/author.js +++ b/editor/components/autocompleters/author.js @@ -21,21 +21,17 @@ export default { getOptionLabel( user ) { return [ { user.name }, - { user.slug }, ]; }, allowNode() { return true; }, - onFocus() { - console.log( 'onFocus' ); - }, - onBlur() { - console.log( 'onBlur' ); - }, + getOptionCompletion( user ) { - // After selection. - console.log( user ); - return `${ user.name }`; + return { + action: 'insert-at-caret', + value: `${ user.name }`, + id: user.id, + }; }, }; diff --git a/editor/components/rich-text/index.js b/editor/components/rich-text/index.js index 256ffa77d67e4e..c103588e06bada 100644 --- a/editor/components/rich-text/index.js +++ b/editor/components/rich-text/index.js @@ -852,6 +852,7 @@ export class RichText extends Component { formatters, autocompleters, format, + onSelect, } = this.props; const ariaProps = { ...pickAriaProps( this.props ), 'aria-multiline': !! MultilineTag }; @@ -889,7 +890,7 @@ export class RichText extends Component { { formatToolbar } ) } - + { ( { isExpanded, listBoxId, activeId } ) => ( Date: Sun, 20 May 2018 22:20:49 -0400 Subject: [PATCH 4/5] select contents on focus --- edit-post/components/sidebar/post-author/index.js | 13 +++++++++---- editor/components/rich-text/index.js | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/edit-post/components/sidebar/post-author/index.js b/edit-post/components/sidebar/post-author/index.js index ca3c774d170525..a827df0fb4a2f5 100644 --- a/edit-post/components/sidebar/post-author/index.js +++ b/edit-post/components/sidebar/post-author/index.js @@ -20,7 +20,7 @@ export class PostAuthor extends Component { constructor() { super( ...arguments ); this.onSelect = this.onSelect.bind( this ); - this.onBlur = this.onBlur.bind( this ); + this.onFocus = this.onFocus.bind( this ); this.state = { theAuthor: false, }; @@ -42,8 +42,13 @@ export class PostAuthor extends Component { onUpdateAuthor( Number( value.id ) ); } - onBlur( content ) { - //this.onSelect( content[1] ) + onFocus( editor ) { + if ( ! editor.dom ) { + return; + } + const range = editor.dom.createRng(); + range.selectNodeContents(editor.getBody()); + editor.selection.setRng(range); } @@ -69,7 +74,7 @@ export class PostAuthor extends Component { onSelect={ this.onSelect } onChange={ () => {} } autocompleters={ [ authorAutocompleter ] } - onBlur={ this.onBlur } + onFocus={ this.onFocus } /> diff --git a/editor/components/rich-text/index.js b/editor/components/rich-text/index.js index c103588e06bada..4818cb14a86242 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 ); + } } /** From 5e097adb6df527702d626a00568e8b2e2d07c908 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Sun, 20 May 2018 22:45:50 -0400 Subject: [PATCH 5/5] fixes for eslint --- components/autocomplete/index.js | 5 ++--- .../sidebar/document-sidebar/index.js | 1 - .../components/sidebar/post-author/index.js | 17 +++++------------ editor/components/post-author/index.js | 19 ++++++++----------- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/components/autocomplete/index.js b/components/autocomplete/index.js index a9bed98f78918b..3263a3893d81ec 100644 --- a/components/autocomplete/index.js +++ b/components/autocomplete/index.js @@ -257,9 +257,9 @@ 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 ); } @@ -270,7 +270,6 @@ export class Autocomplete extends Component { onSelect( completion ); } } - } reset() { diff --git a/edit-post/components/sidebar/document-sidebar/index.js b/edit-post/components/sidebar/document-sidebar/index.js index f28fa1cf11e976..dbe435e5e90889 100644 --- a/edit-post/components/sidebar/document-sidebar/index.js +++ b/edit-post/components/sidebar/document-sidebar/index.js @@ -19,7 +19,6 @@ import MetaBoxes from '../../meta-boxes'; import SettingsHeader from '../settings-header'; import Sidebar from '../'; - const SIDEBAR_NAME = 'edit-post/document'; const DocumentSidebar = () => ( diff --git a/edit-post/components/sidebar/post-author/index.js b/edit-post/components/sidebar/post-author/index.js index a827df0fb4a2f5..30b99b67a8df34 100644 --- a/edit-post/components/sidebar/post-author/index.js +++ b/edit-post/components/sidebar/post-author/index.js @@ -2,8 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody, PanelRow } from '@wordpress/components'; -import { withInstanceId } from '@wordpress/components'; +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'; @@ -24,10 +23,9 @@ export class PostAuthor extends Component { this.state = { theAuthor: false, }; - const { postAuthor, instanceId } = this.props; + const { postAuthor } = this.props; wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } ) .then( ( response ) => { - console.log( 'two', response ); this.setState( { theAuthor: response } ); } ); } @@ -37,7 +35,6 @@ export class PostAuthor extends Component { if ( ! value ) { return; } - console.log( 'setAuthorId', value ) const { onUpdateAuthor } = this.props; onUpdateAuthor( Number( value.id ) ); } @@ -47,17 +44,13 @@ export class PostAuthor extends Component { return; } const range = editor.dom.createRng(); - range.selectNodeContents(editor.getBody()); - editor.selection.setRng(range); + range.selectNodeContents( editor.getBody() ); + editor.selection.setRng( range ); } - render() { - const { postAuthor, instanceId, authors, isOpened, onTogglePanel } = this.props; - const selectId = 'post-author-selector-' + instanceId; + const { isOpened, onTogglePanel } = this.props; const theAuthor = this.state.theAuthor; - console.log( 'render', theAuthor ? theAuthor.name : '' ); - /* eslint-disable jsx-a11y/no-onchange */ return ( diff --git a/editor/components/post-author/index.js b/editor/components/post-author/index.js index 6138ac1695168a..dde79b8e81b8ec 100644 --- a/editor/components/post-author/index.js +++ b/editor/components/post-author/index.js @@ -20,10 +20,9 @@ export class PostAuthor extends Component { this.state = { theAuthor: false, }; - const { postAuthor, instanceId } = this.props; + const { postAuthor } = this.props; wp.apiRequest( { path: '/wp/v2/users/' + postAuthor + '?context=edit' } ) .then( ( response ) => { - console.log( 'two', response ); this.setState( { theAuthor: response } ); } ); } @@ -38,24 +37,22 @@ export class PostAuthor extends Component { } render() { - const { postAuthor, instanceId, authors } = this.props; + const { instanceId } = this.props; const selectId = 'post-author-selector-' + instanceId; const theAuthor = this.state.theAuthor; - console.log( theAuthor ? theAuthor.name : '' ); // Disable reason: A select with an onchange throws a warning - /* eslint-disable jsx-a11y/no-onchange */ return (