Skip to content

Commit 4fa584d

Browse files
committed
Utils: Adding the "accept" utility as a replacement for window.confirm
1 parent c85ac20 commit 4fa584d

File tree

8 files changed

+190
-6
lines changed

8 files changed

+190
-6
lines changed

editor/assets/stylesheets/_z-index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ $z-layers: (
1010
'.editor-header': 20,
1111
'.editor-post-visibility__dialog': 30,
1212
'.editor-post-schedule__dialog': 30,
13+
'.utils-accept__backdrop': 100000
1314
);
1415

1516
@function z-index( $key ) {

editor/sidebar/post-visibility/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { find } from 'lodash';
1010
*/
1111
import { __ } from 'i18n';
1212
import { Component } from 'element';
13+
import { accept } from 'utils';
1314

1415
/**
1516
* Internal Dependencies
@@ -52,10 +53,13 @@ class PostVisibility extends Component {
5253
this.setState( { hasPassword: false } );
5354
};
5455
const setPrivate = () => {
55-
if ( window.confirm( __( 'Would you like to privately publish this post now?' ) ) ) { // eslint-disable-line no-alert
56-
onSave( post, { ...edits, status: 'private' }, blocks );
57-
this.setState( { opened: false } );
58-
}
56+
const message = __( 'Would you like to privately publish this post now?' );
57+
accept( message, ( accepted ) => {
58+
if ( accepted ) {
59+
onSave( post, { ...edits, status: 'private' }, blocks );
60+
this.setState( { opened: false } );
61+
}
62+
}, __( 'Yes' ), __( 'No' ) );
5963
};
6064
const setPasswordProtected = () => {
6165
onUpdateVisibility( visibility === 'private' ? 'publish' : status, password || '' );

index.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ function gutenberg_register_scripts() {
192192
wp_register_script(
193193
'wp-utils',
194194
plugins_url( 'utils/build/index.js', __FILE__ ),
195-
array(),
195+
array( 'wp-components', 'wp-i18n' ),
196196
filemtime( plugin_dir_path( __FILE__ ) . 'utils/build/index.js' )
197197
);
198198
wp_register_script(
@@ -253,6 +253,12 @@ function gutenberg_register_scripts() {
253253
);
254254

255255
// Editor Styles.
256+
wp_register_style(
257+
'wp-utils',
258+
plugins_url( 'utils/build/style.css', __FILE__ ),
259+
array(),
260+
filemtime( plugin_dir_path( __FILE__ ) . 'components/build/style.css' )
261+
);
256262
wp_register_style(
257263
'wp-components',
258264
plugins_url( 'components/build/style.css', __FILE__ ),
@@ -548,7 +554,7 @@ function gutenberg_scripts_and_styles( $hook ) {
548554
wp_enqueue_style(
549555
'wp-editor',
550556
plugins_url( 'editor/build/style.css', __FILE__ ),
551-
array( 'wp-components', 'wp-blocks' ),
557+
array( 'wp-components', 'wp-blocks', 'wp-utils' ),
552558
filemtime( plugin_dir_path( __FILE__ ) . 'editor/build/style.css' )
553559
);
554560
}

utils/accept/dialog.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import clickOutside from 'react-click-outside';
5+
6+
/**
7+
* WordPress Dependencies
8+
*/
9+
import { Component } from 'element';
10+
import { Button } from 'components';
11+
import { __ } from 'i18n';
12+
13+
class AcceptDialog extends Component {
14+
handleClickOutside() {
15+
this.props.onClose( 'cancel' );
16+
}
17+
18+
render() {
19+
const { message, onClose, confirmButtonText, cancelButtonText } = this.props;
20+
const accept = () => onClose( 'accept' );
21+
const cancel = () => onClose( 'cancel' );
22+
23+
return (
24+
<div>
25+
<div className="utils-accept__dialog">
26+
<div className="utils-accept__dialog-content">
27+
{ message }
28+
</div>
29+
<div className="utils-accept__dialog-buttons">
30+
<Button onClick={ cancel } className="button">
31+
{ cancelButtonText || __( 'Cancel' ) }
32+
</Button>
33+
<Button isPrimary onClick={ accept }>
34+
{ confirmButtonText || __( 'OK' ) }
35+
</Button>
36+
</div>
37+
</div>
38+
</div>
39+
);
40+
}
41+
}
42+
43+
export default clickOutside( AcceptDialog );

utils/accept/index.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { render, unmountComponentAtNode } from 'react-dom';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import './style.scss';
10+
import AcceptDialog from './dialog';
11+
12+
export default function accept( message, callback, confirmButtonText, cancelButtonText ) {
13+
let wrapper = document.createElement( 'div' );
14+
wrapper.className = 'utils-accept__backdrop';
15+
document.body.appendChild( wrapper );
16+
17+
function onClose( result ) {
18+
if ( wrapper ) {
19+
unmountComponentAtNode( wrapper );
20+
document.body.removeChild( wrapper );
21+
wrapper = null;
22+
}
23+
24+
if ( callback ) {
25+
callback( result === 'accept' );
26+
}
27+
}
28+
29+
render(
30+
<AcceptDialog
31+
message={ message }
32+
onClose={ onClose }
33+
confirmButtonText={ confirmButtonText }
34+
cancelButtonText={ cancelButtonText }
35+
/>,
36+
wrapper
37+
);
38+
}

utils/accept/style.scss

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.utils-accept__dialog {
2+
top: 10px;
3+
bottom: 10px;
4+
width: 400px;
5+
margin: auto;
6+
background: $white;
7+
box-shadow: $shadow-popover;
8+
border: 1px solid $light-gray-500;
9+
}
10+
11+
.utils-accept__dialog-content {
12+
padding: 20px;
13+
}
14+
15+
.utils-accept__dialog-buttons {
16+
text-align: right;
17+
padding: 10px 20px;
18+
border-top: 1px solid $light-gray-500;
19+
20+
.components-button {
21+
margin-left: 10px;
22+
}
23+
}
24+
25+
.utils-accept__backdrop {
26+
align-items: center;
27+
bottom: 0;
28+
left: 0;
29+
right: 0;
30+
top: 0;
31+
display: flex;
32+
justify-content: center;
33+
position: fixed;
34+
z-index: z-index( '.utils-accept__backdrop' );
35+
background-color: rgba( $light-gray-900, 0.8 );
36+
}

utils/accept/test/index.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { expect } from 'chai';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import accept from '../';
10+
11+
describe( '#accept()', () => {
12+
beforeEach( () => {
13+
document.body.innerHTML = '';
14+
} );
15+
16+
it( 'should render a dialog to the document body', () => {
17+
const message = 'Are you sure?';
18+
19+
accept( message, () => {} );
20+
21+
const dialog = document.querySelector( '.utils-accept__dialog-content' );
22+
expect( dialog ).to.be.an.instanceof( window.Element );
23+
expect( dialog.textContent ).to.equal( message );
24+
} );
25+
26+
it( 'should trigger the callback with an accepted prompt', ( done ) => {
27+
accept( 'Are you sure?', ( accepted ) => {
28+
expect( accepted ).to.be.be.true();
29+
done();
30+
} );
31+
32+
document.querySelector( '.components-button.button-primary' ).click();
33+
} );
34+
35+
it( 'should trigger the callback with a denied prompt', ( done ) => {
36+
accept( 'Are you sure?', ( accepted ) => {
37+
expect( accepted ).to.be.be.false();
38+
done();
39+
} );
40+
41+
document.querySelector( '.components-button:not( .button-primary )' ).click();
42+
} );
43+
44+
it( 'should clean up after itself once the prompt is closed', ( done ) => {
45+
accept( 'Are you sure?', () => {
46+
process.nextTick( () => {
47+
expect( document.querySelector( '.utils-accept__dialog' ) ).to.be.null();
48+
49+
done();
50+
} );
51+
} );
52+
53+
document.querySelector( '.components-button.button-primary' ).click();
54+
} );
55+
} );

utils/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import * as keycodes from './keycodes';
22

3+
export { default as accept } from './accept';
34
export { keycodes };

0 commit comments

Comments
 (0)