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

Add an API to add a plugin sidebar (new) #4777

Merged
merged 22 commits into from
Feb 21, 2018
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a69476e
Make it possible for plugins to render a sidebar
IreneStr Jan 31, 2018
f5586c9
Fix sidebar styling
IreneStr Jan 31, 2018
26c088e
Remove unused mobile middleware
IreneStr Jan 31, 2018
d221bd9
Fix editor mode switching
IreneStr Feb 1, 2018
d31b21c
Fix editorMode switch test
IreneStr Feb 1, 2018
b69794b
Fix documentation
IreneStr Feb 1, 2018
1db6a05
Merge branch 'master' into add/api-add-plugin-sidebar-2
IreneStr Feb 6, 2018
3cdf86f
Change `@returns` into `@return`
atimmer Feb 7, 2018
fbf1225
Add storeKey to make the plugins panel connect to the correct store
IreneStr Feb 12, 2018
f30e950
Merge branch 'master' into add/api-add-plugin-sidebar-2
IreneStr Feb 12, 2018
380a125
Rename 'plugins' to 'plugin' in selector
IreneStr Feb 13, 2018
cdfc5a6
Set editor as default activeGeneralSidebar
IreneStr Feb 13, 2018
872ddcc
Unexpose getSidebarSettings
IreneStr Feb 13, 2018
271db7c
Remove duplicate scss and remove renderSidebar function
IreneStr Feb 13, 2018
e116f96
Fix unittests
IreneStr Feb 13, 2018
6bed5f5
Merge branch 'master' into add/api-add-plugin-sidebar-2
IreneStr Feb 13, 2018
2388b60
Fix header height, font and close button
IreneStr Feb 20, 2018
c417b7e
Update index.js
gziolo Feb 21, 2018
0570733
Edit Post: Remove no longer used getPluginSidebar
gziolo Feb 21, 2018
29beb82
Edit Post: Remove no longer used imports from PluginsPanel
gziolo Feb 21, 2018
ab02dff
Edit Post: Update Layout to handle missing plugin properly
gziolo Feb 21, 2018
85d6ff1
Edit Post: Remove obsolete blank line
gziolo Feb 21, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions edit-post/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
registerSidebar,
activateSidebar,
} from './sidebar';
98 changes: 98 additions & 0 deletions edit-post/api/sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* eslint no-console: [ 'error', { allow: [ 'error' ] } ] */

/* External dependencies */
import { isFunction } from 'lodash';

/* Internal dependencies */
import store from '../store';
import { setGeneralSidebarActivePanel, openGeneralSidebar } from '../store/actions';
import { applyFilters } from '@wordpress/hooks';

const sidebars = {};

/**
* Registers a sidebar to the editor.
*
* A button will be shown in the settings menu to open the sidebar. The sidebar
* can be manually opened by calling the `activateSidebar` function.
*
* @param {string} name The name of the sidebar. Should be in
* `[plugin]/[sidebar]` format.
* @param {Object} settings The settings for this sidebar.
* @param {string} settings.title The name to show in the settings menu.
* @param {Function} settings.render The function that renders the sidebar.
*
* @return {Object} The final sidebar settings object.
*/
export function registerSidebar( name, settings ) {
settings = {
name,
...settings,
};

if ( typeof name !== 'string' ) {
console.error(
'Sidebar names must be strings.'
);
return null;
}
if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) {
console.error(
'Sidebar names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-sidebar.'
);
return null;
}
if ( ! settings || ! isFunction( settings.render ) ) {
console.error(
'The "render" property must be specified and must be a valid function.'
);
return null;
}
if ( sidebars[ name ] ) {
console.error(
`Sidebar ${ name } is already registered.`
);
}

if ( ! settings.title ) {
console.error(
`The sidebar ${ name } must have a title.`
);
return null;
}
if ( typeof settings.title !== 'string' ) {
console.error(
'Sidebar titles must be strings.'
);
return null;
}

settings = applyFilters( 'editor.registerSidebar', settings, name );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have the same logic in blocks.registerBlockType. I'm afraid this needs to be further discussed. The thing is that it happens after validation process is done, so you can update all settings however you want and it won't be validated again. It seems like this should happen before the validation begins.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be addressed in a next iteration


return sidebars[ name ] = settings;
}

/**
* Retrieves the sidebar settings object.
*
* @param {string} name The name of the sidebar to retrieve the settings for.
*
* @return {Object} The settings object of the sidebar. Or null if the
* sidebar doesn't exist.
*/
export function getSidebarSettings( name ) {
if ( ! sidebars.hasOwnProperty( name ) ) {
return null;
}
return sidebars[ name ];
}
/**
* Activates the given sidebar.
*
* @param {string} name The name of the sidebar to activate.
* @return {void}
*/
export function activateSidebar( name ) {
store.dispatch( openGeneralSidebar( 'plugin' ) );
store.dispatch( setGeneralSidebarActivePanel( 'plugin', name ) );
}
39 changes: 25 additions & 14 deletions edit-post/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,25 @@ import {
import './style.scss';
import EllipsisMenu from './ellipsis-menu';
import HeaderToolbar from './header-toolbar';
import { isSidebarOpened } from '../../store/selectors';
import { toggleSidebar } from '../../store/actions';
import {
getOpenedGeneralSidebar,
isPublishSidebarOpened,
} from '../../store/selectors';
import {
openGeneralSidebar,
closeGeneralSidebar,
togglePublishSidebar,
} from '../../store/actions';

function Header( {
onToggleDefaultSidebar,
isGeneralSidebarEditorOpen,
onOpenGeneralSidebar,
onCloseGeneralSidebar,
isPublishSidebarOpen,
onTogglePublishSidebar,
isDefaultSidebarOpened,
isPublishSidebarOpened,
} ) {
const toggleGeneralSidebar = isGeneralSidebarEditorOpen ? onCloseGeneralSidebar : onOpenGeneralSidebar;

return (
<div
role="region"
Expand All @@ -37,20 +47,20 @@ function Header( {
tabIndex="-1"
>
<HeaderToolbar />
{ ! isPublishSidebarOpened && (
{ ! isPublishSidebarOpen && (
<div className="edit-post-header__settings">
<PostSavedState />
<PostPreviewButton />
<PostPublishPanelToggle
isOpen={ isPublishSidebarOpened }
isOpen={ isPublishSidebarOpen }
onToggle={ onTogglePublishSidebar }
/>
<IconButton
icon="admin-generic"
onClick={ onToggleDefaultSidebar }
isToggled={ isDefaultSidebarOpened }
onClick={ toggleGeneralSidebar }
isToggled={ isGeneralSidebarEditorOpen }
label={ __( 'Settings' ) }
aria-expanded={ isDefaultSidebarOpened }
aria-expanded={ isGeneralSidebarEditorOpen }
/>
<EllipsisMenu key="ellipsis-menu" />
</div>
Expand All @@ -61,12 +71,13 @@ function Header( {

export default connect(
( state ) => ( {
isDefaultSidebarOpened: isSidebarOpened( state ),
isPublishSidebarOpened: isSidebarOpened( state, 'publish' ),
isGeneralSidebarEditorOpen: getOpenedGeneralSidebar( state ) === 'editor',
isPublishSidebarOpen: isPublishSidebarOpened( state ),
} ),
{
onToggleDefaultSidebar: () => toggleSidebar(),
onTogglePublishSidebar: () => toggleSidebar( 'publish' ),
onOpenGeneralSidebar: () => openGeneralSidebar( 'editor' ),
onCloseGeneralSidebar: closeGeneralSidebar,
onTogglePublishSidebar: togglePublishSidebar,
},
undefined,
{ storeKey: 'edit-post' }
Expand Down
44 changes: 30 additions & 14 deletions edit-post/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,36 @@ import VisualEditor from '../modes/visual-editor';
import EditorModeKeyboardShortcuts from '../modes/keyboard-shortcuts';
import {
getEditorMode,
hasFixedToolbar,
hasOpenSidebar,
isSidebarOpened,
isFeatureActive,
getOpenedGeneralSidebar,
isPublishSidebarOpened,
} from '../../store/selectors';
import { toggleSidebar } from '../../store/actions';
import { closePublishSidebar } from '../../store/actions';
import PluginsPanel from '../../components/plugins-panel/index.js';

function GeneralSidebar( { openedGeneralSidebar } ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be inlined inside the component that is consuming it. If it is going to be reused in other places it should be moved to its own file.

switch ( openedGeneralSidebar ) {
case 'editor':
return <Sidebar />;
case 'plugin':
return <PluginsPanel />;
default:
}
return null;
}

function Layout( {
mode,
layoutHasOpenSidebar,
isDefaultSidebarOpened,
isPublishSidebarOpened,
fixedToolbarActive,
onClosePublishPanel,
publishSidebarOpen,
openedGeneralSidebar,
hasFixedToolbar,
onClosePublishSidebar,
} ) {
const className = classnames( 'edit-post-layout', {
'is-sidebar-opened': layoutHasOpenSidebar,
'has-fixed-toolbar': fixedToolbarActive,
'has-fixed-toolbar': hasFixedToolbar,
} );

return (
Expand All @@ -68,8 +81,11 @@ function Layout( {
<MetaBoxes location="advanced" />
</div>
</div>
{ isDefaultSidebarOpened && <Sidebar /> }
{ isPublishSidebarOpened && <PostPublishPanel onClose={ onClosePublishPanel } /> }
{ publishSidebarOpen && <PostPublishPanel onClose={ onClosePublishSidebar } /> }
{
openedGeneralSidebar !== null && <GeneralSidebar
openedGeneralSidebar={ openedGeneralSidebar } />
}
<Popover.Slot />
</div>
);
Expand All @@ -79,12 +95,12 @@ export default connect(
( state ) => ( {
mode: getEditorMode( state ),
layoutHasOpenSidebar: hasOpenSidebar( state ),
isDefaultSidebarOpened: isSidebarOpened( state ),
isPublishSidebarOpened: isSidebarOpened( state, 'publish' ),
fixedToolbarActive: hasFixedToolbar( state ),
openedGeneralSidebar: getOpenedGeneralSidebar( state ),
publishSidebarOpen: isPublishSidebarOpened( state ),
hasFixedToolbar: isFeatureActive( state, 'fixedToolbar' ),
} ),
{
onClosePublishPanel: () => toggleSidebar( 'publish', false ),
onClosePublishSidebar: closePublishSidebar,
},
undefined,
{ storeKey: 'edit-post' }
Expand Down
33 changes: 11 additions & 22 deletions edit-post/components/modes/visual-editor/block-inspector-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,31 @@ import { IconButton, withSpokenMessages } from '@wordpress/components';
/**
* Internal dependencies
*/
import { getActivePanel, isSidebarOpened } from '../../../store/selectors';
import { toggleSidebar, setActivePanel } from '../../../store/actions';
import { getActiveEditorPanel, isGeneralSidebarPanelOpened } from '../../../store/selectors';
import { openGeneralSidebar } from '../../../store/actions';

export function BlockInspectorButton( {
isDefaultSidebarOpened,
isGeneralSidebarEditorOpened,
onOpenGeneralSidebarEditor,
panel,
toggleDefaultSidebar,
onShowInspector,
onClick = noop,
small = false,
speak,
} ) {
const toggleInspector = () => {
onShowInspector();
if ( ! isDefaultSidebarOpened || panel === 'block' ) {
toggleDefaultSidebar();
}
};

const speakMessage = () => {
if ( ! isDefaultSidebarOpened || ( isDefaultSidebarOpened && panel !== 'block' ) ) {
if ( ! isGeneralSidebarEditorOpened || ( isGeneralSidebarEditorOpened && panel !== 'block' ) ) {
speak( __( 'Additional settings are now available in the Editor advanced settings sidebar' ) );
} else {
speak( __( 'Advanced settings closed' ) );
}
};

const label = ( isDefaultSidebarOpened && panel === 'block' ) ? __( 'Hide Advanced Settings' ) : __( 'Show Advanced Settings' );
const label = ( isGeneralSidebarEditorOpened && panel === 'block' ) ? __( 'Hide Advanced Settings' ) : __( 'Show Advanced Settings' );

return (
<IconButton
className="editor-block-settings-menu__control"
onClick={ flow( toggleInspector, speakMessage, onClick ) }
onClick={ flow( onOpenGeneralSidebarEditor, speakMessage, onClick ) }
icon="admin-generic"
label={ small ? label : undefined }
>
Expand All @@ -56,15 +48,12 @@ export function BlockInspectorButton( {

export default connect(
( state ) => ( {
isDefaultSidebarOpened: isSidebarOpened( state ),
panel: getActivePanel( state ),
isGeneralSidebarEditorOpened: isGeneralSidebarPanelOpened( state, 'editor' ),
panel: getActiveEditorPanel( state ),
} ),
( dispatch ) => ( {
onShowInspector() {
dispatch( setActivePanel( 'block' ) );
},
toggleDefaultSidebar() {
dispatch( toggleSidebar() );
onOpenGeneralSidebarEditor() {
dispatch( openGeneralSidebar( 'editor', 'block' ) );
},
} ),
undefined,
Expand Down
Loading