/** * Internal dependencies */ import './style.scss'; import FieldsRender from '../components/fields-render'; import FieldsCSSOutput from '../components/fields-css-output'; import ServerSideRender from '../components/server-side-render'; import ImageSelector from '../components/image-selector'; import getParentBlock from '../utils/get-parent-block'; /** * WordPress dependencies */ const { __, } = wp.i18n; const { registerBlockType, } = wp.blocks; const { Component, Fragment, RawHTML, } = wp.element; const { BaseControl, Placeholder, PanelBody, Disabled, Notice, } = wp.components; const { InspectorControls, } = wp.blockEditor; const { applyFilters, } = wp.hooks; const { withSelect, } = wp.data; const { blocks, } = window.pk_custom_blocks_localize; const { select, subscribe } = wp.data; const allLocations = { root: __('Block editor root'), 'section-wide': __('Fullwidth section'), 'section-full': __('Fullwidth section with alignment set to "Full"'), 'section-content': __('The content part of a sidebar section'), 'section-sidebar': __('The sidebar part of a sidebar section'), }; // Value, that will not be saved in field attribute. // Used in columns block. const CNVS_PREVENT_UPDATE = 'CNVS_PREVENT_UPDATE'; // Template Switcher. class TemplateSwitcher { constructor() { this.template = null; } init() { subscribe(() => { const newTemplate = select('core/editor').getEditedPostAttribute( 'template' ); if ( newTemplate !== this.template ) { this.template = newTemplate; this.changeTemplate(); } }); } changeTemplate() { let blocks = wp.data.select('core/block-editor').getBlocks(); blocks.forEach((el) => { wp.data.dispatch('core/block-editor').updateBlock(el.clientId, { attributes: {} }); }); } } new TemplateSwitcher().init(); /** * Get block icons and convert string `{icon}; } return icon || ''; } /** * Get block Edit class. * * @param {Object} blockData block data * @return {Class} */ function getBlockEdit(blockData) { const { name, title, fields, sections, layouts, } = blockData; const icon = getBlockIcon(blockData); class CustomBlockEdit extends Component { constructor() { super(...arguments); this.maybeUpdateLocationAttribute = this.maybeUpdateLocationAttribute.bind(this); this.maybeSetDefaultLayout = this.maybeSetDefaultLayout.bind(this); this.getAllowedLocations = this.getAllowedLocations.bind(this); this.getAllowedLocationsNotice = this.getAllowedLocationsNotice.bind(this); this.isAllowed = this.isAllowed.bind(this); this.getLayoutSelector = this.getLayoutSelector.bind(this); this.maybeUpdateLocationAttribute(true); } componentDidMount() { this.maybeSetDefaultLayout(); this.maybeUpdateLocationAttribute(); } componentDidUpdate() { this.maybeUpdateLocationAttribute(); } /** * Maybe update location attribute. */ maybeUpdateLocationAttribute(force) { if (this.props.location !== this.props.attributes.canvasLocation) { if (force) { this.props.attributes.canvasLocation = this.props.location; } this.props.setAttributes({ canvasLocation: this.props.location, }); } } /** * Maybe set default layout, when available only 1 layout. */ maybeSetDefaultLayout() { const { attributes, setAttributes, } = this.props; const { layout, } = attributes; const layoutsCount = layouts ? Object.keys(layouts).length : 0; if (1 === layoutsCount) { const isLayoutDifferent = Object.keys(layouts)[0] !== layout; if (isLayoutDifferent) { setAttributes({ layout: Object.keys(layouts)[0], }); } } } /** * Get array with all allowed locations. * * @return {Array} */ getAllowedLocations() { const { attributes, } = this.props; const { layout, } = attributes; // get locations from the current layout // and from the block settings. return [ ...(layouts && layouts[layout] && layouts[layout].location ? layouts[layout].location : []), ...blockData.location, ]; } /** * Get notice about allowed locations. * * @param {Array} checkLocations array of locations to check. If empty, use locations from the block settings and layout * @return {JSX} */ getAllowedLocationsNotice(checkLocations) { // get locations from the current layout // and from the block settings. if (!checkLocations) { checkLocations = this.getAllowedLocations(); } return (

{__('The block output is allowed in following locations only:')}

); } /** * Check if block is allowed in current location. * * @param {Array} checkLocations array of locations to check. If empty, use locations from the block settings and layout * @return {boolean} */ isAllowed(checkLocations) { const { location, } = this.props; let result = true; // get locations from the current layout // and from the block settings. if (!checkLocations) { checkLocations = this.getAllowedLocations(); } if (checkLocations && checkLocations.length) { result = false; checkLocations.forEach((locationName) => { if (location === locationName) { result = true; } }); } return result; } /** * Returns layout selector. * * @return {JSX} ImageSelector. */ getLayoutSelector() { const { setAttributes, } = this.props; const { layout, } = this.props.attributes; const items = Object.keys(layouts).map((layoutName) => { const layoutData = layouts[layoutName]; const isDisabled = !this.isAllowed(layoutData.location); return { content: {layoutData.icon}, value: layoutName, label: layoutData.name, isDisabled, disabledNotice: isDisabled ? this.getAllowedLocationsNotice(layoutData.location) : '', }; }); return ( { setAttributes({ layout: val, }); }} items={items} /> ); } render() { const { attributes, setAttributes, } = this.props; const { layout, canvasClassName, } = attributes; const isLayoutsAvailable = layouts && Object.keys(layouts).length > 1; // layout selector. if (isLayoutsAvailable && !layout) { return ( {this.getLayoutSelector()} ); } // Block render if all checks passed. const blockRender = applyFilters('canvas.customBlock.editRender', ( ), this.props); return (
{this.isAllowed() ? ( blockRender ) : ( {this.getAllowedLocationsNotice()} )} {fields ? ( {isLayoutsAvailable ? ( {this.getLayoutSelector()} ) : ''} { val = applyFilters('canvas.customBlock.onFieldChange', val, key, this.props); if ( CNVS_PREVENT_UPDATE !== val ) { setAttributes({ [key]: val }); } }} /> ) : ''}
); } } /* * Prepare location type name of the current block. * * Available types: * - root - block inserted in root * - section-wide - block inserted in Section block with layout = wide * - section-full - block inserted in Section block with layout = full * - section-content - block inserted in Section block inside Content column * - block inserted in Row block inside column with size [5-11] * - section-sidebar - block inserted in Section block inside Sidebar column * - block inserted in Row block inside column with size [1-4] */ return withSelect((select, ownProps) => { const { getBlockHierarchyRootClientId, getBlock, } = select('core/block-editor'); const rootBlock = getBlock(getBlockHierarchyRootClientId(ownProps.clientId)); let parentBlock = getParentBlock(rootBlock, ownProps); let isRoot = parentBlock && parentBlock.clientId === ownProps.clientId; // Skip block `core/group` from this check as we can use it for Query Settings. if ( 'core/group' === parentBlock.name && ! isRoot ) { const postGroupId = parentBlock.clientId; parentBlock = getParentBlock(rootBlock, parentBlock); isRoot = parentBlock && parentBlock.clientId === postGroupId; } let location = 'default'; // root if ( isRoot ) { location = 'root'; // inside section content } else if (parentBlock && 'canvas/section-content' === parentBlock.name) { const sectionBlock = getParentBlock(rootBlock, parentBlock); if ('full' === sectionBlock.attributes.layout) { if ('full' === sectionBlock.attributes.layoutAlign) { location = 'section-full'; } else { location = 'section-wide'; } } else if ('with-sidebar' === sectionBlock.attributes.layout) { location = 'section-content'; } // inside section sidebar } else if (parentBlock && 'canvas/section-sidebar' === parentBlock.name) { location = 'section-sidebar'; // inside row block } else if (parentBlock && 'canvas/column' === parentBlock.name) { if (parentBlock.attributes.size < 5) { location = 'section-sidebar'; } else { location = 'section-content'; } } return { location, }; })(CustomBlockEdit); } /** * Register Custom Blocks */ jQuery(() => { if (blocks && blocks.length) { blocks.forEach((blockData) => { let { supports = {}, } = blockData; if ( 'canvas/section' === blockData.name && 'page' !== canvasLocalize.postType ) { return; } const resultBlockData = applyFilters( 'canvas.customBlock.registerData', { ...blockData, supports, icon: getBlockIcon(blockData), edit: getBlockEdit(blockData), save() { // Render in PHP. return null; }, }); // Register block. registerBlockType(blockData.name, resultBlockData); // Register block style. if (blockData.styles && blockData.length) { blockData.styles.forEach((styleData) => { registerBlockStyle(blockData.name, styleData); }); } }); } });