diff --git a/lib/Newsletter/Renderer/Blocks/Button.php b/lib/Newsletter/Renderer/Blocks/Button.php index b34223cd58..0bd623a8fb 100644 --- a/lib/Newsletter/Renderer/Blocks/Button.php +++ b/lib/Newsletter/Renderer/Blocks/Button.php @@ -1,47 +1,43 @@ - - -
- - - - -
- - ' . $element['text'] . ' - -
-
- - '; - + + ' . $element['text'] . ' + + + + + + '; + //!d($template);exit; return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Divider.php b/lib/Newsletter/Renderer/Blocks/Divider.php index ccab9ce7a4..e4dfef303c 100644 --- a/lib/Newsletter/Renderer/Blocks/Divider.php +++ b/lib/Newsletter/Renderer/Blocks/Divider.php @@ -1,23 +1,31 @@ - - - - - - -
-
- - '; - + + + + + + +
+
+ + '; return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Footer.php b/lib/Newsletter/Renderer/Blocks/Footer.php index 005c75f62c..a25c9fdb41 100644 --- a/lib/Newsletter/Renderer/Blocks/Footer.php +++ b/lib/Newsletter/Renderer/Blocks/Footer.php @@ -1,30 +1,27 @@ -getStyles($element['styles'], 'link') . '"', $element['text']); + if (isset($element['styles']['link'])) { + $element['text'] = str_replace( + '
', $element['text']); + $element['text'] = preg_replace('/(<\/?p>)/', '', $element['text']); $template = ' - - -
' . $element['text'] . '
- - '; - + + + ' . $element['text'] . ' + + '; return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Header.php b/lib/Newsletter/Renderer/Blocks/Header.php index 3be509324c..2ef6f8b89b 100644 --- a/lib/Newsletter/Renderer/Blocks/Header.php +++ b/lib/Newsletter/Renderer/Blocks/Header.php @@ -1,30 +1,27 @@ -getStyles($element['styles'], 'link') . '"', $element['text']); + if (isset($element['styles']['link'])) { + $element['text'] = str_replace( + '
', $element['text']); + $element['text'] = preg_replace('/(<\/?p>)/', '', $element['text']); $template = ' - - -
' . $element['text'] . '
- - '; - + + + ' . $element['text'] . ' + + '; return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Image.php b/lib/Newsletter/Renderer/Blocks/Image.php index 92cc0b0327..77529f25ff 100644 --- a/lib/Newsletter/Renderer/Blocks/Image.php +++ b/lib/Newsletter/Renderer/Blocks/Image.php @@ -1,24 +1,42 @@ - - - - - '; - + + + ' . $element['alt'] . ' + + '; return $template; } + + static function getImageDimensions($element, $columnCount) { + $columnWidth = ColumnsHelper::$columnsWidth[$columnCount]; + $paddedWidth = StylesHelper::$paddingWidth * 2; + // resize image if it's wider than the column width + if ((int) $element['width'] >= $columnWidth) { + $ratio = (int) $element['width'] / $columnWidth; + $element['width'] = $columnWidth; + $element['height'] = ceil((int) $element['height'] / $ratio); + } + if ($element['padded'] === true && $element['width'] >= $columnWidth) { + // resize image if the padded option is on + $ratio = (int) $element['width'] / ((int) $element['width'] - $paddedWidth); + $element['width'] = (int) $element['width'] - $paddedWidth; + $element['height'] = ceil((int) $element['height'] / $ratio); + $element['paddedClass'] = 'mailpoet_padded'; + } else { + $element['width'] = (int) $element['width']; + $element['height'] = (int) $element['height']; + $element['paddedClass'] = ''; + } + return $element; + } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Renderer.php b/lib/Newsletter/Renderer/Blocks/Renderer.php index 3db1285863..51588af3a9 100644 --- a/lib/Newsletter/Renderer/Blocks/Renderer.php +++ b/lib/Newsletter/Renderer/Blocks/Renderer.php @@ -1,11 +1,12 @@ -createElementFromBlockType($block); + function render($data, $columnCount) { + array_map(function ($block) use (&$blockContent, &$columns, $columnCount) { + $blockContent .= $this->createElementFromBlockType($block, $columnCount); if(isset($block['blocks'])) { - $blockContent = $this->render($block); + $blockContent = $this->render($block, $columnCount); } // vertical orientation denotes column container if($block['type'] === 'container' && $block['orientation'] === 'vertical') { @@ -16,9 +17,9 @@ class Renderer { return (isset($columns)) ? $columns : $blockContent; } - function createElementFromBlockType($block) { + function createElementFromBlockType($block, $columnCount) { $blockClass = __NAMESPACE__ . '\\' . ucfirst($block['type']); - return (class_exists($blockClass)) ? $blockClass::render($block) : ''; + return (class_exists($blockClass)) ? $blockClass::render($block, $columnCount) : ''; } } diff --git a/lib/Newsletter/Renderer/Blocks/Social.php b/lib/Newsletter/Renderer/Blocks/Social.php index 241e4cca84..0eeebe1c57 100644 --- a/lib/Newsletter/Renderer/Blocks/Social.php +++ b/lib/Newsletter/Renderer/Blocks/Social.php @@ -1,26 +1,26 @@ - $icon) { $iconsBlock .= ' -
- ' . $icon['iconType'] . ' - - '; + + ' . $icon['iconType'] . ' + '; + if ($index !== count($element['icons']) - 1) $iconsBlock .= ''; } + $template = ' + + +
+ ' . $iconsBlock . ' +
+ + '; + return $template; } - - $template = ' - - -
' . $iconsBlock . '
- - '; - - return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Spacer.php b/lib/Newsletter/Renderer/Blocks/Spacer.php index f950264970..c19336a592 100644 --- a/lib/Newsletter/Renderer/Blocks/Spacer.php +++ b/lib/Newsletter/Renderer/Blocks/Spacer.php @@ -1,23 +1,12 @@ - - - '; - + + + '; return $template; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Blocks/Text.php b/lib/Newsletter/Renderer/Blocks/Text.php index 7aa62475f2..8665756f1c 100644 --- a/lib/Newsletter/Renderer/Blocks/Text.php +++ b/lib/Newsletter/Renderer/Blocks/Text.php @@ -1,114 +1,110 @@ - "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); - + $html = self::addLineBreakAfterTags($html); + $html = self::styleLists($html); + $html = self::styleHeadings($html); + $html = self::removeLastElementBreakLine($html); $template = ' - - ' . $html . ' - '; - + + + ' . $html . ' + + '; return $template; } - static function removeLastBreakLine($html) { - return preg_replace('/
([^
]*)$/s', '', $html); - } - static function convertParagraphsToTables($html) { $html = preg_replace('/

(.*?)<\/p>/', ' - - - + +
- + + + - -
$1 - -
', $html); - - return preg_replace('/(.*?)<\/p>/', ' - - - + +
- +

+
' + , $html); + $html = preg_replace('/

(.*?)<\/p>/', ' + + + - -
$2 - -
', $html); +

+

' + , $html); + return $html; } - - static function convertEmptyParagraphsToLineBreaks($html) { - return preg_replace('/<\/p>/', '
', $html); + + + static function removeLastElementBreakLine($html) { + return preg_replace('/([^]*)$/s', '', $html); } - + static function addLineBreakAfterTags($html) { - return preg_replace('/(<\/(ul|ol|h\d)>)/', '$1
', $html); + return preg_replace('/(<\/(ul|ol|h\d)>)/', '$1
', $html); } - + static function convertBlockquotesToTables($html) { $template = ' - - - - - - -
$1
-
'; - - return preg_replace('/

(.*?)<\/blockquote>/s', $template, $html); + + + + + + + + +
+ + + + +
+ $1 +
+
+
'; + preg_match('/
.*?<\/blockquote>/s', $html, $blockquotes); + foreach ($blockquotes as $index => $blockquote) { + $blockquote = preg_replace('/<\/p>\n

/', '

', $blockquote); + $blockquote = preg_replace('/<\/?p>/', '', $blockquote); + $blockquote = preg_replace( + '/

(.*?)<\/blockquote>/s', + $template, + $blockquote + ); + $html = preg_replace( + '/' . preg_quote($blockquotes[$index], '/') . '/', + $blockquote, + $html + ); + } + return $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 - )*+ - # closing tag - ) # end of the group 1 - ) - ~sxi -EOD; - - return preg_replace($pattern, '', $html); + + static function styleHeadings($html) { + return preg_replace( + '/<(h[1-6])(?:.+style=\"(.*)?\")?>/', + '<$1 style="margin:0;font-style:normal;font-weight:normal;$2">', + $html + ); + } + + static function styleLists($html) { + $html = preg_replace( + '/<(ul|ol)>/', + '<$1 class="mailpoet_paragraph" style="padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;">', + $html + ); + $html = preg_replace('/
  • /', '
  • ', $html); + return $html; } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Columns/ColumnsHelper.php b/lib/Newsletter/Renderer/Columns/ColumnsHelper.php new file mode 100644 index 0000000000..b02b534b7b --- /dev/null +++ b/lib/Newsletter/Renderer/Columns/ColumnsHelper.php @@ -0,0 +1,22 @@ + 660, + 2 => 330, + 3 => 220 + ); + + static $columnsClass = array( + 1 => 'cols-one', + 2 => 'cols-two', + 3 => 'cols-three' + ); + + static $columnsAlignment = array( + 1 => null, + 2 => 'left', + 3 => 'right' + ); +} \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Columns/Renderer.php b/lib/Newsletter/Renderer/Columns/Renderer.php index 975d9bba02..927ce2be6d 100644 --- a/lib/Newsletter/Renderer/Columns/Renderer.php +++ b/lib/Newsletter/Renderer/Columns/Renderer.php @@ -1,76 +1,79 @@ - 600, - 2 => 300, - 3 => 200 - ); + function render($columnStyles, $columnsCount, $columnsData) { + $styles = $columnStyles['block']; - 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 = ' - - - - - - + + '; + return $template; + } - // close column container - $columnContainerTemplate .= ' - -
    - '; - - $columnOpenTemplate = ' - - '; - - $columnCloseTemplate = ' - -
    - '; - - foreach ($columnsData as $index => $columnData) { - $index++; - $columnContainerTemplate .= $columnOpenTemplate . $columnData; - if($columnsCount > 1 && $index != $columnsCount) { - $columnContainerTemplate .= $columnCloseTemplate; - } + $width = ColumnsHelper::$columnsWidth[$columnsCount]; + $class = ColumnsHelper::$columnsClass[$columnsCount]; + $alignment = ColumnsHelper::$columnsAlignment[$columnsCount]; + $template = ($columnsCount === 1) ? + $this->getOneColumnTemplate($styles, $class) : + $this->getMultipleColumnsTemplate($styles, $width, $alignment, $class); + $result = array_map(function ($content) use ($template) { + return $template['contentStart'] . $content . $template['contentEnd']; + }, $columnsData); + $result = implode('', $result); + if ($columnsCount !== 1) { + $result = $template['containerStart'] . $result . $template['containerEnd']; } + return $result; + } + + function getOneColumnTemplate($styles, $class) { + $template['contentStart'] = ' +
    + + + + + + +
    + + '; + $template['contentEnd'] = ' + +
    +
    +
    - - - + function getMultipleColumnsTemplate($styles, $width, $alignment, $class) { + $template['containerStart'] = ' + + + + + + + +
    + + '; + $template['contentEnd'] = ' + +
    +
    '; - - return $columnContainerTemplate; + return $template; } -} +} \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Renderer.php b/lib/Newsletter/Renderer/Renderer.php index e0d9ef3dc1..5fde9947ef 100644 --- a/lib/Newsletter/Renderer/Renderer.php +++ b/lib/Newsletter/Renderer/Renderer.php @@ -1,6 +1,7 @@ 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; @@ -17,51 +17,75 @@ class Renderer { function render() { $newsletterContent = $this->renderContent($this->data['content']); - $newsletterStyles = $this->renderStyles($this->data['globalStyles']); - + $newsletterStyles = $this->renderGlobalStyles($this->data['globalStyles']); + $newsletterTitle = ''; + $newsletterPreheader = ''; $renderedTemplate = $this->renderTemplate($this->template, array( + $newsletterTitle, $newsletterStyles, + $newsletterPreheader, $newsletterContent )); $renderedTemplateWithInlinedStyles = $this->inlineCSSStyles($renderedTemplate); - - return $this->postProcessRenderedTemplate($renderedTemplateWithInlinedStyles); + return $this->postProcessTemplate($renderedTemplateWithInlinedStyles); } function renderContent($content) { - $newsletterContent = array_map(function ($contentBlock) { + $content = array_map(function ($contentBlock) { $columnCount = count($contentBlock['blocks']); - $columnData = $this->blocksRenderer->render($contentBlock); - return $this->columnsRenderer->render($columnCount, $columnData); + $columnData = $this->blocksRenderer->render($contentBlock, $columnCount); + return $this->columnsRenderer->render( + $contentBlock['styles'], + $columnCount, + $columnData + ); }, $content['blocks']); - return implode('', $newsletterContent); + return implode('', $content); } - function renderStyles($styles) { - $newsletterStyles = ''; + function renderGlobalStyles($styles) { + $css = ''; foreach ($styles as $selector => $style) { switch ($selector) { + case 'h1': + $selector = 'h1'; + break; + case 'h2': + $selector = 'h2'; + break; + case 'h3': + $selector = 'h3'; + break; case 'text': - $selector = 'span.paragraph, ul, ol'; + $selector = '.mailpoet_paragraph'; break; case 'body': - $selector = '.mailpoet_content-wrapper'; + $selector = 'body, .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'; + $selector = '.mailpoet_content'; break; } - $newsletterStyles .= $selector . '{' . PHP_EOL; - foreach ($style as $attribute => $individualStyle) { - $newsletterStyles .= $this->stylesHelper->translateCSSAttribute($attribute) . ':' . $individualStyle . ';' . PHP_EOL; + if (isset($style['fontSize'])) { + $css .= StylesHelper::setFontAndLineHeight( + (int) $style['fontSize'], + $selector + ); + unset($style['fontSize']); } - $newsletterStyles .= '}' . PHP_EOL; + if (isset($style['fontFamily'])) { + $css .= StylesHelper::setFontFamily( + $style['fontFamily'], + $selector + ); + unset($style['fontFamily']); + } + $css .= StylesHelper::setStyle($style, $selector); } - - return $newsletterStyles; + return $css; } function renderTemplate($template, $data) { @@ -74,14 +98,11 @@ class Renderer { return $this->CSSInliner->inlineCSS(null, $template); } - function postProcessRenderedTemplate($template) { - // remove padding from last element inside each column + function postProcessTemplate($template) { + // replace all !important tags except for in the body tag $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'])); - } - + $lastColumnElement = $DOM->query('.mailpoet_template'); + $lastColumnElement->html(str_replace('!important', '', $lastColumnElement->html())); return $DOM->__toString(); } } \ No newline at end of file diff --git a/lib/Newsletter/Renderer/StylesHelper.php b/lib/Newsletter/Renderer/StylesHelper.php index 5ebc31febc..9c69aff497 100644 --- a/lib/Newsletter/Renderer/StylesHelper.php +++ b/lib/Newsletter/Renderer/StylesHelper.php @@ -1,7 +1,10 @@ - 'background-color', 'fontColor' => 'color', 'fontFamily' => 'font-family', @@ -14,26 +17,234 @@ class StylesHelper { 'borderRadius' => 'border-radius', 'lineHeight' => 'line-height' ); - - function getBlockStyles($element, $ignoreSpecificStyles = false) { - if(!isset($element['styles']['block'])) { + static $font = 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 $fontSize = array( + // fontSize => array(columnCount => lineHeight); + 8 => array( + 1 => "20", + 2 => "15", + 3 => "13" + ), + 9 => array( + 1 => "20", + 2 => "16", + 3 => "14" + ), + 10 => array( + 1 => "20", + 2 => "17", + 3 => "15" + ), + 11 => array( + 1 => "21", + 2 => "18", + 3 => "16" + ), + 12 => array( + 1 => "22", + 2 => "19", + 3 => "17" + ), + 13 => array( + 1 => "23", + 2 => "20", + 3 => "19" + ), + 14 => array( + 1 => "24", + 2 => "21", + 3 => "20" + ), + 15 => array( + 1 => "25", + 2 => "22", + 3 => "21" + ), + 16 => array( + 1 => "26", + 2 => "23", + 3 => "22" + ), + 17 => array( + 1 => "27", + 2 => "24", + 3 => "24" + ), + 18 => array( + 1 => "28", + 2 => "25", + 3 => "25" + ), + 19 => array( + 1 => "29", + 2 => "27", + 3 => "26" + ), + 20 => array( + 1 => "30", + 2 => "28", + 3 => "27" + ), + 21 => array( + 1 => "31", + 2 => "29", + 3 => "29" + ), + 22 => array( + 1 => "32", + 2 => "30", + 3 => "30" + ), + 23 => array( + 1 => "33", + 2 => "32", + 3 => "31" + ), + 24 => array( + 1 => "34", + 2 => "33", + 3 => "32" + ), + 25 => array( + 1 => "36", + 2 => "34", + 3 => "34" + ), + 26 => array( + 1 => "37", + 2 => "35", + 3 => "35" + ), + 27 => array( + 1 => "38", + 2 => "37", + 3 => "36" + ), + 28 => array( + 1 => "39", + 2 => "38", + 3 => "37" + ), + 29 => array( + 1 => "40", + 2 => "39", + 3 => "39" + ), + 30 => array( + 1 => "42", + 2 => "40", + 3 => "40" + ), + 31 => array( + 1 => "43", + 2 => "42", + 3 => "41" + ), + 32 => array( + 1 => "44", + 2 => "43", + 3 => "43" + ), + 33 => array( + 1 => "45", + 2 => "44", + 3 => "44" + ), + 34 => array( + 1 => "47", + 2 => "46", + 3 => "45" + ), + 35 => array( + 1 => "48", + 2 => "47", + 3 => "46" + ), + 36 => array( + 1 => "49", + 2 => "48", + 3 => "48" + ), + 37 => array( + 1 => "50", + 2 => "49", + 3 => "49" + ), + 38 => array( + 1 => "52", + 2 => "51", + 3 => "50" + ), + 39 => array( + 1 => "53", + 2 => "52", + 3 => "52" + ), + 40 => array( + 1 => "54", + 2 => "53", + 3 => "53" + ) + ); + static $paddingWidth = 20; + + static function getBlockStyles($element, $ignoreSpecificStyles = false) { + if (!isset($element['styles']['block'])) { return; } - - return $this->getStyles($element['styles'], 'block', $ignoreSpecificStyles); + return self::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;'; + + static function getStyles($data, $type, $ignoreSpecificStyles = false) { + $styles = array_map(function ($attribute, $style) use ($ignoreSpecificStyles) { + if (!$ignoreSpecificStyles || !in_array($attribute, $ignoreSpecificStyles)) { + return self::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; + + static function translateCSSAttribute($attribute) { + return (array_key_exists($attribute, self::$cssAttributesTable)) ? self::$cssAttributesTable[$attribute] : $attribute; } -} + + static function setFontFamily($fontFamily, $selector) { + $fontFamily = (isset(self::$font[$fontFamily])) ? + self::$font[$fontFamily] : + $fontFamily; + $css = $selector . '{' . PHP_EOL; + $css .= 'font-family:' . $fontFamily . ';' . PHP_EOL; + $css .= '}' . PHP_EOL; + return $css; + } + + static function setFontAndLineHeight($fontSize, $selector) { + $css = ''; + foreach (ColumnsHelper::$columnsClass as $columnCount => $columnClass) { + $css .= '.mailpoet_content-' . $columnClass . ' ' . $selector . '{' . PHP_EOL; + $css .= 'font-size:' . $fontSize . 'px;' . PHP_EOL; + $css .= 'line-height:' . StylesHelper::$fontSize[$fontSize][$columnCount] . 'px;' . PHP_EOL; + $css .= '}' . PHP_EOL; + } + return $css; + } + + static function setStyle($style, $selector) { + $css = $selector . '{' . PHP_EOL; + foreach ($style as $attribute => $individualStyle) { + $css .= self::translateCSSAttribute($attribute) . ':' . $individualStyle . ';' . PHP_EOL; + } + $css .= '}' . PHP_EOL; + return $css; + } +} \ No newline at end of file diff --git a/lib/Newsletter/Renderer/Template.html b/lib/Newsletter/Renderer/Template.html index 283b37326d..ae0f652cd1 100644 --- a/lib/Newsletter/Renderer/Template.html +++ b/lib/Newsletter/Renderer/Template.html @@ -1,266 +1,96 @@ - - MailPoet Newsletter Template + {{newsletter_title}} - - - } - - {{newsletter_editor_styles}} - - - - - - - -
    - - - - {{newsletter_editor_content}} - -
    - -
    + + + + + + + + + +
    {{newsletter_preheader}} +
    + + + + {{newsletter_content}} + +
    + +
    - + \ No newline at end of file diff --git a/lib/Util/CSS.php b/lib/Util/CSS.php index 25c439f795..d15347d0bb 100644 --- a/lib/Util/CSS.php +++ b/lib/Util/CSS.php @@ -366,7 +366,7 @@ class CSS { $node->style = self::arrayToStyle($style); // remove all !important tags (inlined styles take precedent over others anyway) - $node->style = str_replace("!important", "", $node->style); +// $node->style = str_replace("!important", "", $node->style); // I'm leaving this for debug purposes, it has proved useful. /* diff --git a/tests/unit/Newsletter/RendererCest.php b/tests/unit/Newsletter/RendererCest.php index 0aee956d6f..3e51badebf 100644 --- a/tests/unit/Newsletter/RendererCest.php +++ b/tests/unit/Newsletter/RendererCest.php @@ -13,7 +13,10 @@ use MailPoet\Newsletter\Renderer\Renderer; class NewsletterRendererCest { function __construct() { - $this->newsletterData = json_decode(file_get_contents(dirname(__FILE__) . '/RendererTestData.json'), true); + $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(); @@ -22,109 +25,228 @@ class NewsletterRendererCest { function itRendersCompleteNewsletter() { $template = $this->renderer->render(); $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); + // we expect to have 7 columns: + // 1x column including header + // 2x column + // 3x column + // 1x footer + expect(count($DOM('.mailpoet_cols-one')))->equals(2); + expect(count($DOM('.mailpoet_cols-two')))->equals(2); + expect(count($DOM('.mailpoet_cols-three')))->equals(3); } - function itRendersColumns() { + function itRendersOneColumn() { + $columnContent = array( + 'one' + ); + $columnStyles = array( + 'block' => array( + 'backgroundColor' => "#999999" + ) + ); + $DOM = $this->queryDOM->parseStr( + $this->columnRenderer->render( + $columnStyles, + count($columnContent), + $columnContent) + ); + foreach ($DOM('table.mailpoet_cols-one > tbody') as $column) { + $renderedColumnContent[] = trim($column->text()); + }; + expect($renderedColumnContent)->equals($columnContent); + } + + function itRendersTwoColumns() { + $columnContent = array( + 'one', + 'two' + ); + $columnStyles = array( + 'block' => array( + 'backgroundColor' => "#999999" + ) + ); + $DOM = $this->queryDOM->parseStr( + $this->columnRenderer->render( + $columnStyles, + count($columnContent), + $columnContent) + ); + foreach ($DOM('table.mailpoet_cols-two > tbody') as $column) { + $renderedColumnContent[] = trim($column->text()); + }; + expect($renderedColumnContent)->equals($columnContent); + } + + function itRendersThreeColumns() { $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) { + $columnStyles = array( + 'block' => array( + 'backgroundColor' => "#999999" + ) + ); + $DOM = $this->queryDOM->parseStr( + $this->columnRenderer->render( + $columnStyles, + count($columnContent), + $columnContent) + ); + foreach ($DOM('table.mailpoet_cols-three > tbody') as $column) { $renderedColumnContent[] = trim($column->text()); }; - expect(count(array_diff($renderedColumnContent, $columnContent)))->equals(0); + expect($renderedColumnContent)->equals($columnContent); } 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 , and

    elements - expect(is_object($DOM('tr > td > p', 0)))->true(); - expect(is_object($DOM('tr > td > p > a', 0)))->true(); + // element should be proplerly nested, and styles should be applied + expect(!empty($DOM('tr > td.mailpoet_header', 0)->html()))->true(); + expect(!empty($DOM('tr > td > a', 0)->html()))->true(); expect($DOM('a', 0)->attr('style'))->notEmpty(); - expect($DOM('p', 0)->attr('style'))->notEmpty(); + expect($DOM('td', 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 - 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(); + $DOM = $this->queryDOM->parseStr(Image::render($template, $columnCount = 1)); + // 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(); } + function itAdjustImageSizeBasedOnColumnWidth() { + $template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][1]; + $template['width'] = '800px'; + $DOM = $this->queryDOM->parseStr(Image::render($template, $columnCount = 2)); + // 800px resized to 330px (2-column layout) and 40px padding applied + expect($DOM('tr > td > img', 0)->attr('width'))->equals(290); + $template['width'] = '280px'; + $DOM = $this->queryDOM->parseStr(Image::render($template, $columnCount = 2)); + // 280px image should not be resized and padding should not be applied + expect($DOM('tr > td > img', 0)->attr('width'))->equals(280); + } + + function itRendersText() { $template = $this->newsletterData['content']['blocks'][0]['blocks'][0]['blocks'][2]; $DOM = $this->queryDOM->parseStr(Text::render($template)); - + //!d($DOM->__toString());exit; // 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(); + expect( + !empty($DOM('tr > td > table > tr > td.mailpoet_paragraph', 0)->html()) + )->true(); + expect( + !empty($DOM('tr > td > table > tr > td.mailpoet_blockquote', 0)->html() + ))->true(); + // ul/ol/li should have mailpoet_paragraph class added & styles applied + expect( + !empty( + $DOM('tr > td > ul.mailpoet_paragraph > li.mailpoet_paragraph', 0)->html() + ) + )->true(); + expect( + !empty( + $DOM('tr > td > ol.mailpoet_paragraph > li.mailpoet_paragraph', 0)->html() + ) + )->true(); + expect($DOM('tr > td.mailpoet_text > ul.mailpoet_paragraph', 0)->attr('style')) + ->contains('padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;'); + // headings should be styled + expect($DOM('tr > td.mailpoet_text > h1', 0)->attr('style')) + ->contains('margin:0;font-style:normal;font-weight:normal;'); + } 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); + expect( + preg_match( + '/border-top-width: 3px/', + $DOM('tr > td.mailpoet_divider > table > tr > td.mailpoet_divider-cell', 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); + expect($DOM('tr > td.mailpoet_spacer', 0)->attr('height'))->equals(50); } 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); + expect( + !empty($DOM('tr > td > div > table > tr > td > a.mailpoet_button', 0)->html()) + )->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 > div > table > tr > td', 0)->text()) + )->equals(1); + expect( + preg_match( + '/style="height:30px.*?width:100px/', + $DOM('tr > td > div > table > tr > td', 0)->text()) + )->equals(1); + expect( + preg_match( + '/style="color:#ffffff.*?font-family:Arial.*?font-size:14px/', + $DOM('tr > td > div > table > tr > td', 0)->text()) + )->equals(1); + expect( + preg_match( + '/fillcolor="#666666/', + $DOM('tr > td > 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(); + // element should be properly nested, contain social icons and + // image source/link href/alt should be properly set + expect(!empty($DOM('tr > td > div.mailpoet_social-icon', 0)->html()))->true(); + expect($DOM('a', 0)->attr('href'))->equals('http://example.com'); + expect($DOM('div > a:nth-of-type(10) > img')->attr('src'))->contains('custom.png'); + expect($DOM('div > a:nth-of-type(10) > img')->attr('alt'))->equals('custom'); + // there should be 10 icons and 19 spacer images 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'); + expect(count($DOM('img')))->equals(19); } 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 , and

    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(); + // element should be proplerly nested, and styles should be applied + expect(!empty($DOM('tr > td.mailpoet_footer', 0)->html()))->true(); + expect(!empty($DOM('tr > td > a', 0)->html()))->true(); expect($DOM('a', 0)->attr('style'))->notEmpty(); - expect($DOM('p', 0)->attr('style'))->notEmpty(); + expect($DOM('td', 0)->attr('style'))->notEmpty(); + } + + function itPostProcessesTemplate() { + $template = $this->renderer->render(); + // !important should be stripped from everywhere except from + // with the