-
Notifications
You must be signed in to change notification settings - Fork 809
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extensions: Add block editor extensions source (#11685)
* Revert "Gutenblocks: Revert move to JP (#11682)" This reverts commit 9deff5e. * Pull changes from wp-calypso
- Loading branch information
Showing
226 changed files
with
15,396 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,48 @@ | ||
<?php | ||
|
||
$path = dirname( dirname( __FILE__ ) ) . '/'; | ||
// The repo root path. | ||
$path = dirname( dirname( __FILE__ ) ) . '/'; | ||
|
||
// Build an iterator over all files in the repo that match the regex in the RegexIterator. | ||
$directory = new RecursiveDirectoryIterator( $path ); | ||
$iterator = new RecursiveIteratorIterator( $directory ); | ||
$regex = new RegexIterator( $iterator, '/^.+\.(css|js)$/i', RecursiveRegexIterator::GET_MATCH ); | ||
|
||
$ignore_paths = array( | ||
'_inc/client/', | ||
'bin/', | ||
'docker/', | ||
'docs/', | ||
'extensions/', | ||
'logs/', | ||
'node_modules/', | ||
'tests/', | ||
'tools/', | ||
'vendor/', | ||
); | ||
|
||
$manifest = array(); | ||
foreach ( $regex as $file => $value ) { | ||
$file = str_replace( $path, '', $file ); | ||
$directory = substr( $file, 0, strpos( $file, '/' ) ); | ||
if ( in_array( $directory, array( 'node_modules', 'tests' ) ) ) { | ||
foreach ( $regex as $path_to_file => $value ) { | ||
$path_from_repo_root = str_replace( $path, '', $path_to_file ); | ||
|
||
// Ignore top-level files. | ||
if ( false === strpos( $path_from_repo_root, '/' ) ) { | ||
continue; | ||
} | ||
$manifest[] = $file; | ||
|
||
// Ignore explicit ignore list. | ||
foreach ( $ignore_paths as $ignore_path ) { | ||
if ( 0 === strpos( $path_from_repo_root, $ignore_path ) ) { | ||
continue 2; | ||
} | ||
} | ||
|
||
$manifest[] = $path_from_repo_root; | ||
} | ||
|
||
$export = var_export( $manifest, true ); | ||
|
||
file_put_contents( $path . 'modules/photon-cdn/jetpack-manifest.php', "<?php \r\n\$assets = $export;\r\n" ); | ||
file_put_contents( $path . 'modules/photon-cdn/jetpack-manifest.php', "<?php | ||
// This file is autogenerated by bin/build-asset-cdn-json.php | ||
\$assets = $export;\r\n" ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,38 @@ | ||
# Jetpack Block Editor Extensions | ||
|
||
This directory lists extensions for the Block Editor, also known as Gutenberg, [that was introduced in WordPress 5.0](https://wordpress.org/news/2018/12/bebo/). | ||
This directory lists extensions for the Block Editor, also known as Gutenberg, | ||
[that was introduced in WordPress 5.0](https://wordpress.org/news/2018/12/bebo/). | ||
|
||
## Extension Type | ||
|
||
We define different types of block editor extensions: | ||
|
||
- Blocks are available in the editor itself, and live in the `blocks` directory. | ||
- Plugins are available in the Jetpack sidebar that appears on the right side of the block editor. Those live in the `plugins` directory. | ||
|
||
When adding a new extension, add a new directory for your extension the matching directory. | ||
- Blocks are available in the editor itself. | ||
- Plugins are available in the Jetpack sidebar that appears on the right side of the block editor. | ||
|
||
## Extension Structure | ||
|
||
Your extension should follow this structure: | ||
Extensions loosely follow this structure: | ||
|
||
``` | ||
. | ||
└── blockname/ | ||
└── blockname.php ← PHP file where the block and its assets are registered. | ||
└── block-or-plugin-name/ | ||
├── block-or-plugin-name.php ← PHP file where the block and its assets are registered. | ||
├── editor.js ← script loaded only in the editor | ||
├── editor.scss ← styles loaded only in the editor | ||
├── view.js ← script loaded in the editor and theme | ||
└── view.scss ← styles loaded in the editor and theme | ||
``` | ||
|
||
If your block depends on another block, place them all in extensions folder: | ||
|
||
``` | ||
. | ||
├── blockname/ | ||
├── block-name/ | ||
└── sub-blockname/ | ||
``` | ||
|
||
**Note that this directory is still being populated. For now, you can find the blocks [here](https://github.com/Automattic/wp-calypso/tree/master/client/gutenberg/extensions). | ||
|
||
## Develop new blocks | ||
|
||
You can follow [the instructions here](../docs/guides/gutenberg-blocks.md) to add your own block to Jetpack. | ||
|
||
## Block naming conventions | ||
Coming when [#11640](https://github.com/Automattic/jetpack/pull/11640) lands. | ||
|
||
Blocks should use the `jetpack/` prefix, e.g. `jetpack/markdown`. |
200 changes: 200 additions & 0 deletions
200
extensions/blocks/business-hours/components/day-edit.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { isEmpty } from 'lodash'; | ||
import { Component, Fragment } from '@wordpress/element'; | ||
import { IconButton, TextControl, ToggleControl } from '@wordpress/components'; | ||
import classNames from 'classnames'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { __ } from '../../../utils/i18n'; | ||
|
||
const defaultOpen = '09:00'; | ||
const defaultClose = '17:00'; | ||
|
||
class DayEdit extends Component { | ||
renderInterval = ( interval, intervalIndex ) => { | ||
const { day } = this.props; | ||
const { opening, closing } = interval; | ||
return ( | ||
<Fragment key={ intervalIndex }> | ||
<div className="business-hours__row"> | ||
<div className={ classNames( day.name, 'business-hours__day' ) }> | ||
{ intervalIndex === 0 && this.renderDayToggle() } | ||
</div> | ||
<div className={ classNames( day.name, 'business-hours__hours' ) }> | ||
<TextControl | ||
type="time" | ||
label={ __( 'Opening' ) } | ||
value={ opening } | ||
className="business-hours__open" | ||
placeholder={ defaultOpen } | ||
onChange={ value => { | ||
this.setHour( value, 'opening', intervalIndex ); | ||
} } | ||
/> | ||
<TextControl | ||
type="time" | ||
label={ __( 'Closing' ) } | ||
value={ closing } | ||
className="business-hours__close" | ||
placeholder={ defaultClose } | ||
onChange={ value => { | ||
this.setHour( value, 'closing', intervalIndex ); | ||
} } | ||
/> | ||
</div> | ||
<div className="business-hours__remove"> | ||
{ day.hours.length > 1 && ( | ||
<IconButton | ||
isSmall | ||
isLink | ||
icon="trash" | ||
onClick={ () => { | ||
this.removeInterval( intervalIndex ); | ||
} } | ||
/> | ||
) } | ||
</div> | ||
</div> | ||
{ intervalIndex === day.hours.length - 1 && ( | ||
<div className="business-hours__row business-hours-row__add"> | ||
<div className={ classNames( day.name, 'business-hours__day' ) }> </div> | ||
<div className={ classNames( day.name, 'business-hours__hours' ) }> | ||
<IconButton isLink label={ __( 'Add Hours' ) } onClick={ this.addInterval }> | ||
{ __( 'Add Hours' ) } | ||
</IconButton> | ||
</div> | ||
<div className="business-hours__remove"> </div> | ||
</div> | ||
) } | ||
</Fragment> | ||
); | ||
}; | ||
|
||
setHour = ( hourValue, hourType, hourIndex ) => { | ||
const { day, attributes, setAttributes } = this.props; | ||
const { days } = attributes; | ||
setAttributes( { | ||
days: days.map( value => { | ||
if ( value.name === day.name ) { | ||
return { | ||
...value, | ||
hours: value.hours.map( ( hour, index ) => { | ||
if ( index === hourIndex ) { | ||
return { | ||
...hour, | ||
[ hourType ]: hourValue, | ||
}; | ||
} | ||
return hour; | ||
} ), | ||
}; | ||
} | ||
return value; | ||
} ), | ||
} ); | ||
}; | ||
|
||
toggleClosed = nextValue => { | ||
const { day, attributes, setAttributes } = this.props; | ||
const { days } = attributes; | ||
|
||
setAttributes( { | ||
days: days.map( value => { | ||
if ( value.name === day.name ) { | ||
const hours = nextValue | ||
? [ | ||
{ | ||
opening: defaultOpen, | ||
closing: defaultClose, | ||
}, | ||
] | ||
: []; | ||
return { | ||
...value, | ||
hours, | ||
}; | ||
} | ||
return value; | ||
} ), | ||
} ); | ||
}; | ||
|
||
addInterval = () => { | ||
const { day, attributes, setAttributes } = this.props; | ||
const { days } = attributes; | ||
day.hours.push( { opening: '', closing: '' } ); | ||
setAttributes( { | ||
days: days.map( value => { | ||
if ( value.name === day.name ) { | ||
return { | ||
...value, | ||
hours: day.hours, | ||
}; | ||
} | ||
return value; | ||
} ), | ||
} ); | ||
}; | ||
|
||
removeInterval = hourIndex => { | ||
const { day, attributes, setAttributes } = this.props; | ||
const { days } = attributes; | ||
|
||
setAttributes( { | ||
days: days.map( value => { | ||
if ( day.name === value.name ) { | ||
return { | ||
...value, | ||
hours: value.hours.filter( ( hour, index ) => { | ||
return hourIndex !== index; | ||
} ), | ||
}; | ||
} | ||
return value; | ||
} ), | ||
} ); | ||
}; | ||
|
||
isClosed() { | ||
const { day } = this.props; | ||
return isEmpty( day.hours ); | ||
} | ||
|
||
renderDayToggle() { | ||
const { day, localization } = this.props; | ||
return ( | ||
<Fragment> | ||
<span className="business-hours__day-name">{ localization.days[ day.name ] }</span> | ||
<ToggleControl | ||
label={ this.isClosed() ? __( 'Closed' ) : __( 'Open' ) } | ||
checked={ ! this.isClosed() } | ||
onChange={ this.toggleClosed } | ||
/> | ||
</Fragment> | ||
); | ||
} | ||
|
||
renderClosed() { | ||
const { day } = this.props; | ||
return ( | ||
<div className="business-hours__row business-hours-row__closed"> | ||
<div className={ classNames( day.name, 'business-hours__day' ) }> | ||
{ this.renderDayToggle() } | ||
</div> | ||
<div className={ classNames( day.name, 'closed', 'business-hours__hours' ) }> </div> | ||
<div className="business-hours__remove"> </div> | ||
</div> | ||
); | ||
} | ||
|
||
render() { | ||
const { day } = this.props; | ||
return this.isClosed() ? this.renderClosed() : day.hours.map( this.renderInterval ); | ||
} | ||
} | ||
|
||
export default DayEdit; |
58 changes: 58 additions & 0 deletions
58
extensions/blocks/business-hours/components/day-preview.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { Component, Fragment } from '@wordpress/element'; | ||
import { date } from '@wordpress/date'; | ||
import { isEmpty } from 'lodash'; | ||
import { sprintf } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { _x } from '../../../utils/i18n'; | ||
|
||
class DayPreview extends Component { | ||
formatTime( time ) { | ||
const { timeFormat } = this.props; | ||
const [ hours, minutes ] = time.split( ':' ); | ||
const _date = new Date(); | ||
if ( ! hours || ! minutes ) { | ||
return false; | ||
} | ||
_date.setHours( hours ); | ||
_date.setMinutes( minutes ); | ||
return date( timeFormat, _date ); | ||
} | ||
|
||
renderInterval = ( interval, key ) => { | ||
return ( | ||
<dd key={ key }> | ||
{ sprintf( | ||
_x( 'From %s to %s', 'from business opening hour to closing hour' ), | ||
this.formatTime( interval.opening ), | ||
this.formatTime( interval.closing ) | ||
) } | ||
</dd> | ||
); | ||
}; | ||
|
||
render() { | ||
const { day, localization } = this.props; | ||
const hours = day.hours.filter( | ||
// remove any malformed or empty intervals | ||
interval => this.formatTime( interval.opening ) && this.formatTime( interval.closing ) | ||
); | ||
return ( | ||
<Fragment> | ||
<dt className={ day.name }>{ localization.days[ day.name ] }</dt> | ||
{ isEmpty( hours ) ? ( | ||
<dd>{ _x( 'Closed', 'business is closed on a full day' ) }</dd> | ||
) : ( | ||
hours.map( this.renderInterval ) | ||
) } | ||
</Fragment> | ||
); | ||
} | ||
} | ||
|
||
export default DayPreview; |
Oops, something went wrong.