Skip to content
This repository has been archived by the owner on Nov 6, 2022. It is now read-only.

[WIP] React refactoring of the 'Edit Block' UI #478

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4a583f2
Begin the proof of concept for the refactoring
kienstra Nov 24, 2019
dae00a8
At least for now, delete PHP saving of Block Properties meta box
kienstra Nov 24, 2019
558fdf7
Port PHP rendering to React, mainly copying
kienstra Nov 24, 2019
f85c315
Render basic field rows from the post content
kienstra Nov 24, 2019
8c6212a
Correct DocBlocks in FieldRow
kienstra Nov 24, 2019
52fd0b3
Merge in develop, resolve conflicts
kienstra Dec 17, 2019
32aa1d9
Add a basic JS unit test setup, modeled after AMP plugin
kienstra Dec 17, 2019
a0c8510
Attempt to fix failed Travis build
kienstra Dec 17, 2019
3486c27
Move comment to the relevant file, do npm run lint:js:fix
kienstra Dec 17, 2019
95384cf
Restructure js files into js/src
kienstra Dec 21, 2019
4d667fd
Add the build/ directory to the ignored test paths
kienstra Dec 22, 2019
8bdaf09
Rename function to getBlockLabAttributes, add unit test
kienstra Dec 22, 2019
a947395
Remove .gitkeep, as the directory isn't empty anymore
kienstra Dec 22, 2019
4e7ef28
Add a Jest unit test for getSimplifiedFields()
kienstra Dec 22, 2019
84755bb
Add a unit test for getBlockLabAttributes()
kienstra Dec 26, 2019
ce9c437
Add a unit test for registerBlocks()
kienstra Dec 27, 2019
89b15e0
Add more unit tests for registerBlocks()
kienstra Dec 27, 2019
1648af2
Use the singular for no block
kienstra Dec 27, 2019
422f024
Apply Rob's HTML and CSS for the new UI
kienstra Dec 27, 2019
8350ee6
Add a function to save a new field value
kienstra Dec 30, 2019
5b8a702
Fix an issue with saving fields
kienstra Dec 30, 2019
4099e6f
Address an issue where the rich text editor wasn't disabled
kienstra Dec 30, 2019
9ef2653
Address an issue where the rich text editor wasn't disabled
kienstra Dec 30, 2019
ce65b45
Port the slugify function from the previous JS file
kienstra Dec 30, 2019
6da5177
Add a function to save the block
kienstra Dec 31, 2019
b540f7b
Add a function to get a new field's name
kienstra Dec 31, 2019
5b82bc5
Add a function to remove the slug format
kienstra Dec 31, 2019
34988cd
Add helper functions to an index.js file
kienstra Dec 31, 2019
3f12879
Allow toggling the field editing area open and closed
kienstra Dec 31, 2019
4f36644
Merge in develop, resolve conflicts
kienstra Jan 14, 2020
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
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
js/editor.blocks.js
js/scripts.js
js/admin.edit-block.js
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@ coverage/html/

# Builds
js/editor.blocks.js
js/scripts.js
js/admin.edit-block.js
css/blocks.editor.css
package/
5 changes: 5 additions & 0 deletions css/admin.block-post.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* Hide the main block editing area, as that does not apply to this. */
.post-type-block_lab .editor-block-list__layout {
display: none;
}

#minor-publishing-actions,
#misc-publishing-actions #visibility,
#misc-publishing-actions .curtime {
Expand Down
94 changes: 94 additions & 0 deletions js/src/components/block-lab-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* WordPress dependencies
*/
const { blocks } = wp;
const { Button } = wp.components;
const { compose } = wp.compose;
const { withDispatch, withSelect } = wp.data;
const { Component } = wp.element;
const { __ } = wp.i18n;

/**
* Internal dependencies
*/
import { getBlockFromContent } from '../helpers';
import { FieldRow } from '.';

/**
* The Block Lab field editor.
*/
class BlockLabEditor extends Component {
/**
* Renders the editor.
*
* @return {Function} The rendered component.
*/
render() {
const { content } = this.props;
const parsedBlock = getBlockFromContent( content );
const { fields } = parsedBlock;

return (
<div>
<div className="block-fields-list">
<table className="widefat">
<thead>
<tr>
<th className="block-fields-sort"></th>
<th className="block-fields-label">
{ __( 'Field Label', 'block-lab' ) }
</th>
<th className="block-fields-name">
{ __( 'Field Name', 'block-lab' ) }
</th>
<th className="block-fields-control">
{ __( 'Field Type', 'block-lab' ) }
</th>
</tr>
</thead>
<tbody>
<tr>
<td colSpan="4">
<div className="block-fields-rows">
<p className="block-no-fields">
{ __( 'Click Add Field below to add your first field.', 'block-lab' ) }
</p>
{
!! fields && Object.values( fields ).map( ( field, index ) => {
return <FieldRow field={ field } uid={ index } key={ `field-row-${ index }` } />;
} )
}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div className="block-fields-actions-add-field">
<Button type="button" aria-label="Add Field" className="block-fields-action" id="block-add-field">
<span className="dashicons dashicons-plus"></span>
{ __( 'Add Field', 'block-lab' ) }
</Button>
</div>
</div>
);
}
}

export default compose( [
withSelect( ( select ) => {
return {
content: select( 'core/editor' ).getEditedPostContent(),
};
} ),
withDispatch( ( dispatch ) => {
const store = dispatch( 'core/editor' );

return {
onChange( content ) {
store.editPost( { content } );
store.resetEditorBlocks( blocks.parse( content ) );
},
};
} ),
] )( BlockLabEditor );
180 changes: 180 additions & 0 deletions js/src/components/field-row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* WordPress dependencies
*/
const { Button, TextControl } = wp.components;
const { Component } = wp.element;
const { __ } = wp.i18n;

/**
* The Block Lab field editor.
*/
export default class FieldRow extends Component {
/**
* Renders the editor.
*
* @return {Function} The rendered component.
*/
render() {
const { field, uid } = this.props;
const isFieldDisabled = false;

return (
<div className="block-fields-row" data-uid={ uid }>
<div className="block-fields-row-columns">
<div className="block-fields-sort">
<span className="block-fields-sort-handle"></span>
</div>
<div className="block-fields-label">
<Button className="row-title" id={ `block-fields-label_${ uid }` }>
{ field.label }
</Button>
<div className="block-fields-actions">
<Button className="block-fields-actions-edit">
{ __( 'Edit', 'block-lab' ) }
</Button>
<Button className="block-fields-actions-duplicate">
{ __( 'Duplicate', 'block-lab' ) }
</Button>
<Button className="block-fields-actions-delete">
{ __( 'Delete', 'block-lab' ) }
</Button>
</div>
</div>
<div className="block-fields-name" id={ `block-fields-name_${ uid }` }>
<code id={ `block-fields-name-code_${ uid }` }>{ field.name }</code>
</div>
<div className="block-fields-control" id={ `block-fields-control_${ uid }` }>
{
/* <?php
@todo: reimpliment this in JS.
if ( ! isFieldDisabled && isset( $this->controls[ $field->control ] ) ) :
echo esc_html( $this->controls[ $field->control ]->label );
else :
<span className="dashicons dashicons-warning"></span>
<span className="pro-required">

sprintf(
__( 'This <code>%1$s</code> field requires an active <a href="%2$s">pro license</a>.', 'block-lab' ),
field.control,
'https://example.com'
)

</span>
endif;
*/
}
</div>
</div>
<div className="block-fields-edit">
<table className="widefat">
<tr className="block-fields-edit-label">
<td className="spacer"></td>
<th scope="row">
<label htmlFor={ `block-fields-edit-label-input_${ uid } ` }>
{ __( 'Field Label', 'block-lab' ) }
</label>
<p className="description">
{ __( 'A label describing your block\'s custom field.', 'block-lab' ) }
</p>
</th>
<td>
<TextControl
type="text"
id={ `block-fields-edit-label-input_${ uid }` }
className="regular-text"
value={ field.label }
data-sync={ `block-fields-label_${ uid }` }
readOnly={ isFieldDisabled }
/>
</td>
</tr>
<tr className="block-fields-edit-name">
<td className="spacer"></td>
<th scope="row">
<label id={ `block-fields-edit-name-${ uid }` } htmlFor={ `block-fields-edit-name-input_${ uid }` }>
{ __( 'Field Name', 'block-lab' ) }
</label>
<p className="description">
{ __( 'Single word, no spaces.', 'block-lab' ) }
</p>
</th>
<td>
<TextControl
id={ `block-fields-edit-name-input_${ uid }` }
className="regular-text"
value={ field.name }
data-sync="block-fields-name-code"
readOnly={ isFieldDisabled }
/>
</td>
</tr>
<tr className="block-fields-edit-control">
<td className="spacer"></td>
<th scope="row">
<label htmlFor={ `block-fields-edit-control-input_${ uid }` }>
{ __( 'Field Type', 'block-lab' ) }
</label>
</th>
<td>
<select
id={ `block-fields-edit-control-input_${ uid }` }
data-sync={ `block-fields-control_${ uid }` }
disabled={ isFieldDisabled }
>
{
/*
@todo: reimpliment this in JS.
$controls_for_select = $this->controls;

// If this field is disabled, it was probably added when there was a valid pro license, so still display it.
if ( isFieldDisabled && in_array( $field->control, $this->pro_controls, true ) ) {
$controls_for_select[ $field->control ] = $this->get_control( $field->control );
}

// Don't allow nesting repeaters inside repeaters.
if ( ! empty( $field->settings['parent'] ) ) {
unset( $controls_for_select['repeater'] );
}

foreach ( $controls_for_select as $control_for_select ) :
?>
<option
value="<?php echo esc_attr( $control_for_select->name ); ?>"
<?php selected( $field->control, $control_for_select->name ); ?>>
<?php echo esc_html( $control_for_select->label ); ?>
</option>
<?php endforeach; ?>
*/
}
</select>
</td>
</tr>
{ /* <?php $this->render_field_settings( $field, $uid ); ?> */ }
<tr className="block-fields-edit-actions-close">
<td className="spacer"></td>
<th scope="row">
</th>
<td>
<Button className="button" title={ __( 'Close Field', 'block-lab' ) } >
{ __( 'Close Field', 'block-lab' ) }
</Button>
</td>
</tr>
</table>
</div>

{
/*
@todo: reimpliment this in JS.
if ( 'repeater' === field.control ) {
if ( ! field.settings.sub_fields ) {
field.settings.sub_fields = [];
}
$this->render_fields_sub_rows( $field->settings['sub_fields'], $uid );
}
*/
}
</div>
);
}
}
2 changes: 2 additions & 0 deletions js/src/components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as BlockLabEditor } from './block-lab-editor';
export { default as FieldRow } from './field-row';
19 changes: 19 additions & 0 deletions js/src/edit-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* WordPress dependencies
*/
const { domReady } = wp;
const { dispatch } = wp.data;
const { render } = wp.element;

/**
* Internal dependencies
*/
import { BlockLabEditor } from './components';

domReady( () => {
dispatch( 'core/editor' ).updateEditorSettings( { richEditingEnabled: false } );
render(
<BlockLabEditor />,
document.getElementById( 'bl-block-editor' ),
);
} );
15 changes: 15 additions & 0 deletions js/src/helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Parses the block from the post content into an object.
*
* @param {string} content The post content, probably containing JSON.
* @return {Object|boolean} The block parsed into an object.
*/
export const getBlockFromContent = ( content ) => {
try {
const parsedContent = JSON.parse( content );
const values = Object.values( parsedContent );
return values[ 0 ] ? values[ 0 ] : false;
} catch ( e ) {
return false;
}
};
1 change: 0 additions & 1 deletion js/src/index.js

This file was deleted.

Loading