first commit
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* WordPress dependencies
|
||||
*/
|
||||
const {
|
||||
addFilter,
|
||||
} = wp.hooks;
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import ColumnBlockEdit from './edit.jsx';
|
||||
import ColumnBlockSave from './save.jsx';
|
||||
import changeColumnSize from './change-column-size';
|
||||
|
||||
const CNVS_PREVENT_UPDATE = 'CNVS_PREVENT_UPDATE';
|
||||
|
||||
/**
|
||||
* Custom block Edit output for Column block.
|
||||
*
|
||||
* @param {JSX} edit Original block edit.
|
||||
* @param {Object} blockProps Block data.
|
||||
*
|
||||
* @return {JSX} Block edit.
|
||||
*/
|
||||
function editRender( edit, blockProps ) {
|
||||
if ( 'canvas/column' === blockProps.name ) {
|
||||
return (
|
||||
<ColumnBlockEdit { ...blockProps } />
|
||||
);
|
||||
}
|
||||
|
||||
return edit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom block register data for Column block.
|
||||
*
|
||||
* @param {Object} blockData Block data.
|
||||
*
|
||||
* @return {Object} Block data.
|
||||
*/
|
||||
function registerData( blockData ) {
|
||||
if ( 'canvas/column' === blockData.name ) {
|
||||
blockData.save = ColumnBlockSave;
|
||||
}
|
||||
|
||||
return blockData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compensate adjacent columns, when changing size directly in field.
|
||||
*
|
||||
* @param {Mixed} val Attribute value.
|
||||
* @param {String} name Attribute name.
|
||||
* @param {Object} blockProps Block data.
|
||||
*
|
||||
* @return {Mixed} Attribute value.
|
||||
*/
|
||||
function onFieldChange( val, name, blockProps ) {
|
||||
if ( 'canvas/column' === blockProps.name && 'size' === name ) {
|
||||
changeColumnSize( blockProps.clientId, val, true );
|
||||
return CNVS_PREVENT_UPDATE;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
addFilter( 'canvas.customBlock.editRender', 'canvas/column/editRender', editRender );
|
||||
addFilter( 'canvas.customBlock.registerData', 'canvas/column/registerData', registerData );
|
||||
addFilter( 'canvas.customBlock.onFieldChange', 'canvas/column/changeColumnSize', onFieldChange );
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* WordPress dependencies.
|
||||
*/
|
||||
const {
|
||||
getBlockRootClientId,
|
||||
getBlocks,
|
||||
getBlockAttributes,
|
||||
} = wp.data.select( 'core/block-editor' );
|
||||
|
||||
const {
|
||||
jQuery: $,
|
||||
} = window;
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getAdjacentBlocks } from './utils';
|
||||
|
||||
const MIN_COL_SIZE = 1;
|
||||
|
||||
/**
|
||||
* Update columns size.
|
||||
*
|
||||
* First, we update the column size by changing style directly, then we update the block attribute.
|
||||
* This hack is needed to prevent columns jumping as `updateBlockAttributes` don't apply changes immediately.
|
||||
*
|
||||
* @param {*} clientId
|
||||
* @param {*} size
|
||||
*/
|
||||
function updateAttribute( clientId, size ) {
|
||||
$( `#block-${ clientId }[data-type="canvas/column"]` ).css( {
|
||||
flexBasis: `${ 100 * size / 12 }%`,
|
||||
width: `${ 100 * size / 12 }%`,
|
||||
} );
|
||||
|
||||
wp.data.dispatch( 'core/block-editor' ).updateBlockAttributes(clientId, {
|
||||
size: size,
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update columns size and compensate adjacent columns if needed.
|
||||
*
|
||||
* @param {String} clientId - block client id.
|
||||
* @param {Int} size - new column size.
|
||||
* @param {Boolean} compensate - compensate adjacent columns also.
|
||||
*/
|
||||
export default function( clientId, size, compensate = false ) {
|
||||
if ( ! compensate ) {
|
||||
updateAttribute( clientId, size );
|
||||
return;
|
||||
}
|
||||
|
||||
// Compensate
|
||||
if ( size < MIN_COL_SIZE || size > 12 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Constrain or expand siblings to account for gain or loss of
|
||||
// total columns area.
|
||||
const columns = getBlocks( getBlockRootClientId( clientId ) );
|
||||
const adjacentColumns = getAdjacentBlocks( columns, clientId );
|
||||
const thisColumnAttrs = getBlockAttributes( clientId );
|
||||
|
||||
let neededSize = size - thisColumnAttrs.size;
|
||||
|
||||
/*
|
||||
* Make col smaller.
|
||||
*/
|
||||
if ( neededSize < 0 ) {
|
||||
// set new size to current column.
|
||||
updateAttribute( clientId, size );
|
||||
|
||||
// set new size to next column.
|
||||
updateAttribute( adjacentColumns[0].clientId, adjacentColumns[0].attributes.size - neededSize );
|
||||
} else if ( neededSize > 0) {
|
||||
/*
|
||||
* Make col larger.
|
||||
*/
|
||||
let availableSize = 0;
|
||||
adjacentColumns.map( ( colData ) => {
|
||||
if ( colData.attributes.size > MIN_COL_SIZE ) {
|
||||
availableSize += colData.attributes.size - MIN_COL_SIZE;
|
||||
}
|
||||
} );
|
||||
|
||||
// we can't change size, because no space available on the right.
|
||||
if ( ! availableSize || neededSize > availableSize ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set new size to current column.
|
||||
updateAttribute( clientId, size );
|
||||
|
||||
// set new size to adjacent columns.
|
||||
adjacentColumns.forEach( ( colData ) => {
|
||||
if ( neededSize > 0 && colData.attributes.size > MIN_COL_SIZE ) {
|
||||
const newColSize = Math.max( colData.attributes.size - neededSize, MIN_COL_SIZE );
|
||||
neededSize -= colData.attributes.size - newColSize;
|
||||
|
||||
updateAttribute( colData.clientId, newColSize );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { throttle } from 'throttle-debounce';
|
||||
|
||||
/**
|
||||
* WordPress dependencies
|
||||
*/
|
||||
const $ = window.jQuery;
|
||||
|
||||
const { Component, Fragment } = wp.element;
|
||||
|
||||
const {
|
||||
InnerBlocks,
|
||||
} = wp.blockEditor;
|
||||
|
||||
const {
|
||||
compose,
|
||||
} = wp.compose;
|
||||
|
||||
const {
|
||||
withSelect,
|
||||
} = wp.data;
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import getStyles from './styles';
|
||||
import changeColumnSize from './change-column-size';
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
class ColumnBlockEdit extends Component {
|
||||
constructor() {
|
||||
super( ...arguments );
|
||||
|
||||
this.state = {
|
||||
resizing: false,
|
||||
resizingContainerWidth: 0,
|
||||
resizingCursorPosition: 0,
|
||||
resizingColSize: 0,
|
||||
};
|
||||
|
||||
this.onResizeStart = this.onResizeStart.bind( this );
|
||||
this.onResizing = throttle( 150, this.onResizing.bind( this ) );
|
||||
this.onResizeEnd = this.onResizeEnd.bind( this );
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener( 'mousemove', this.onResizing );
|
||||
document.addEventListener( 'mouseup', this.onResizeEnd );
|
||||
}
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener( 'mousemove', this.onResizing );
|
||||
document.removeEventListener( 'mouseup', this.onResizeEnd );
|
||||
}
|
||||
|
||||
/**
|
||||
* On start column resize
|
||||
*
|
||||
* @param {Object} e event.
|
||||
*/
|
||||
onResizeStart( e ) {
|
||||
const {
|
||||
clientId,
|
||||
attributes,
|
||||
} = this.props;
|
||||
|
||||
const $column = $(`[data-block="${ clientId }"`);
|
||||
const $parentRow = $column.closest('.cnvs-block-row');
|
||||
|
||||
this.setState( {
|
||||
resizing: true,
|
||||
resizingContainerWidth: $parentRow.width(),
|
||||
resizingCursorPosition: e.clientX,
|
||||
resizingColSize: attributes.size,
|
||||
} );
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* On resizing column
|
||||
*
|
||||
* @param {Object} e event.
|
||||
*/
|
||||
onResizing( e ) {
|
||||
if ( ! this.state.resizing ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
attributes,
|
||||
clientId,
|
||||
} = this.props;
|
||||
|
||||
const mouseMoved = e.clientX - this.state.resizingCursorPosition;
|
||||
const oneColumnSize = this.state.resizingContainerWidth / 12;
|
||||
const columnsResized = Math.round( mouseMoved / oneColumnSize );
|
||||
const newSize = this.state.resizingColSize + columnsResized;
|
||||
|
||||
if ( newSize !== attributes.size ) {
|
||||
changeColumnSize( clientId, newSize, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On end column resize
|
||||
*
|
||||
* @param {Object} e event.
|
||||
*/
|
||||
onResizeEnd( e ) {
|
||||
if ( ! this.state.resizing ) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.setState( {
|
||||
resizing: false,
|
||||
resizingContainerWidth: 0,
|
||||
resizingCursorPosition: 0,
|
||||
resizingColSize: 0,
|
||||
} );
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
hasChildBlocks,
|
||||
attributes,
|
||||
clientId,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
canvasClassName,
|
||||
} = attributes;
|
||||
|
||||
let {
|
||||
className,
|
||||
} = this.props;
|
||||
|
||||
className = classnames(
|
||||
'cnvs-block-column',
|
||||
canvasClassName,
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={ className }>
|
||||
<div className="cnvs-block-column-inner" data-min-height={ attributes['minHeight'] }>
|
||||
<div>
|
||||
<InnerBlocks
|
||||
templateLock={ false }
|
||||
renderAppender={ (
|
||||
hasChildBlocks ?
|
||||
undefined :
|
||||
() => <InnerBlocks.ButtonBlockAppender />
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="cnvs-block-column-resizer"
|
||||
draggable="true"
|
||||
onMouseDown={ ( e ) => { this.onResizeStart( e ) } }
|
||||
>
|
||||
<span />
|
||||
</div>
|
||||
<style>{ canvasClassName && clientId ? getStyles( attributes, canvasClassName, clientId ) : '' }</style>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ColumnBlockEditWithSelect = compose(
|
||||
withSelect( ( select, ownProps ) => {
|
||||
const {
|
||||
clientId,
|
||||
} = ownProps;
|
||||
|
||||
const {
|
||||
getBlockRootClientId,
|
||||
getBlocks,
|
||||
getBlockOrder,
|
||||
} = select( 'core/block-editor' );
|
||||
|
||||
return {
|
||||
getBlockRootClientId,
|
||||
getBlocks,
|
||||
hasChildBlocks: getBlockOrder( clientId ).length > 0,
|
||||
};
|
||||
} )
|
||||
)( ColumnBlockEdit );
|
||||
|
||||
export default ColumnBlockEditWithSelect;
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* Column block template
|
||||
*
|
||||
* @var $attributes - block attributes
|
||||
* @var $content - inner blocks
|
||||
* @var $options - layout options
|
||||
*
|
||||
* @package Canvas
|
||||
*/
|
||||
?>
|
||||
|
||||
<div class="<?php echo esc_attr( $attributes['className'] ); ?>" <?php echo ( isset( $attributes['anchor'] ) ? ' id="' . esc_attr( $attributes['anchor'] ) . '"' : '' ); ?>>
|
||||
<div class="cnvs-block-column-inner">
|
||||
<div>
|
||||
<?php echo (string) $content; // XSS. ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* WordPress dependencies
|
||||
*/
|
||||
const { Component } = wp.element;
|
||||
|
||||
const {
|
||||
InnerBlocks,
|
||||
} = wp.blockEditor;
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default class ColumnBlockSave extends Component {
|
||||
render() {
|
||||
return <InnerBlocks.Content />;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
const {
|
||||
canvasBreakpoints,
|
||||
} = window;
|
||||
|
||||
/**
|
||||
* Row block styles for Editor
|
||||
*
|
||||
* @param {Object} attributes block attributes
|
||||
* @param {String} className block class name
|
||||
* @param {String} clientId block client id
|
||||
*
|
||||
* @returns {String}
|
||||
*/
|
||||
export default function( attributes, className, clientId ) {
|
||||
let result = '';
|
||||
let hideResizer = true;
|
||||
|
||||
Object.keys( canvasBreakpoints ).forEach( ( name ) => {
|
||||
const data = canvasBreakpoints[ name ];
|
||||
let styles = '';
|
||||
let suffix = '';
|
||||
|
||||
if ( 'desktop' !== name ) {
|
||||
suffix = `_${ name }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide resizer.
|
||||
*/
|
||||
if ( suffix && hideResizer ) {
|
||||
hideResizer = false;
|
||||
styles += `
|
||||
.${ className } + .cnvs-block-column-resizer {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Size.
|
||||
*/
|
||||
if ( attributes[ `size${ suffix }` ] ) {
|
||||
const size = attributes[ `size${ suffix }` ];
|
||||
styles += `
|
||||
#block-${ clientId }[data-type="canvas/column"] {
|
||||
-ms-flex-preferred-size: ${ 100 * size / 12 }%;
|
||||
flex-basis: ${ 100 * size / 12 }%;
|
||||
width: ${ 100 * size / 12 }%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order.
|
||||
*/
|
||||
if ( attributes[ `order${ suffix }` ] ) {
|
||||
const order = attributes[ `order${ suffix }` ];
|
||||
styles += `
|
||||
#block-${ clientId }[data-type="canvas/column"] {
|
||||
-ms-flex-order: ${ order };
|
||||
order: ${ order };
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Min Height.
|
||||
*/
|
||||
if ( attributes[ `minHeight${ suffix }` ] ) {
|
||||
const minHeight = attributes[ `minHeight${ suffix }` ];
|
||||
styles += `
|
||||
.${ className } > .cnvs-block-column-inner {
|
||||
min-height: ${ minHeight };
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertical Align.
|
||||
*/
|
||||
if ( attributes[ `verticalAlign${ suffix }` ] ) {
|
||||
let verticalAlign = attributes[ `verticalAlign${ suffix }` ];
|
||||
|
||||
if ( 'top' === verticalAlign ) {
|
||||
verticalAlign = 'flex-start';
|
||||
} else if ( 'bottom' === verticalAlign ) {
|
||||
verticalAlign = 'flex-end';
|
||||
}
|
||||
|
||||
styles += `
|
||||
#block-${ clientId }[data-type="canvas/column"] {
|
||||
justify-content: ${ verticalAlign };
|
||||
}
|
||||
.${ className } > .cnvs-block-column-inner {
|
||||
align-items: ${ verticalAlign };
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
// add media query.
|
||||
if ( suffix && styles ) {
|
||||
styles = `@media (max-width: ${ data.width }px) { ${ styles } } `;
|
||||
}
|
||||
|
||||
if ( styles ) {
|
||||
result += styles;
|
||||
}
|
||||
} );
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* Column block styles for Frontend
|
||||
*
|
||||
* @var $attributes - block attributes
|
||||
* @var $class_name - block class name
|
||||
*
|
||||
* @package Canvas
|
||||
*/
|
||||
|
||||
$breakpoints = cnvs_gutenberg()->get_breakpoints_data();
|
||||
|
||||
foreach ( $breakpoints as $name => $data ) {
|
||||
$result = '';
|
||||
$suffix = '';
|
||||
|
||||
if ( 'desktop' !== $name ) {
|
||||
$suffix = '_' . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Size.
|
||||
*/
|
||||
if ( isset( $attributes[ 'size' . $suffix ] ) ) {
|
||||
$size = $attributes[ 'size' . $suffix ];
|
||||
$result .= '
|
||||
.' . esc_attr( $class_name ) . ' {
|
||||
-ms-flex-preferred-size: ' . esc_attr( 100 * $size / 12 ) . '%;
|
||||
flex-basis: ' . esc_attr( 100 * $size / 12 ) . '%;
|
||||
}
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* Order.
|
||||
*/
|
||||
if ( isset( $attributes[ 'order' . $suffix ] ) && $attributes[ 'order' . $suffix ] ) {
|
||||
$order = $attributes[ 'order' . $suffix ];
|
||||
$result .= '
|
||||
.' . esc_attr( $class_name ) . ' {
|
||||
-ms-flex-order: ' . esc_attr( $order ) . ';
|
||||
order: ' . esc_attr( $order ) . ';
|
||||
}
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* Min Height.
|
||||
*/
|
||||
if ( isset( $attributes[ 'minHeight' . $suffix ] ) && '' !== $attributes[ 'minHeight' . $suffix ] ) {
|
||||
$minHeight = $attributes[ 'minHeight' . $suffix ];
|
||||
$result .= '
|
||||
.' . esc_attr( $class_name ) . ' > .cnvs-block-column-inner {
|
||||
min-height: ' . esc_attr( $minHeight ) . ';
|
||||
}
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertical Align.
|
||||
*/
|
||||
if ( isset( $attributes[ 'verticalAlign' . $suffix ] ) && $attributes[ 'verticalAlign' . $suffix ] ) {
|
||||
$verticalAlign = $attributes[ 'verticalAlign' . $suffix ];
|
||||
|
||||
if ( 'top' === $verticalAlign ) {
|
||||
$verticalAlign = 'flex-start';
|
||||
} else if ( 'bottom' === $verticalAlign ) {
|
||||
$verticalAlign = 'flex-end';
|
||||
}
|
||||
|
||||
$result .= '
|
||||
.' . esc_attr( $class_name ) . ',
|
||||
.' . esc_attr( $class_name ) . ' > .cnvs-block-column-inner {
|
||||
align-items: ' . esc_attr( $verticalAlign ) . ';
|
||||
}
|
||||
';
|
||||
}
|
||||
|
||||
// add media query.
|
||||
if ( $suffix && $result ) {
|
||||
$result = '@media (max-width: ' . esc_attr( $data['width'] ) . 'px) { ' . $result . ' } ';
|
||||
}
|
||||
|
||||
if ( $result ) {
|
||||
echo $result; // XSS Ok.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
const { findIndex } = window.lodash;
|
||||
|
||||
/**
|
||||
* Returns the considered adjacent to that of the specified `clientId` for
|
||||
* resizing consideration. Adjacent blocks are those occurring after, except
|
||||
* when the given block is the last block in the set. For the last block, the
|
||||
* behavior is reversed.
|
||||
*
|
||||
* @param {WPBlock[]} blocks Block objects.
|
||||
* @param {string} clientId Client ID to consider for adjacent blocks.
|
||||
*
|
||||
* @return {WPBlock[]} Adjacent block objects.
|
||||
*/
|
||||
export function getAdjacentBlocks( blocks, clientId ) {
|
||||
const index = findIndex( blocks, { clientId } );
|
||||
const isLastBlock = index === blocks.length - 1;
|
||||
|
||||
return isLastBlock ? blocks.slice( 0, index ) : blocks.slice( index + 1 );
|
||||
}
|
||||
Reference in New Issue
Block a user