暂无描述

StylesHelper.php 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. namespace MailPoet\Newsletter\Renderer;
  3. if (!defined('ABSPATH')) exit;
  4. class StylesHelper {
  5. public static $cssAttributes = [
  6. 'backgroundColor' => 'background-color',
  7. 'fontColor' => 'color',
  8. 'fontFamily' => 'font-family',
  9. 'textDecoration' => 'text-decoration',
  10. 'textAlign' => 'text-align',
  11. 'fontSize' => 'font-size',
  12. 'fontWeight' => 'font-weight',
  13. 'borderWidth' => 'border-width',
  14. 'borderStyle' => 'border-style',
  15. 'borderColor' => 'border-color',
  16. 'borderRadius' => 'border-radius',
  17. 'lineHeight' => 'line-height',
  18. 'msoLineHeightAlt' => 'mso-line-height-alt',
  19. 'msoFontSize' => 'mso-ansi-font-size',
  20. ];
  21. public static $font = [
  22. 'Arial' => "Arial, 'Helvetica Neue', Helvetica, sans-serif",
  23. 'Comic Sans MS' => "'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif",
  24. 'Courier New' => "'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace",
  25. 'Georgia' => "Georgia, Times, 'Times New Roman', serif",
  26. 'Lucida' => "'Lucida Sans Unicode', 'Lucida Grande', sans-serif",
  27. 'Tahoma' => 'Tahoma, Verdana, Segoe, sans-serif',
  28. 'Times New Roman' => "'Times New Roman', Times, Baskerville, Georgia, serif",
  29. 'Trebuchet MS' => "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif",
  30. 'Verdana' => 'Verdana, Geneva, sans-serif',
  31. 'Arvo' => 'arvo, courier, georgia, serif',
  32. 'Lato' => "lato, 'helvetica neue', helvetica, arial, sans-serif",
  33. 'Lora' => "lora, georgia, 'times new roman', serif",
  34. 'Merriweather' => "merriweather, georgia, 'times new roman', serif",
  35. 'Merriweather Sans' => "'merriweather sans', 'helvetica neue', helvetica, arial, sans-serif",
  36. 'Noticia Text' => "'noticia text', georgia, 'times new roman', serif",
  37. 'Open Sans' => "'open sans', 'helvetica neue', helvetica, arial, sans-serif",
  38. 'Playfair Display' => "'playfair display', georgia, 'times new roman', serif",
  39. 'Roboto' => "roboto, 'helvetica neue', helvetica, arial, sans-serif",
  40. 'Source Sans Pro' => "'source sans pro', 'helvetica neue', helvetica, arial, sans-serif",
  41. 'Oswald' => "Oswald, 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif",
  42. 'Raleway' => "Raleway, 'Century Gothic', CenturyGothic, AppleGothic, sans-serif",
  43. 'Permanent Marker' => "'Permanent Marker', Tahoma, Verdana, Segoe, sans-serif",
  44. 'Pacifico' => "Pacifico, 'Arial Narrow', Arial, sans-serif",
  45. ];
  46. public static $customFonts = [
  47. 'Arvo',
  48. 'Lato',
  49. 'Lora',
  50. 'Merriweather',
  51. 'Merriweather Sans',
  52. 'Noticia Text',
  53. 'Open Sans',
  54. 'Playfair Display',
  55. 'Roboto',
  56. 'Source Sans Pro',
  57. 'Oswald',
  58. 'Raleway',
  59. 'Permanent Marker',
  60. 'Pacifico',
  61. ];
  62. public static $defaultLineHeight = 1.6;
  63. public static $headingMarginMultiplier = 0.3;
  64. public static $paddingWidth = 20;
  65. public static function getBlockStyles($element, $ignoreSpecificStyles = false) {
  66. if (!isset($element['styles']['block'])) {
  67. return;
  68. }
  69. return self::getStyles($element['styles'], 'block', $ignoreSpecificStyles);
  70. }
  71. public static function getStyles($data, $type, $ignoreSpecificStyles = false) {
  72. $styles = array_map(function($attribute, $style) use ($ignoreSpecificStyles) {
  73. if (!$ignoreSpecificStyles || !in_array($attribute, $ignoreSpecificStyles)) {
  74. $style = StylesHelper::applyFontFamily($attribute, $style);
  75. return StylesHelper::translateCSSAttribute($attribute) . ': ' . $style . ';';
  76. }
  77. }, array_keys($data[$type]), $data[$type]);
  78. return implode('', $styles);
  79. }
  80. public static function translateCSSAttribute($attribute) {
  81. return (array_key_exists($attribute, self::$cssAttributes)) ?
  82. self::$cssAttributes[$attribute] :
  83. $attribute;
  84. }
  85. public static function setStyle(array $style, string $selector): string {
  86. $css = $selector . '{' . PHP_EOL;
  87. $style = self::applyHeadingMargin($style, $selector);
  88. $style = self::applyLineHeight($style, $selector);
  89. foreach ($style as $attribute => $individualStyle) {
  90. $individualStyle = self::applyFontFamily($attribute, $individualStyle);
  91. $css .= self::translateCSSAttribute($attribute) . ':' . $individualStyle . ';' . PHP_EOL;
  92. }
  93. $css .= '}' . PHP_EOL;
  94. return $css;
  95. }
  96. public static function applyTextAlignment($block) {
  97. if (is_array($block)) {
  98. $textAlignment = isset($block['styles']['block']['textAlign']) ?
  99. strtolower($block['styles']['block']['textAlign']) :
  100. '';
  101. if (preg_match('/center|right|justify/i', $textAlignment)) {
  102. return $block;
  103. }
  104. $block['styles']['block']['textAlign'] = 'left';
  105. return $block;
  106. }
  107. return (preg_match('/text-align.*?[center|justify|right]/i', $block)) ?
  108. $block :
  109. $block . 'text-align:left;';
  110. }
  111. /**
  112. * Join styles and makes sure they are separated by ;
  113. */
  114. public static function joinStyles(?string $styles1, ?string $styles2): string {
  115. if ($styles1 === null) $styles1 = '';
  116. if ($styles2 === null) $styles2 = '';
  117. $style = trim($styles1);
  118. if (
  119. (strlen($style) > 0)
  120. && (substr($style, -1) !== ';')
  121. ) $style .= ';';
  122. $style .= $styles2;
  123. return $style;
  124. }
  125. public static function applyFontFamily($attribute, $style) {
  126. if ($attribute !== 'fontFamily') return $style;
  127. return (isset(self::$font[$style])) ?
  128. self::$font[$style] :
  129. self::$font['Arial'];
  130. }
  131. public static function applyHeadingMargin(array $style, string $selector): array {
  132. if (!preg_match('/h[1-4]/i', $selector)) return $style;
  133. $fontSize = (int)$style['fontSize'];
  134. $style['margin'] = sprintf('0 0 %spx 0', self::$headingMarginMultiplier * $fontSize);
  135. return $style;
  136. }
  137. public static function applyLineHeight(array $style, string $selector): array {
  138. if (!preg_match('/mailpoet_paragraph|h[1-4]/i', $selector)) return $style;
  139. $lineHeight = isset($style['lineHeight']) ? (float)$style['lineHeight'] : self::$defaultLineHeight;
  140. $fontSize = (int)$style['fontSize'];
  141. $msoLineHeight = round($lineHeight * $fontSize);
  142. if ($msoLineHeight % 2 === 1) {
  143. $msoLineHeight++;
  144. }
  145. $msoFontSize = $fontSize;
  146. if ($msoFontSize % 2 === 1) {
  147. $msoFontSize++;
  148. }
  149. $style['msoLineHeightAlt'] = sprintf('%spx', $msoLineHeight);
  150. $style = ['msoFontSize' => sprintf('%spx', $msoFontSize)] + $style;
  151. $style['lineHeight'] = sprintf('%spx', $lineHeight * $fontSize);
  152. return $style;
  153. }
  154. private static function getCustomFontsNames($styles) {
  155. $fontNames = [];
  156. foreach ($styles as $style) {
  157. if (isset($style['fontFamily']) && in_array($style['fontFamily'], self::$customFonts)) {
  158. $fontNames[$style['fontFamily']] = true;
  159. }
  160. }
  161. return array_keys($fontNames);
  162. }
  163. public static function getCustomFontsLinks($styles) {
  164. $links = [];
  165. foreach (self::getCustomFontsNames($styles) as $name) {
  166. $links[] = urlencode($name) . ':400,400i,700,700i';
  167. }
  168. if (!count($links)) {
  169. return '';
  170. }
  171. // see https://stackoverflow.com/a/48214207
  172. return '<!--[if !mso]><!-- --><link href="https://fonts.googleapis.com/css?family='
  173. . implode("|", $links)
  174. . '" rel="stylesheet"><!--<![endif]-->';
  175. }
  176. }