diff --git a/mailpoet/lib/EmailEditor/Engine/Renderer/Layout/FlexLayoutRenderer.php b/mailpoet/lib/EmailEditor/Engine/Renderer/Layout/FlexLayoutRenderer.php new file mode 100644 index 0000000000..72cabae8a5 --- /dev/null +++ b/mailpoet/lib/EmailEditor/Engine/Renderer/Layout/FlexLayoutRenderer.php @@ -0,0 +1,77 @@ +computeWidthsForFlexLayout($parsedBlock, $settingsController); + + // MS Outlook doesn't support style attribute in divs so we conditionally wrap the buttons in a table and repeat styles + $outputHtml = ' +
'; + + foreach ($innerBlocks as $key => $block) { + $styles = []; + if ($block['email_attrs']['layout_width'] ?? null) { + $styles['width'] = $block['email_attrs']['layout_width']; + } + if ($key > 0) { + $styles['padding-left'] = SettingsController::FLEX_GAP; + } + $outputHtml .= ''; + } + $outputHtml .= '
' . render_block($block) . '
+ '; + + $styles = wp_style_engine_get_styles($parsedBlock['attrs']['style'])['css']; + $justify = $parsedBlock['attrs']['layout']['justifyContent'] ?? 'left'; + $styles .= 'text-align: ' . esc_attr($justify); + $outputHtml = str_replace('{style}', $styles, $outputHtml); + $outputHtml = str_replace('{align}', $justify, $outputHtml); + + return $outputHtml; + } + + private function computeWidthsForFlexLayout(array $parsedBlock, SettingsController $settingsController): array { + $blocksCount = count($parsedBlock['innerBlocks']); + $totalSetWidth = 0; // Total width set by user. Excludes items that have no width set + $totalUsedWidth = 0; // Total width assuming items without set width would consume proportional width + $parentWidth = $settingsController->parseNumberFromStringWithPixels($parsedBlock['email_attrs']['width'] ?? SettingsController::EMAIL_WIDTH); + $flexGap = $settingsController->parseNumberFromStringWithPixels(SettingsController::FLEX_GAP); + $innerBlocks = $parsedBlock['innerBlocks'] ?? []; + + foreach ($innerBlocks as $key => $block) { + $blockWidthPercent = ($block['attrs']['width'] ?? 0) ? intval($block['attrs']['width']) : 0; + $blockWidth = floor($parentWidth * ($blockWidthPercent / 100)); + $totalSetWidth += $blockWidth; + // If width is not set, we assume it's 25% of the parent width + $totalUsedWidth += $blockWidth ?: floor($parentWidth * (25 / 100)); + + if (!$blockWidth) { + $innerBlocks[$key]['email_attrs']['layout_width'] = null; // Will be rendered as auto + continue; + } + // How many percent of width we will strip to keep some space fot the gap + // Todo add more precise comment + $widthGapReduction = $flexGap * ((100 - $blockWidthPercent) / 100); + $innerBlocks[$key]['email_attrs']['layout_width'] = floor($blockWidth - $widthGapReduction) . 'px'; + } + + // When there is only one block, or percentage is set reasonably we don't need to adjust and just render as set by user + if ($blocksCount <= 1 || ($totalSetWidth < $parentWidth)) { + return $innerBlocks; + } + + foreach ($innerBlocks as $key => $block) { + $proportionalSpaceOverflow = $parentWidth / $totalUsedWidth; + $blockWidth = $block['email_attrs']['layout_width'] ? $settingsController->parseNumberFromStringWithPixels($block['email_attrs']['layout_width']) : 0; + $innerBlocks[$key]['email_attrs']['layout_width'] = $blockWidth ? intval(round($blockWidth * $proportionalSpaceOverflow)) . 'px' : null; + } + return $innerBlocks; + } +} diff --git a/mailpoet/lib/EmailEditor/Integrations/Core/Initializer.php b/mailpoet/lib/EmailEditor/Integrations/Core/Initializer.php index d920344b14..592f545612 100644 --- a/mailpoet/lib/EmailEditor/Integrations/Core/Initializer.php +++ b/mailpoet/lib/EmailEditor/Integrations/Core/Initializer.php @@ -3,6 +3,7 @@ namespace MailPoet\EmailEditor\Integrations\Core; use MailPoet\EmailEditor\Engine\Renderer\BlocksRegistry; +use MailPoet\EmailEditor\Engine\Renderer\Layout\FlexLayoutRenderer; class Initializer { public function initialize(): void { @@ -19,7 +20,7 @@ class Initializer { $blocksRegistry->addBlockRenderer('core/columns', new Renderer\Blocks\Columns()); $blocksRegistry->addBlockRenderer('core/list', new Renderer\Blocks\ListBlock()); $blocksRegistry->addBlockRenderer('core/image', new Renderer\Blocks\Image()); - $blocksRegistry->addBlockRenderer('core/buttons', new Renderer\Blocks\Buttons()); + $blocksRegistry->addBlockRenderer('core/buttons', new Renderer\Blocks\Buttons(new FlexLayoutRenderer())); $blocksRegistry->addBlockRenderer('core/button', new Renderer\Blocks\Button()); } } diff --git a/mailpoet/lib/EmailEditor/Integrations/Core/Renderer/Blocks/Buttons.php b/mailpoet/lib/EmailEditor/Integrations/Core/Renderer/Blocks/Buttons.php index f6abdbf503..3a407c2718 100644 --- a/mailpoet/lib/EmailEditor/Integrations/Core/Renderer/Blocks/Buttons.php +++ b/mailpoet/lib/EmailEditor/Integrations/Core/Renderer/Blocks/Buttons.php @@ -3,87 +3,24 @@ namespace MailPoet\EmailEditor\Integrations\Core\Renderer\Blocks; use MailPoet\EmailEditor\Engine\Renderer\BlockRenderer; +use MailPoet\EmailEditor\Engine\Renderer\Layout\FlexLayoutRenderer; use MailPoet\EmailEditor\Engine\SettingsController; class Buttons implements BlockRenderer { + /** @var FlexLayoutRenderer */ + private $flexLayoutRenderer; + + public function __construct( + FlexLayoutRenderer $flexLayoutRenderer + ) { + $this->flexLayoutRenderer = $flexLayoutRenderer; + } + public function render($blockContent, array $parsedBlock, SettingsController $settingsController): string { $contentStyles = $settingsController->getEmailContentStyles(); $typography = $parsedBlock['attrs']['style']['typography'] ?? []; $typography['fontSize'] = $typography['fontSize'] ?? $contentStyles['typography']['fontSize']; $parsedBlock['attrs']['style']['typography'] = $typography; - $styles = wp_style_engine_get_styles($parsedBlock['attrs']['style'])['css']; - $content = $this->renderButtonsInLayout($parsedBlock, $settingsController); - $justify = $parsedBlock['attrs']['layout']['justifyContent'] ?? 'left'; - $styles .= 'text-align: ' . esc_attr($justify); - - $markup = $this->getMarkup(); - $markup = str_replace('{style}', $styles, $markup); - $markup = str_replace('{align}', $justify, $markup); - $markup = str_replace('{buttons}', $content, $markup); - - return $markup; - } - - private function getMarkup(): string { - // MS Outlook doesn't support style attribute in divs so we conditionally wrap the buttons in a table and repeat styles - return ' -
{buttons}
- '; - } - - private function renderButtonsInLayout(array $parsedBlock, SettingsController $settingsController): string { - $innerBlocks = $this->computeWidthsForFlexLayout($parsedBlock, $settingsController); - - $blocksHtml = ''; - foreach ($innerBlocks as $key => $block) { - $styles = []; - if ($block['email_attrs']['layout_width'] ?? null) { - $styles['width'] = $block['email_attrs']['layout_width']; - } - if ($key > 0) { - $styles['padding-left'] = SettingsController::FLEX_GAP; - } - $blocksHtml .= ''; - } - $blocksHtml .= '
' . render_block($block) . '
'; - return $blocksHtml; - } - - private function computeWidthsForFlexLayout(array $parsedBlock, SettingsController $settingsController): array { - $blocksCount = count($parsedBlock['innerBlocks']); - $totalSetWidth = 0; // Total width set by user. Excludes items that have no width set - $totalUsedWidth = 0; // Total width assuming items without set width would consume proportional width - $parentWidth = $settingsController->parseNumberFromStringWithPixels($parsedBlock['email_attrs']['width'] ?? SettingsController::EMAIL_WIDTH); - $flexGap = $settingsController->parseNumberFromStringWithPixels(SettingsController::FLEX_GAP); - $innerBlocks = $parsedBlock['innerBlocks'] ?? []; - - foreach ($innerBlocks as $key => $block) { - $blockWidthPercent = ($block['attrs']['width'] ?? 0) ? intval($block['attrs']['width']) : 0; - $blockWidth = floor($parentWidth * ($blockWidthPercent / 100)); - $totalSetWidth += $blockWidth; - // If width is not set, we assume it's 25% of the parent width - $totalUsedWidth += $blockWidth ?: floor($parentWidth * (25 / 100)); - - if (!$blockWidth) { - $innerBlocks[$key]['email_attrs']['layout_width'] = null; // Will be rendered as auto - continue; - } - // How many percent of width we will strip to keep some space fot the gap - // Todo add more precise comment - $widthGapReduction = $flexGap * ((100 - $blockWidthPercent) / 100); - $innerBlocks[$key]['email_attrs']['layout_width'] = floor($blockWidth - $widthGapReduction) . 'px'; - } - - // When there is only one block, or percentage is set reasonably we don't need to adjust and just render as set by user - if ($blocksCount <= 1 || ($totalSetWidth < $parentWidth)) { - return $innerBlocks; - } - - foreach ($innerBlocks as $key => $block) { - $proportionalSpaceOverflow = $parentWidth / $totalUsedWidth; - $blockWidth = $block['email_attrs']['layout_width'] ? $settingsController->parseNumberFromStringWithPixels($block['email_attrs']['layout_width']) : 0; - $innerBlocks[$key]['email_attrs']['layout_width'] = $blockWidth ? intval(round($blockWidth * $proportionalSpaceOverflow)) . 'px' : null; - } - return $innerBlocks; + return $this->flexLayoutRenderer->renderInnerBlocksInLayout($parsedBlock, $settingsController); } }