Make renderer render different widths columns

[MAILPOET-1568]
This commit is contained in:
Pavel Dohnal
2018-10-25 11:04:05 +02:00
parent 6028027d47
commit 2ae39c9255
7 changed files with 177 additions and 124 deletions

View File

@@ -5,8 +5,8 @@ use MailPoet\Newsletter\Renderer\Columns\ColumnsHelper;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Button {
static function render($element, $column_count) {
$element['styles']['block']['width'] = self::calculateWidth($element, $column_count);
static function render($element, $column_base_width) {
$element['styles']['block']['width'] = self::calculateWidth($element, $column_base_width);
$template = '
<tr>
<td class="mailpoet_padded_bottom mailpoet_padded_side" valign="top">
@@ -40,9 +40,8 @@ class Button {
return $template;
}
static function calculateWidth($element, $column_count) {
$column_width = ColumnsHelper::columnWidth($column_count);
$column_width = $column_width - (StylesHelper::$padding_width * 2);
static function calculateWidth($element, $column_base_width) {
$column_width = $column_base_width - (StylesHelper::$padding_width * 2);
$border_width = (int)$element['styles']['block']['borderWidth'];
$button_width = (int)$element['styles']['block']['width'];
$button_width = ($button_width > $column_width) ?

View File

@@ -6,7 +6,7 @@ use MailPoet\Newsletter\Renderer\Columns\ColumnsHelper;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Image {
static function render($element, $column_count) {
static function render($element, $column_base_width) {
if(empty($element['src'])) {
return '';
}
@@ -16,7 +16,7 @@ class Image {
$element['width'] = (int)$element['width'];
$element['height'] = (int)$element['height'];
$element = self::adjustImageDimensions($element, $column_count);
$element = self::adjustImageDimensions($element, $column_base_width);
$image_template = '
<img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '"
width="' . $element['width'] . '" alt="' . $element['alt'] . '"/>
@@ -37,21 +37,20 @@ class Image {
return $template;
}
static function adjustImageDimensions($element, $column_count) {
$column_width = ColumnsHelper::columnWidth($column_count);
static function adjustImageDimensions($element, $column_base_width) {
$padded_width = StylesHelper::$padding_width * 2;
// scale image to fit column width
if($element['width'] > $column_width) {
$ratio = $element['width'] / $column_width;
$element['width'] = $column_width;
if($element['width'] > $column_base_width) {
$ratio = $element['width'] / $column_base_width;
$element['width'] = $column_base_width;
$element['height'] = (int)ceil($element['height'] / $ratio);
}
// resize image if the image is padded and wider than padded column width
if($element['fullWidth'] === false &&
$element['width'] > ($column_width - $padded_width)
$element['width'] > ($column_base_width - $padded_width)
) {
$ratio = $element['width'] / ($column_width - $padded_width);
$element['width'] = $column_width - $padded_width;
$ratio = $element['width'] / ($column_base_width - $padded_width);
$element['width'] = $column_base_width - $padded_width;
$element['height'] = (int)ceil($element['height'] / $ratio);
}
return $element;

View File

@@ -3,6 +3,7 @@ namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterPost;
use MailPoet\Newsletter\Renderer\Columns\ColumnsHelper;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Renderer {
@@ -33,32 +34,41 @@ class Renderer {
);
}
function render($data, $column_count) {
function render($data) {
$column_count = count($data['blocks']);
$columns_layout = isset($data['columnLayout'])?$data['columnLayout']:null;
$column_widths = ColumnsHelper::columnWidth($column_count, $columns_layout);
$column_content = [];
foreach($data['blocks'] as $index => $column_blocks) {
$rendered_block_element = $this->renderBlocksInColumn($column_blocks, $column_widths[$index]);
$column_content[] = $rendered_block_element;
}
return $column_content;
}
private function renderBlocksInColumn($block, $column_base_width) {
$block_content = '';
$_this = $this;
array_map(function($block) use (&$block_content, &$column_content, $column_count, $_this) {
$rendered_block_element = $_this->createElementFromBlockType($block, $column_count);
array_map(function($block) use (&$block_content, $column_base_width, $_this) {
$rendered_block_element = $_this->createElementFromBlockType($block, $column_base_width);
if(isset($block['blocks'])) {
$rendered_block_element = $_this->render($block, $column_count);
$rendered_block_element = $_this->renderBlocksInColumn($block, $column_base_width);
// nested vertical column container is rendered as an array
if(is_array($rendered_block_element)) {
$rendered_block_element = implode('', $rendered_block_element);
}
}
// vertical orientation denotes column container
if($block['type'] === 'container' && $block['orientation'] === 'vertical') {
$column_content[] = $rendered_block_element;
} else {
$block_content .= $rendered_block_element;
}
}, $data['blocks']);
return (isset($column_content)) ? $column_content : $block_content;
$block_content .= $rendered_block_element;
}, $block['blocks']);
return $block_content;
}
function createElementFromBlockType($block, $column_count) {
function createElementFromBlockType($block, $column_base_width) {
if($block['type'] === 'automatedLatestContent') {
$content = $this->processAutomatedLatestContent($block, $column_count);
$content = $this->processAutomatedLatestContent($block, $column_base_width);
return $content;
}
$block = StylesHelper::applyTextAlignment($block);
@@ -66,7 +76,7 @@ class Renderer {
if(!class_exists($block_class)) {
return '';
}
return $block_class::render($block, $column_count);
return $block_class::render($block, $column_base_width);
}
function automatedLatestContentTransformedPosts($args) {
@@ -79,12 +89,12 @@ class Renderer {
return $this->ALC->transformPosts($args, $ALC_posts);
}
function processAutomatedLatestContent($args, $column_count) {
function processAutomatedLatestContent($args, $column_base_width) {
$transformed_posts = array(
'blocks' => $this->automatedLatestContentTransformedPosts($args)
);
$transformed_posts = StylesHelper::applyTextAlignment($transformed_posts);
$rendered_posts = $this->render($transformed_posts, $column_count);
$rendered_posts = $this->renderBlocksInColumn($transformed_posts, $column_base_width);
return $rendered_posts;
}

View File

@@ -3,9 +3,11 @@ namespace MailPoet\Newsletter\Renderer\Columns;
class ColumnsHelper {
static $columns_width = array(
1 => 660,
2 => 330,
3 => 220
1 => [660],
2 => [330, 330],
"1_2" => [160, 400],
"2_1" => [400, 160],
3 => [220, 220, 220],
);
static $columns_class = array(
@@ -20,7 +22,11 @@ class ColumnsHelper {
3 => 'right'
);
static function columnWidth($columns_count) {
/** @return int[] */
static function columnWidth($columns_count, $columns_layout) {
if(isset(self::$columns_width[$columns_layout])) {
return self::$columns_width[$columns_layout];
}
return self::$columns_width[$columns_count];
}

View File

@@ -2,25 +2,26 @@
namespace MailPoet\Newsletter\Renderer\Columns;
class Renderer {
function render($column_styles, $column_image, $columns_count, $columns_data) {
$styles = $column_styles['block'];
$width = ColumnsHelper::columnWidth($columns_count);
$class = ColumnsHelper::columnClass($columns_count);
$alignment = ColumnsHelper::columnAlignment($columns_count);
$template = ($columns_count === 1) ?
$this->getOneColumnTemplate($styles, $column_image, $class) :
$this->getMultipleColumnsTemplate($styles, $column_image, $width, $alignment, $class);
$result = array_map(function($content) use ($template) {
return $template['content_start'] . $content . $template['content_end'];
}, $columns_data);
$result = implode('', $result);
if($columns_count !== 1) {
$result = $template['container_start'] . $result . $template['container_end'];
function render($content_block, $columns_data) {
$columns_count = count($content_block['blocks']);
if($columns_count === 1) {
return $this->renderOneColumn($content_block, $columns_data[0]);
}
return $result;
return $this->renderMultipleColumns($content_block, $columns_data);
}
function getOneColumnTemplate($styles, $image, $class) {
private function renderOneColumn($content_block, $content) {
$template = $this->getOneColumnTemplate(
$content_block['styles']['block'],
isset($content_block['image'])?$content_block['image']:null
);
return $template['content_start'] . $content . $template['content_end'];
}
function getOneColumnTemplate($styles, $image) {
$background_css = $this->getBackgroundCss($styles, $image);
$template['content_start'] = '
<tr>
@@ -29,7 +30,7 @@ class Renderer {
<tbody>
<tr>
<td style="padding-left:0;padding-right:0">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="mailpoet_' . $class . '" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;table-layout:fixed;margin-left:auto;margin-right:auto;padding-left:0;padding-right:0;">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="mailpoet_' . ColumnsHelper::columnClass(1) . '" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;table-layout:fixed;margin-left:auto;margin-right:auto;padding-left:0;padding-right:0;">
<tbody>';
$template['content_end'] = '
</tbody>
@@ -43,11 +44,28 @@ class Renderer {
return $template;
}
function getMultipleColumnsTemplate($styles, $image, $width, $alignment, $class) {
$background_css = $this->getBackgroundCss($styles, $image);
$template['container_start'] = '
private function renderMultipleColumns($content_block, $columns_data) {
$columns_count = count($content_block['blocks']);
$columns_layout = isset($content_block['columnLayout'])?$content_block['columnLayout']:null;
$widths = ColumnsHelper::columnWidth($columns_count, $columns_layout);
$class = ColumnsHelper::columnClass($columns_count);
$alignment = ColumnsHelper::columnAlignment($columns_count);
$index = 0;
$result = $this->getMultipleColumnsContainerStart($class, $content_block['styles']['block'], isset($content_block['image'])?$content_block['image']:null);
foreach($columns_data as $content) {
$result .= $this->getMultipleColumnsContentStart($widths[$index++], $alignment, $class);
$result .= $content;
$result .= $this->getMultipleColumnsContentEnd();
}
$result .= $this->getMultipleColumnsContainerEnd();
return $result;
}
private function getMultipleColumnsContainerStart($class, $styles, $image) {
return '
<tr>
<td class="mailpoet_content-' . $class . '" align="left" style="border-collapse:collapse;' . $background_css . '">
<td class="mailpoet_content-' . $class . '" align="left" style="border-collapse:collapse;' . $this->getBackgroundCss($styles, $image) . '">
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
<tbody>
<tr>
@@ -55,17 +73,10 @@ class Renderer {
<table border="0" width="100%" cellpadding="0" cellspacing="0">
<tbody>
<tr>';
$template['content_start'] = '
<td width="' . $width . '" valign="top">
<![endif]--><div style="display:inline-block; max-width:' . $width . 'px; vertical-align:top; width:100%;">
<table width="' . $width . '" class="mailpoet_' . $class . '" border="0" cellpadding="0" cellspacing="0" align="' . $alignment . '" style="width:100%;max-width:' . $width . 'px;border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;table-layout:fixed;margin-left:auto;margin-right:auto;padding-left:0;padding-right:0;">
<tbody>';
$template['content_end'] = '
</tbody>
</table>
</div><!--[if mso]>
</td>';
$template['container_end'] = '
}
private function getMultipleColumnsContainerEnd() {
return '
</tr>
</tbody>
</table>
@@ -75,7 +86,22 @@ class Renderer {
</table>
</td>
</tr>';
return $template;
}
private function getMultipleColumnsContentEnd() {
return '
</tbody>
</table>
</div><!--[if mso]>
</td>';
}
function getMultipleColumnsContentStart($width, $alignment, $class) {
return '
<td width="' . $width . '" valign="top">
<![endif]--><div style="display:inline-block; max-width:' . $width . 'px; vertical-align:top; width:100%;">
<table width="' . $width . '" class="mailpoet_' . $class . '" border="0" cellpadding="0" cellspacing="0" align="' . $alignment . '" style="width:100%;max-width:' . $width . 'px;border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;table-layout:fixed;margin-left:auto;margin-right:auto;padding-left:0;padding-right:0;">
<tbody>';
}
private function getBackgroundCss($styles, $image) {

View File

@@ -97,17 +97,12 @@ class Renderer {
$_this = $this;
$rendered_content = array_map(function($content_block) use($_this) {
$column_count = count($content_block['blocks']);
$column_data = $_this->blocks_renderer->render(
$content_block,
$column_count
);
$content_block_image = isset($content_block['image'])?$content_block['image']:null;
$columns_data = $_this->blocks_renderer->render($content_block);
return $_this->columns_renderer->render(
$content_block['styles'],
$content_block_image,
$column_count,
$column_data
$content_block,
$columns_data
);
}, $blocks);
return implode('', $rendered_content);

View File

@@ -61,10 +61,12 @@ class RendererTest extends \MailPoetTest {
);
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
null,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[]],
],
$column_content
)
);
foreach($DOM('table.mailpoet_cols-one > tbody') as $column) {
$rendered_column_content[] = trim($column->text());
@@ -84,10 +86,12 @@ class RendererTest extends \MailPoetTest {
);
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
null,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[], []],
],
$column_content
)
);
foreach($DOM('table.mailpoet_cols-two > tbody') as $column) {
$rendered_column_content[] = trim($column->text());
@@ -108,10 +112,12 @@ class RendererTest extends \MailPoetTest {
);
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
null,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[], [], []],
],
$column_content
)
);
foreach($DOM('table.mailpoet_cols-three > tbody') as $column) {
$rendered_column_content[] = trim($column->text());
@@ -125,10 +131,13 @@ class RendererTest extends \MailPoetTest {
$column_image = ['src' => 'https://example.com/image.jpg', 'display' => 'scale', 'width' => '1000px', 'height' => '500px'];
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
$column_image,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[]],
'image' => $column_image,
],
$column_content
)
);
$column_css = $DOM('td.mailpoet_content')[0]->attr('style');
expect($column_css)->contains('background: #999999 url(https://example.com/image.jpg) no-repeat center/cover;');
@@ -145,10 +154,13 @@ class RendererTest extends \MailPoetTest {
$column_image = ['src' => 'https://example.com/image.jpg', 'display' => 'fit', 'width' => '1000px', 'height' => '500px'];
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
$column_image,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[]],
'image' => $column_image,
],
$column_content
)
);
$column_css = $DOM('td.mailpoet_content')[0]->attr('style');
expect($column_css)->contains('background: #999999 url(https://example.com/image.jpg) no-repeat center/contain;');
@@ -165,10 +177,13 @@ class RendererTest extends \MailPoetTest {
$column_image = ['src' => 'https://example.com/image.jpg', 'display' => 'tile', 'width' => '1000px', 'height' => '500px'];
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
$column_image,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[]],
'image' => $column_image,
],
$column_content
)
);
$column_css = $DOM('td.mailpoet_content')[0]->attr('style');
expect($column_css)->contains('background: #999999 url(https://example.com/image.jpg) repeat center/contain;');
@@ -185,10 +200,13 @@ class RendererTest extends \MailPoetTest {
$column_image = ['src' => 'https://example.com/image.jpg', 'display' => 'tile', 'width' => '1000px', 'height' => '500px'];
$DOM = $this->DOM_parser->parseStr(
$this->column_renderer->render(
$column_styles,
$column_image,
count($column_content),
$column_content)
[
'styles' => $column_styles,
'blocks' => [[]],
'image' => $column_image,
],
$column_content
)
);
$column_css = $DOM('td.mailpoet_content')[0]->attr('style');
expect($column_css)->contains('background: #ffffff url(https://example.com/image.jpg) repeat center/contain;');
@@ -209,7 +227,7 @@ class RendererTest extends \MailPoetTest {
function testItRendersImage() {
$newsletter = $this->newsletter['body'];
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
$DOM = $this->DOM_parser->parseStr(Image::render($template, 660));
// element should be properly nested, it's width set and style applied
expect($DOM('tr > td > img', 0)->attr('width'))->equals(620);
expect($DOM('tr > td > img', 0)->attr('style'))->notEmpty();
@@ -246,7 +264,7 @@ class RendererTest extends \MailPoetTest {
'link' => '',
'alt' => 'some test alt text'
);
$rendered_image = Image::render($image, $columnCount = 1);
$rendered_image = Image::render($image, $column_base_width = 660);
expect($rendered_image)->equals('');
}
@@ -259,7 +277,7 @@ class RendererTest extends \MailPoetTest {
'fullWidth' => false,
'alt' => 'some test alt text'
);
$rendered_image = Image::render($image, $columnCount = 1);
$rendered_image = Image::render($image, $column_base_width = 660);
$site_url = get_option('siteurl');
expect($rendered_image)->contains('src="'.$site_url.'/relative-path"');
@@ -271,7 +289,7 @@ class RendererTest extends \MailPoetTest {
'fullWidth' => false,
'alt' => 'some test alt text'
);
$rendered_image = Image::render($image, $columnCount = 1);
$rendered_image = Image::render($image, $column_base_width = 660);
expect($rendered_image)->contains('src="//path-without-protocol"');
}
@@ -279,7 +297,7 @@ class RendererTest extends \MailPoetTest {
$newsletter = $this->newsletter['body'];
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
$template['link'] = 'http://example.com';
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 1));
$DOM = $this->DOM_parser->parseStr(Image::render($template, $column_base_width = 660));
// element should be wrapped in <a> tag
expect($DOM('tr > td > a', 0)->html())->contains('<img');
expect($DOM('tr > td > a', 0)->attr('href'))->equals($template['link']);
@@ -292,25 +310,25 @@ class RendererTest extends \MailPoetTest {
'height' => 600,
'fullWidth' => true
);
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$new_image_dimensions = Image::adjustImageDimensions($image, $column_base_width = 660);
expect($new_image_dimensions['width'])->equals(660);
expect($new_image_dimensions['height'])->equals(495);
// nothing happens when image width = column width
$image['width'] = 661;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$new_image_dimensions = Image::adjustImageDimensions($image, $column_base_width = 660);
expect($new_image_dimensions['width'])->equals(660);
// nothing happens when image width < column width
$image['width'] = 659;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$new_image_dimensions = Image::adjustImageDimensions($image, $column_base_width = 660);
expect($new_image_dimensions['width'])->equals(659);
// image is reduced by 40px when it's width > padded column width
$image['width'] = 621;
$image['fullWidth'] = false;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$new_image_dimensions = Image::adjustImageDimensions($image, $column_base_width = 660);
expect($new_image_dimensions['width'])->equals(620);
// nothing happens when image with < padded column width
$image['width'] = 619;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$new_image_dimensions = Image::adjustImageDimensions($image, $column_base_width = 660);
expect($new_image_dimensions['width'])->equals(619);
}
@@ -389,14 +407,14 @@ class RendererTest extends \MailPoetTest {
$newsletter = $this->newsletter['body'];
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$template['styles']['block']['width'] = '700px';
$button_width = Button::calculateWidth($template, $columnCunt = 1);
$button_width = Button::calculateWidth($template, $column_base_width = 660);
expect($button_width)->equals('618px'); //(width - (2 * border width)
}
function testItRendersButton() {
$newsletter = $this->newsletter['body'];
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$DOM = $this->DOM_parser->parseStr(Button::render($template, $columnCount = 1));
$DOM = $this->DOM_parser->parseStr(Button::render($template, $column_base_width = 660));
// element should be properly nested with arcsize/styles/fillcolor set
expect(
$DOM('tr > td > div > table > tr > td > a.mailpoet_button', 0)->html()
@@ -432,7 +450,7 @@ class RendererTest extends \MailPoetTest {
$newsletter = $this->newsletter['body'];
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$template['styles']['block']['fontFamily'] = 'Lucida';
$DOM = $this->DOM_parser->parseStr(Button::render($template, $columnCount = 1));
$DOM = $this->DOM_parser->parseStr(Button::render($template, $column_base_width = 660));
expect(
preg_match(
'/font-family: \'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif/',
@@ -464,7 +482,7 @@ class RendererTest extends \MailPoetTest {
'iconType' => 'custom',
)
);
$rendered_block = Social::render($block, $columnCount = 1);
$rendered_block = Social::render($block, $column_base_width = 660);
expect($rendered_block)->equals('');
}