Merge pull request #123 from mailpoet/rendering_engine

Newsletter rendering engine.
This commit is contained in:
Marco
2015-09-24 10:16:23 +02:00
15 changed files with 2027 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Button {
static function render($element) {
$stylesHelper = new StylesHelper();
$template = '
<tr>
<td class="mailpoet_col mailpoet_button mailpoet_padded" valign = "top" >
<div>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="' . $element['styles']['block']['textAlign'] . '">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w="urn:schemas-microsoft-com:office:word"
href="' . $element['url'] . '"
style="height:' . $element['styles']['block']['lineHeight'] . ';
width:' . $element['styles']['block']['width'] . ';
v-text-anchor:middle;"
arcsize="' . round($element['styles']['block']['borderRadius'] / $element['styles']['block']['lineHeight'] * 100) . '%"
strokecolor="' . $element['styles']['block']['borderColor'] . '"
fillcolor="' . $element['styles']['block']['backgroundColor'] . '">
<w:anchorlock/>
<center style="color:' . $element['styles']['block']['fontColor'] . ';
font-family:' . $element['styles']['block']['fontFamily'] . ';
font-size:' . $element['styles']['block']['fontSize'] . ';
font-weight:bold;">' . $element['text'] . '
</center>
</v:roundrect>
<![endif]-->
<a class="mailpoet_button"
href="' . $element['url'] . '"
style="display:inline-block;text-align:center;text-decoration:none;-webkit-text-size-adjust:none;mso-hide:all;' . $stylesHelper->getBlockStyles($element, array('textAlign')) . '"> ' . $element['text'] . '
</a>
</td>
</tr>
</table>
</div>
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,23 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
class Divider {
static function render($element) {
$template = '
<tr>
<td class="mailpoet_col mailpoet_divider mailpoet_padded"
style="background-color: ' . $element['styles']['block']['backgroundColor'] . '; padding: ' . $element['styles']['block']['padding'] . ' 0;"
valign="top">
<table width="100%">
<tr>
<td style="border-top-width: ' . $element['styles']['block']['borderWidth'] . ';
border-top-style: ' . $element['styles']['block']['borderStyle'] . ';
border-top-color: ' . $element['styles']['block']['borderColor'] . ';">
</td>
</tr>
</table>
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,30 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Footer {
static function render($element) {
$stylesHelper = new StylesHelper();
// apply link styles
if(isset($element['styles']['link'])) {
$element['text'] = str_replace('<a', '<a style="' . $stylesHelper->getStyles($element['styles'], 'link') . '"', $element['text']);
}
// apply text styles
if(isset($element['styles']['link'])) {
$element['text'] = str_replace('<p', '<p style="' . $stylesHelper->getStyles($element['styles'], 'text') . '"', $element['text']);
}
$template = '
<tr>
<td class="mailpoet_col mailpoet_footer"
style="' . $stylesHelper->getStyles($element['styles'], 'block') . '"
valign="top">
<div>' . $element['text'] . '</div>
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,30 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Header {
static function render($element) {
$stylesHelper = new StylesHelper();
// apply link styles
if(isset($element['styles']['link'])) {
$element['text'] = str_replace('<a', '<a style="' . $stylesHelper->getStyles($element['styles'], 'link') . '"', $element['text']);
}
// apply text styles
if(isset($element['styles']['link'])) {
$element['text'] = str_replace('<p', '<p style="' . $stylesHelper->getStyles($element['styles'], 'text') . '"', $element['text']);
}
$template = '
<tr>
<td class="mailpoet_col mailpoet_header"
style="' . $stylesHelper->getBlockStyles($element) . '"
valign="top">
<div>' . $element['text'] . '</div>
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,24 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Image {
static function render($element) {
$stylesHelper = new StylesHelper();
$element['width'] = (int) $element['width'];
$template = '
<tr>
<td class="mailpoet_col mailpoet_image ' . (($element['padded'] === true) ? "mailpoet_padded" : "") . '"
style="' . $stylesHelper->getBlockStyles($element) . '"
valign="top">
<img style="top:0; left:0; height: auto; width:100%;"
src="' . $element['src'] . '"
width="' . (($element['padded'] === true) ? $element['width'] - (20 * 2) : $element['width']) . '">
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,24 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
class Renderer {
function render($data) {
array_map(function ($block) use (&$blockContent, &$columns) {
$blockContent .= $this->createElementFromBlockType($block);
if(isset($block['blocks'])) {
$blockContent = $this->render($block);
}
// vertical orientation denotes column container
if($block['type'] === 'container' && $block['orientation'] === 'vertical') {
$columns[] = $blockContent;
}
}, $data['blocks']);
return (isset($columns)) ? $columns : $blockContent;
}
function createElementFromBlockType($block) {
$blockClass = __NAMESPACE__ . '\\' . ucfirst($block['type']);
return (class_exists($blockClass)) ? $blockClass::render($block) : '';
}
}

View File

@@ -0,0 +1,26 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
class Social {
static function render($element) {
$iconsBlock = '';
if(is_array($element['icons'])) {
foreach ($element['icons'] as $icon) {
$iconsBlock .= '
<a href="' . $icon['link'] . '">
<img src="' . $icon['image'] . '" width = "32" height = "32" style="width: 32px; height: 32px;" alt="' . $icon['iconType'] . '">
</a>
<img src="http://mp3.mailpoet.net/spacer.gif" width = "10" height = "1" style=" width: 10px; height: 1px;">';
}
}
$template = '
<tr>
<td class="mailpoet_col mailpoet_social" valign="top">
<div class="mailpoet_social-icon mailpoet_padded">' . $iconsBlock . ' </div>
</td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,23 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Newsletter\Renderer\StylesHelper;
class Spacer {
static function render($element) {
$stylesHelper = new StylesHelper();
// if the parent container (column) has background set and the divider element has a transparent background,
// it will assume the newsletter background, not that of the parent container
if($element['styles']['block']['backgroundColor'] === 'transparent') {
unset($element['styles']['block']['backgroundColor']);
}
$template = '
<tr>
<td class="mailpoet_col mailpoet_spacer" style="' . $stylesHelper->getBlockStyles($element) . '" valign="top"> </td>
</tr>';
return $template;
}
}

View File

@@ -0,0 +1,114 @@
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
class Text {
static $typeFace = array(
'Arial' => "Arial, 'Helvetica Neue', Helvetica, sans-serif",
'Comic Sans MS' => "'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif",
'Courier New' => "'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace",
'Georgia' => "Georgia, Times, 'Times New Roman', serif",
'Lucida' => "'Lucida Sans Unicode', 'Lucida Grande', sans-serif",
'Tahoma' => "Tahoma, Verdana, Segoe, sans-serif",
'Times New Roman' => "'Times New Roman', Times, Baskerville, Georgia, serif",
'Trebuchet MS' => "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif",
'Verdana' => "Verdana, Geneva, sans-serif"
);
static function render($element) {
$html = $element['text'];
$html = self::convertBlockquotesToTables($html);
$html = self::addLineBreakAfterTags($html);
$html = self::removeEmptyTags($html);
$html = self::convertEmptyParagraphsToLineBreaks($html);
$html = self::convertParagraphsToTables($html);
$html = self::removeLastBreakLine($html);
$template = '
<tr>
<td class="mailpoet_col mailpoet_text mailpoet_padded" valign="top">' . $html . ' </td>
</tr>';
return $template;
}
static function removeLastBreakLine($html) {
return preg_replace('/<br>([^<br>]*)$/s', '', $html);
}
static function convertParagraphsToTables($html) {
$html = preg_replace('/<p>(.*?)<\/p>/', '
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<span class="paragraph">
$1
</span>
</td>
</tr>
</table>', $html);
return preg_replace('/<p(.+style=\".*?\")?>(.*?)<\/p>/', '
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td $1>
<span class="paragraph">
$2
</span>
</td>
</tr>
</table>', $html);
}
static function convertEmptyParagraphsToLineBreaks($html) {
return preg_replace('/<p(?:.+style=\".*?\")?><\/p>/', '<br>', $html);
}
static function addLineBreakAfterTags($html) {
return preg_replace('/(<\/(ul|ol|h\d)>)/', '$1<br>', $html);
}
static function convertBlockquotesToTables($html) {
$template = '
<table cellpadding="0" cellspacing="0" border="0" class="mailpoet_blockquote">
<tbody>
<tr>
<td valign="top">$1</td>
</tr>
</tbody>
</table>
<br>';
return preg_replace('/<blockquote>(.*?)<\/blockquote>/s', $template, $html);
}
static function removeEmptyTags($html) {
$pattern = <<<'EOD'
~
<
(?:
!--[^-]*(?:-(?!->)[^-]*)*-->[^<]*(*SKIP)(*F) # skip comments
|
( # group 1
(span|em|strong) # tag name in group 2
[^"'>]* #'"# all that is not a quote or a closing angle bracket
(?: # quoted attributes
"[^\\"]*(?:\\.[^\\"]*)*+" [^"'>]* #'"# double quote
|
'[^\\']*(?:\\.[^\\']*)*+' [^"'>]* #'"# single quote
)*+
>
\s*
(?:
<!--[^-]*(?:-(?!->)[^-]*)*+--> \s* # html comments
|
<(?1) \s* # recursion with the group 1
)*+
</\2> # closing tag
) # end of the group 1
)
~sxi
EOD;
return preg_replace($pattern, '', $html);
}
}

View File

@@ -0,0 +1,76 @@
<?php namespace MailPoet\Newsletter\Renderer\Columns;
class Renderer {
public $columnWidths = array(
1 => 600,
2 => 300,
3 => 200
);
public $columnClasses = array(
1 => 'mailpoet_col-one',
2 => 'mailpoet_col-two',
3 => 'mailpoet_col-three'
);
function render($columnsCount, $columnsData) {
$columnWidth = $this->columnWidths[$columnsCount];
$columnClass = $this->columnClasses[$columnsCount];
// open column container
$columnContainerTemplate = '
<tr>
<td class="mailpoet_content" align="left" style="border-collapse: collapse;">
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
<tbody>
<tr>
<td class="mailpoet_cols-wrapper" style="border-collapse: collapse; padding-left: 0px; padding-right: 0px;">
<!--[if mso]>
<table border="0" width="100%" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td width="' . $columnWidth . '" style="width: ' . $columnWidth . 'px;" valign="top">
<![endif]-->';
$columnOpenTemplate = '
<table width="' . $columnWidth . '"
border="0" cellpadding="0" cellspacing="0" align="left" class="mailpoet_force-row ' . $columnClass . ' mailpoet_col"
style="width: ' . $columnWidth . 'px; border-spacing: 0; mso-table-lspace: 0pt; mso-table-rspace: 0pt;
table-layout: fixed; margin-left: auto; margin-right: auto;" bgcolor="#999999">
<tbody>';
$columnCloseTemplate = '
</tbody>
</table>
<!--[if mso]>
</td>
<td width="' . $columnWidth . '" style="width: ' . $columnWidth . 'px;" valign="top">
<![endif]-->';
foreach ($columnsData as $index => $columnData) {
$index++;
$columnContainerTemplate .= $columnOpenTemplate . $columnData;
if($columnsCount > 1 && $index != $columnsCount) {
$columnContainerTemplate .= $columnCloseTemplate;
}
}
// close column container
$columnContainerTemplate .= '
</tbody>
</table>
<!--[if mso]>
</td>
</tr>
</tbody>
</table>
<![endif]-->
</td>
</tr>
</table>
</td>
</tr>';
return $columnContainerTemplate;
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace MailPoet\Newsletter\Renderer;
if(!defined('ABSPATH')) exit;
class Renderer {
public $template = 'Template.html';
function __construct($newsletterData) {
$this->blocksRenderer = new Blocks\Renderer();
$this->columnsRenderer = new Columns\Renderer();
$this->stylesHelper = new StylesHelper();
$this->DOMQuery = new \pQuery();
$this->CSSInliner = new \MailPoet\Util\CSS();
$this->data = $newsletterData;
$this->template = file_get_contents(dirname(__FILE__) . '/' . $this->template);
}
function renderAll() {
$newsletterContent = $this->renderContent($this->data['content']);
$newsletterStyles = $this->renderStyles($this->data['globalStyles']);
$renderedTemplate = $this->renderTemplate($this->template, array(
$newsletterStyles,
$newsletterContent
));
$renderedTemplateWithInlinedStyles = $this->inlineCSSStyles($renderedTemplate);
return $this->postProcessRenderedTemplate($renderedTemplateWithInlinedStyles);
}
function renderContent($content) {
$newsletterContent = array_map(function ($contentBlock) {
$columnCount = count($contentBlock['blocks']);
$columnData = $this->blocksRenderer->render($contentBlock);
return $this->columnsRenderer->render($columnCount, $columnData);
}, $content['blocks']);
return implode('', $newsletterContent);
}
function renderStyles($styles) {
$newsletterStyles = '';
foreach ($styles as $selector => $style) {
switch ($selector) {
case 'text':
$selector = 'span.paragraph, ul, ol';
break;
case 'body':
$selector = '.mailpoet_content-wrapper';
break;
case 'link':
$selector = '.mailpoet_content-wrapper a';
break;
case 'wrapper':
$selector = '.mailpoet_container, .mailpoet_col-one, .mailpoet_col-two, .mailpoet_col-three';
break;
}
$newsletterStyles .= $selector . '{' . PHP_EOL;
foreach ($style as $attribute => $individualStyle) {
$newsletterStyles .= $this->stylesHelper->translateCSSAttribute($attribute) . ':' . $individualStyle . ';' . PHP_EOL;
}
$newsletterStyles .= '}' . PHP_EOL;
}
return $newsletterStyles;
}
function renderTemplate($template, $data) {
return preg_replace_callback('/{{\w+}}/', function ($matches) use (&$data) {
return array_shift($data);
}, $template);
}
function inlineCSSStyles($template) {
return $this->CSSInliner->inlineCSS(null, $template);
}
function postProcessRenderedTemplate($template) {
// remove padding from last element inside each column
$DOM = $this->DOMQuery->parseStr($template);
$lastColumnElement = $DOM->query('.mailpoet_col > tbody > tr:last-child > td');
foreach ($lastColumnElement as $element) {
$element->setAttribute('style', str_replace('padding-bottom:20px;', '', $element->attributes['style']));
}
return $DOM->__toString();
}
}

View File

@@ -0,0 +1,39 @@
<?php namespace MailPoet\Newsletter\Renderer;
class StylesHelper {
public $cssAtributesTable = array(
'backgroundColor' => 'background-color',
'fontColor' => 'color',
'fontFamily' => 'font-family',
'textDecoration' => 'text-decoration',
'textAlign' => 'text-align',
'fontSize' => 'font-size',
'borderWidth' => 'border-width',
'borderStyle' => 'border-style',
'borderColor' => 'border-color',
'borderRadius' => 'border-radius',
'lineHeight' => 'line-height'
);
function getBlockStyles($element, $ignoreSpecificStyles = false) {
if(!isset($element['styles']['block'])) {
return;
}
return $this->getStyles($element['styles'], 'block', $ignoreSpecificStyles);
}
function getStyles($data, $type, $ignoreSpecificStyles = false) {
$styles = array_map(function ($attribute, $style) use($ignoreSpecificStyles) {
if(!$ignoreSpecificStyles || !in_array($attribute, $ignoreSpecificStyles)) {
return $this->translateCSSAttribute($attribute) . ': ' . $style . ' !important;';
}
}, array_keys($data[$type]), $data[$type]);
return implode('', $styles);
}
function translateCSSAttribute($attribute) {
return (array_key_exists($attribute, $this->cssAtributesTable)) ? $this->cssAtributesTable[$attribute] : $attribute;
}
}

View File

@@ -0,0 +1,266 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<title>MailPoet Newsletter Template</title>
</head>
<body style="-ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; mso-line-height-rule: exactly; font-family: Helvetica, Arial, sans-serif; text-align: left; color: #333333; margin: 0; padding: 0;"
bgcolor="#F0F0F0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<style type="text/css">
body {
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
mso-line-height-rule: exactly;
text-align: left;
}
h1,
h2,
h3,
p,
ol,
ul,
li {
margin: 0;
}
ol,
ul,
li {
padding-left: 0;
}
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.ReadMsgBody {
width: 100%;
background-color: #ebebeb;
}
table {
border-spacing: 0;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
p {
margin: 0;
padding: 0;
margin-bottom: 0;
}
table td {
border-collapse: collapse;
}
img {
-ms-interpolation-mode: bicubic;
margin: 0;
border: 0;
padding: 0;
display: block;
}
td.mailpoet_button, .mailpoet_image, .mailpoet_text, .mailpoet_social {
padding-bottom: 20px;
}
.mailpoet_button div {
padding: 8px 0 8px 0;
}
.yshortcuts a {
border-bottom: none !important;
}
.mailpoet_container {
width: 600px;
max-width: 600px;
}
.mailpoet_col,
.mailpoet_cols-wrapper {
padding-left: 0px;
padding-right: 0px;
}
.mailpoet_col-one,
.mailpoet_col-two,
.mailpoet_col-three {
table-layout: fixed;
margin-left: auto;
margin-right: auto;
}
.mailpoet_col-one,
.mailpoet_col-two,
.mailpoet_col-three,
.mailpoet_header,
.mailpoet_footer {
margin-left: auto;
margin-right: auto;
}
.mailpoet_footer div, .mailpoet_header div {
margin: 5px 0 5px 0;
}
/* .mailpoet_col-one ol,*/
.mailpoet_col-one ul {
margin-left: 18px;
}
/*.mailpoet_col-two ol,*/
.mailpoet_col-two ul {
margin-left: 16px;
}
.mailpoet_col-two li {
padding-left: 5px;
}
/*.mailpoet_col-three ol,*/
.mailpoet_col-three ul {
margin-left: 14px;
}
.mailpoet_col-three li {
padding-left: 6px;
}
.mailpoet_content-wrapper a {
text-decoration: underline;
}
.mailpoet_padded {
padding-left: 20px;
padding-right: 20px;
/*word-break: break-all;*/
word-wrap: break-word;
}
.mailpoet_centered {
margin-left: auto;
margin-right: auto;
}
.mailpoet_center {
text-align: center;
}
.mailpoet_right {
text-align: right;
}
.mailpoet_left {
text-align: left;
}
.mailpoet_justify {
text-align: justify;
}
.mailpoet_blockquote {
border-left: 2px #565656 solid;
padding-left: 10px;
font-style: italic;
}
.mailpoet_blockquote p.mailpoet_signature {
font-style: normal;
font-weight: bold;
}
.mailpoet_social {
text-align: center;
}
.mailpoet_social img {
display: inline;
}
.mailpoet_social div {
padding: 5px 0 5px 0;
}
.ios-footer a {
color: #aaaaaa !important;
text-decoration: underline;
}
@media screen and (max-width: 400px) and (-webkit-min-device-pixel-ratio: 1) {
[class="mailpoet_cols-wrapper"] {
padding-left: 0 !important;
padding-right: 0 !important;
}
}
@media screen and (max-width: 599px) and (-webkit-min-device-pixel-ratio: 1) {
[class~="mailpoet_force-row"],
[class="mailpoet_container"] {
width: 100% !important;
max-width: 100% !important;
}
a[class="mailpoet_button"] {
width: 100% !important;
max-width: 100% !important;
padding: 5px 0 !important;
}
td[class="mailpoet_col"] {
width: 100% !important;
}
[class=mailpoet_wrapper] ol,
[class=mailpoet_wrapper] ul {
margin-left: 18px !important;
}
[class=mailpoet_wrapper] li {
padding-left: 2px !important;
}
.mailpoet_social img {
height: 32px !important;
width: 32px !important;
padding-bottom: 20px !important;
}
}
{{newsletter_editor_styles}}
</style>
<table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
<tbody>
<tr>
<td align="center" class="mailpoet_content-wrapper" valign="top" style="border-collapse:collapse;" bgcolor="#333333">
<table border="0" width="600" cellpadding="0" cellspacing="0" class="mailpoet_container" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;max-width:600px">
<tbody>
{{newsletter_editor_content}}
</tbody>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,130 @@
<?php
use MailPoet\Newsletter\Renderer\Blocks\Button;
use MailPoet\Newsletter\Renderer\Blocks\Divider;
use MailPoet\Newsletter\Renderer\Blocks\Footer;
use MailPoet\Newsletter\Renderer\Blocks\Header;
use MailPoet\Newsletter\Renderer\Blocks\Image;
use MailPoet\Newsletter\Renderer\Blocks\Social;
use MailPoet\Newsletter\Renderer\Blocks\Spacer;
use MailPoet\Newsletter\Renderer\Blocks\Text;
use MailPoet\Newsletter\Renderer\Columns\Renderer as ColumnRenderer;
use MailPoet\Newsletter\Renderer\Renderer;
class RendererCest {
function __construct() {
$this->newsletterData = json_decode(file_get_contents(dirname(__FILE__) . '/RendererTestData.json'), true);
$this->renderer = new Renderer($this->newsletterData);
$this->columnRenderer = new ColumnRenderer();
$this->queryDOM = new \pQuery();
}
function itRendersCompleteNewsletter() {
$template = $this->renderer->renderAll();
$DOM = $this->queryDOM->parseStr($template);
// we expect to have 4 column containers and 7 columns (1x1, 1x2, 1x3, 1x1)
expect(count($DOM('.mailpoet_cols-wrapper')))->equals(4);
expect(count($DOM('.mailpoet_force-row')))->equals(7);
}
function itRendersColumns() {
$columnContent = array(
'one',
'two',
'three'
);
$DOM = $this->queryDOM->parseStr($this->columnRenderer->render(count($columnContent), $columnContent));
// rendered object should cocntain three columns
foreach ($DOM('.mailpoet_force-row > tbody') as $column) {
$renderedColumnContent[] = trim($column->text());
};
expect(count(array_diff($renderedColumnContent, $columnContent)))->equals(0);
}
function itRendersHeader() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][0];
$DOM = $this->queryDOM->parseStr(Header::render($template));
// element should be proplerly nested, and styles should be applied to <td>, <a> and <p> elements
expect(is_object($DOM('tr > td > p', 0)))->true();
expect(is_object($DOM('tr > td > p > a', 0)))->true();
expect($DOM('a', 0)->attr('style'))->notEmpty();
expect($DOM('p', 0)->attr('style'))->notEmpty();
}
function itRendersImage() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][1];
$DOM = $this->queryDOM->parseStr(Image::render($template));
// element should be properly nested, it's width set and style applied to <td>
expect(is_object($DOM('tr > td > img', 0)))->true();
expect($DOM('tr > td > img', 0)->attr('width'))->equals(560);
expect($DOM('tr > td', 0)->attr('style'))->notEmpty();
}
function itRendersText() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][2];
$DOM = $this->queryDOM->parseStr(Text::render($template));
// blockquotes and paragraphs should be converted to spans and placed inside a table
expect(is_object($DOM('tr > td.mailpoet_text > table > tr > td > span.paragraph', 0)))->true();
expect(is_object($DOM('tr > td.mailpoet_text > table.mailpoet_blockquote > tbody > tr > td > table > tr > td > span.paragraph', 0)))->true();
}
function itRendersDivider() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][3];
$DOM = $this->queryDOM->parseStr(Divider::render($template));
// element should be properly nested and its border-top-width set
expect(is_object($DOM('tr > td.mailpoet_divider > table > tr > td', 0)))->true();
expect(preg_match('/border-top-width: 3px/', $DOM('tr > td.mailpoet_divider > table > tr > td', 0)->attr('style')))->equals(1);
}
function itRendersSpacer() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][4];
$DOM = $this->queryDOM->parseStr(Spacer::render($template));
// element should be properly nested and its height set
expect(is_object($DOM('tr > td.mailpoet_spacer', 0)))->true();
expect(preg_match('/height: 50px/', $DOM('tr > td.mailpoet_spacer', 0)->attr('style')))->equals(1);
}
function itRendersButton() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][5];
$DOM = $this->queryDOM->parseStr(Button::render($template));
// element should be properly nested with arcsize/styles/fillcolor set
expect(is_object($DOM('tr > td.mailpoet_button > div > table > tr > td > a.mailpoet_button', 0)))->true();
expect(preg_match('/line-height: 30px/', $DOM('a.mailpoet_button', 0)->attr('style')))->equals(1);
expect(preg_match('/arcsize="' . round(20 / 30 * 100) . '%"/', $DOM('tr > td.mailpoet_button > div > table > tr > td', 0)->text()))->equals(1);
expect(preg_match('/style="height:30px.*?width:100px/', $DOM('tr > td.mailpoet_button > div > table > tr > td', 0)->text()))->equals(1);
expect(preg_match('/style="color:#ffffff.*?font-family:Arial.*?font-size:13px/', $DOM('tr > td.mailpoet_button > div > table > tr > td', 0)->text()))->equals(1);
expect(preg_match('/fillcolor="#666666/', $DOM('tr > td.mailpoet_button > div > table > tr > td', 0)->text()))->equals(1);
}
function itRendersSocialIcons() {
$template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][6];
$DOM = $this->queryDOM->parseStr(Social::render($template));
// element should be properly nested, contain social icons and image source/link href/alt should be properly set
expect(is_object($DOM('tr > td.mailpoet_social > div', 0)))->true();
expect(count($DOM('a > img')))->equals(10);
expect($DOM('a', 0)->attr('href'))->equals('http://example.org');
expect($DOM('a > img', 0)->attr('src'))->equals('http://mp3.mailpoet.net/various/social-icons/custom.png');
expect($DOM('a > img', 0)->attr('alt'))->equals('custom');
}
function itRendersFooter() {
$template = $this->newsletterData['content']['blocks'][3]['blocks'][0]['blocks'][0];
$DOM = $this->queryDOM->parseStr(Footer::render($template));
// element should be proplerly nested, and styles should be applied to <td>, <a> and <p> elements
expect(is_object($DOM('tr > td.mailpoet_footer > div', 0)))->true();
expect(is_object($DOM('tr > td.mailpoet_footer > div > a > p', 0)))->true();
expect($DOM('tr > td.mailpoet_footer', 0)->attr('style'))->notEmpty();
expect($DOM('a', 0)->attr('style'))->notEmpty();
expect($DOM('p', 0)->attr('style'))->notEmpty();
}
}

File diff suppressed because it is too large Load Diff