Skip to content

Commit

Permalink
Enable post locking in Gutenberg (#4217)
Browse files Browse the repository at this point in the history
* Enable post locking via the heartbeat api, following core

* remove interval change

* Docblock updates

* revert unintended changes

* remove nonce handling

* rename file & setup

* Ensure heartbeat interval is low enough to work for post locking

* Unlock the post when the window is closed or exited.

* Fixes for eslint

* tabs not spaces

* post locking WIP

* modal on load first pass

* Fixes for phpunit

* Enable a Modal showCloseIcon property

* Add a post locked modal, first pass

* Add an “isPostLocked” selector

* Add a locked reducer

* action is ‘lockPost’ and takes a boolean

* fixes for phpunit

* cleanup hearbeat post locking

* Show the post locked modal when the post is locked

* spaces for phpcs

* passed lock & user at initialization

* update inline docs

* pass a unlocking lockNonce to settings if the post is locked

* Lock modal actions, first pass; leverage existing PostPreviewButton

* note previews open in a new tab, unlike classic editor where it happens in the main window

* Add some style

* improve modal string construction, nonce setup, linting fixes

* better setup, fix beforeunload

* complete takeover action logic

* update core data readme

* Complete takeover action, reaction

* alignment for eslint

* Add the lock details to the lockPost dispatch

* Ensure modal header can display an icon when passed its src

* modal icon img styles

* Improve post lock modal, improve all posts url construction

* Add lockedDetails to the lockPost action

* add lockDetails to the locked reducer

* new selector: getLockDetails

* Add avatgar data for existing locks

* dispatch an autosave when the post is taken over

* Fix for phpcs, also smaller gravatar size x2 display

* Add docs for getLockDetails

* improve post locking modal style to match designs

* switch ajaxurl from global to editor settings

* Don’t hide the modal title - display it above the existing content

* import { setupHearthbeatPostLocking } from '@wordpress/editor';

* complete move of setupHearthbeatPostLocking to editor package

* showCloseIcon -> isDismissable

* post lock modal - switch to withSelect

* Revert "post lock modal - switch to withSelect"

This reverts commit 2c1fcf0.

* modal cleanup and withSelect rework

* improve avatar image alignment

* Use a href links instead of action handlers for buttons

* no closing

* Try moving to editor package

* Revert "Try moving to editor package"

This reverts commit ca9fa60.

* remove inner buttons, not needed

* clean up modal imports

* improve heartbeat post locking setup

* docs update

* more docs cleanup

* Fixes for phpcs

* Remove specific Modal Header Icon

* Move the PostLockedModal to the editor module

* Styles cleaning for the post locked modal

* Post Lock: Clarifying the lock state

* Move post locking setup to the post locked modal component

* Remove unnecessary exposed function

* cleanup after merge

* fixes for phpcs

* docs cleanup

* cleanup after merge

* Adjust the modal display with latest language, formatting and post type

* spacing

* restore heartbeat settings after merge

* Add e2e tests for the post locking modal

* Revert "Add e2e tests for the post locking modal"

This reverts commit 1f53d95.

* Fix i18n of the post lock modal message and tweak docs

* Try fixing the release post issue

* include and use an unclock nonce

* Remove the heartbeat interval tweak

* Code style and documentation tweaks

* i18n: Drop untranslatable `postType` interpolation.

* i18n: Separate strings for more versatile translation
  • Loading branch information
Adam Silverstein authored and youknowriad committed Oct 4, 2018
1 parent 590cf72 commit 37bd1e6
Show file tree
Hide file tree
Showing 17 changed files with 515 additions and 17 deletions.
74 changes: 74 additions & 0 deletions docs/data/data-core-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,24 @@ unsaved status values.

Whether the post has been published.

### isEditedPostDateFloating

Returns whether the current post should be considered to have a "floating"
date (i.e. that it would publish "Immediately" rather than at a set time).

Unlike in the PHP backend, the REST API returns a full date string for posts
where the 0000-00-00T00:00:00 placeholder is present in the database. To
infer that a post is set to publish "Immediately" we check whether the date
and modified date are the same.

*Parameters*

* state: Editor state.

*Returns*

Whether the edited post has a floating date value.

### getBlockDependantsCacheBust

Returns a new reference when the inner blocks of a given block client ID
Expand Down Expand Up @@ -1255,6 +1273,54 @@ Returns the editor settings.

The editor settings object

### isPostLocked

Returns whether the post is locked.

*Parameters*

* state: Global application state.

*Returns*

Is locked.

### isPostLockTakeover

Returns whether the edition of the post has been taken over.

*Parameters*

* state: Global application state.

*Returns*

Is post lock takeover.

### getPostLockUser

Returns details about the post lock user.

*Parameters*

* state: Global application state.

*Returns*

A user object.

### getActivePostLock

Returns the active post lock.

*Parameters*

* state: Global application state.

*Returns*

The lock object.

### canUserUseUnfilteredHTML

Returns whether or not the user has the unfiltered_html capability.
Expand Down Expand Up @@ -1568,6 +1634,14 @@ Returns an action object used to remove a notice.

* id: The notice id.

### updatePostLock

Returns an action object used to lock the editor.

*Parameters*

* lock: Details about the post lock status, user, and nonce.

### fetchReusableBlocks

Returns an action object used to fetch a single reusable block or all
Expand Down
4 changes: 3 additions & 1 deletion edit-post/assets/stylesheets/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ body.gutenberg-editor-page {
}
}

.gutenberg {
.gutenberg,
// The modals are shown outside the .gutenberg wrapper, they need these styles
.components-modal__frame {
box-sizing: border-box;

*,
Expand Down
4 changes: 2 additions & 2 deletions edit-post/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
* WordPress dependencies
*/
import { withSelect } from '@wordpress/data';
import { EditorProvider, ErrorBoundary } from '@wordpress/editor';
import { EditorProvider, ErrorBoundary, PostLockedModal } from '@wordpress/editor';
import { StrictMode } from '@wordpress/element';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -39,6 +38,7 @@ function Editor( {
<ErrorBoundary onError={ onError }>
<Layout />
</ErrorBoundary>
<PostLockedModal />
</EditorProvider>
</StrictMode>
);
Expand Down
56 changes: 55 additions & 1 deletion lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ function gutenberg_register_scripts_and_styles() {
'wp-editor',
gutenberg_url( 'build/editor/index.js' ),
array(
'jquery',
'lodash',
'tinymce-latest-lists',
'wp-a11y',
Expand Down Expand Up @@ -1460,6 +1461,52 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
}
}

// Lock settings.
$user_id = wp_check_post_lock( $post->ID );
if ( $user_id ) {
/**
* Filters whether to show the post locked dialog.
*
* Returning a falsey value to the filter will short-circuit displaying the dialog.
*
* @since 3.6.0
*
* @param bool $display Whether to display the dialog. Default true.
* @param WP_Post $post Post object.
* @param WP_User|bool $user The user id currently editing the post.
*/
if ( apply_filters( 'show_post_locked_dialog', true, $post, $user_id ) ) {
$locked = true;
}

$user_details = null;
if ( $locked ) {
$user = get_userdata( $user_id );
$user_details = array(
'name' => $user->display_name,
);
$avatar = get_avatar( $user_id, 64 );
if ( $avatar ) {
if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) ) {
$user_details['avatar'] = $matches[1];
}
}
}

$lock_details = array(
'isLocked' => $locked,
'user' => $user_details,
);
} else {

// Lock the post.
$active_post_lock = wp_set_post_lock( $post->ID );
$lock_details = array(
'isLocked' => false,
'activePostLock' => esc_attr( implode( ':', $active_post_lock ) ),
);
}

$editor_settings = array(
'alignWide' => $align_wide || ! empty( $gutenberg_theme_support[0]['wide-images'] ), // Backcompat. Use `align-wide` outside of `gutenberg` array.
'availableTemplates' => $available_templates,
Expand All @@ -1472,7 +1519,14 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
'autosaveInterval' => 10,
'maxUploadFileSize' => $max_upload_size,
'allowedMimeTypes' => get_allowed_mime_types(),
'styles' => $styles,
'postLock' => $lock_details,

// Ideally, we'd remove this and rely on a REST API endpoint.
'postLockUtils' => array(
'nonce' => wp_create_nonce( 'lock-post_' . $post->ID ),
'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
),
);

$post_autosave = get_autosave_newer_than_post_save( $post );
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 13 additions & 5 deletions packages/components/src/modal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const MyModal = withState( {
<Button isDefault onClick={ () => setState( { isOpen: false } ) }>
My custom close button
</Button>
</Modal>
</Modal>
: null }
</div>
) );
Expand Down Expand Up @@ -77,23 +77,31 @@ If this property is added, it will be added to the modal content `div` as `aria-

If this property is true, it will focus the first tabbable element rendered in the modal.

- Type: `bool`
- Type: `boolean`
- Required: No
- Default: true

### shouldCloseOnEsc

If this property is added, it will determine whether the modal requests to close when the escape key is pressed.
If this property is added, it will determine whether the modal requests to close when the escape key is pressed.

- Type: `bool`
- Type: `boolean`
- Required: No
- Default: true

### shouldCloseOnClickOutside

If this property is added, it will determine whether the modal requests to close when a mouse click occurs outside of the modal content.

- Type: `bool`
- Type: `boolean`
- Required: No
- Default: true

### isDismissable

If this property is set to false, the modal will not display a close icon and cannot be dismissed.

- Type: `boolean`
- Required: No
- Default: true

Expand Down
14 changes: 8 additions & 6 deletions packages/components/src/modal/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { __ } from '@wordpress/i18n';
*/
import IconButton from '../icon-button';

const ModalHeader = ( { icon, title, onClose, closeLabel, headingId } ) => {
const ModalHeader = ( { icon, title, onClose, closeLabel, headingId, isDismissable } ) => {
const label = closeLabel ? closeLabel : __( 'Close dialog' );

return (
Expand All @@ -28,11 +28,13 @@ const ModalHeader = ( { icon, title, onClose, closeLabel, headingId } ) => {
</h1>
}
</div>
<IconButton
onClick={ onClose }
icon="no-alt"
label={ label }
/>
{ isDismissable &&
<IconButton
onClick={ onClose }
icon="no-alt"
label={ label }
/>
}
</div>
);
};
Expand Down
6 changes: 5 additions & 1 deletion packages/components/src/modal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class Modal extends Component {
children,
aria,
instanceId,
isDismissable,
...otherProps
} = this.props;

Expand Down Expand Up @@ -154,10 +155,12 @@ class Modal extends Component {
{ ...otherProps } >
<ModalHeader
closeLabel={ closeButtonLabel }
isDismissable={ isDismissable }
onClose={ onRequestClose }
title={ title }
headingId={ headingId }
icon={ icon } />
icon={ icon }
/>
<div
className={ 'components-modal__content' }>
{ children }
Expand All @@ -178,6 +181,7 @@ Modal.defaultProps = {
focusOnMount: true,
shouldCloseOnEsc: true,
shouldCloseOnClickOutside: true,
isDismissable: true,
/* accessibility */
aria: {
labelledby: null,
Expand Down
1 change: 1 addition & 0 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"classnames": "^2.2.5",
"dom-scroll-into-view": "^1.2.1",
"inherits": "^2.0.3",
"jquery": "^3.3.1",
"lodash": "^4.17.10",
"memize": "^1.0.5",
"react-autosize-textarea": "^3.0.2",
Expand Down
1 change: 1 addition & 0 deletions packages/editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export { default as PostFormat } from './post-format';
export { default as PostFormatCheck } from './post-format/check';
export { default as PostLastRevision } from './post-last-revision';
export { default as PostLastRevisionCheck } from './post-last-revision/check';
export { default as PostLockedModal } from './post-locked-modal';
export { default as PostPendingStatus } from './post-pending-status';
export { default as PostPendingStatusCheck } from './post-pending-status/check';
export { default as PostPingbacks } from './post-pingbacks';
Expand Down
Loading

0 comments on commit 37bd1e6

Please sign in to comment.