self::ENGINE_EMOGRIFIER,
'cleanup' => true,
'responsive' => false, // If classes/ids should not be remove, only relevant for cleanup=>true
'useInlineStylesBlock' => true,
'debug' => false, // only cssToInline
'xhtmlOutput' => false, // only cssToInline
'removeCss' => true, // only cssToInline
'correctUtf8' => false // only cssToInline
];
public $config = [];
/**
* Inits with auto merged config.
*
* @param array $config
*/
public function __construct($config = []) {
$defaults = (array)Configure::read('InlineCss') + $this->_defaults;
$this->config = $config + $defaults;
if (!method_exists($this, '_process' . ucfirst($this->config['engine']))) {
throw new InternalErrorException('Engine does not exist: ' . $this->config['engine']);
}
}
/**
* Processes HTML and CSS.
*
* @param string $html
* @param string|null $css
* @return string Result
*/
public function process($html, $css = null) {
$html = trim($html);
if ($html === '') {
return $html;
}
$method = '_process' . ucfirst($this->config['engine']);
return $this->{$method}($html, $css);
}
/**
* @param string $html
* @param string $css
* @return string Result
*/
protected function _processEmogrifier($html, $css) {
if (class_exists('\Pelago\Emogrifier')) {
$Emogrifier = new \Pelago\Emogrifier($html, $css);
} else {
App::import('Vendor', 'Tools.Emogrifier', ['file' => 'Emogrifier/Emogrifier.php']);
$Emogrifier = new Emogrifier($html, $css);
}
if (method_exists($Emogrifier, 'enableCssToHtmlMapping')) {
$Emogrifier->enableCssToHtmlMapping();
}
if (method_exists($Emogrifier, 'disableInvisibleNodeRemoval')) {
$Emogrifier->disableInvisibleNodeRemoval();
}
$result = @$Emogrifier->emogrify();
if ($this->config['cleanup']) {
// Remove comments and whitespace
$result = preg_replace('//', '', $result);
//$result = preg_replace( '/\s\s+/', '\s', $result);
// Result classes and ids
if (!$this->config['responsive']) {
$result = preg_replace('/\bclass="[^"]*"/', '', $result);
$result = preg_replace('/\bid="[^"]*"/', '', $result);
}
}
return $result;
}
/**
* Process css blocks to inline css
* Also works for html snippets (without )
*
* @param string $html
* @param string $css
* @return string HTML output
*/
protected function _processCssToInline($html, $css) {
App::import('Vendor', 'Tools.CssToInlineStyles', ['file' => 'CssToInlineStyles' . DS . 'CssToInlineStyles.php']);
//fix issue with being added
$separator = '~~~~~~~~~~~~~~~~~~~~';
if (strpos($html, 'config['cleanup']) {
$CssToInlineStyles->setCleanup();
}
if ($this->config['useInlineStylesBlock']) {
$CssToInlineStyles->setUseInlineStylesBlock();
}
if ($this->config['removeCss']) {
$CssToInlineStyles->setStripOriginalStyleTags();
}
if ($this->config['correctUtf8']) {
$CssToInlineStyles->setCorrectUtf8();
}
if ($this->config['debug']) {
CakeLog::write('css', $html);
}
$html = $CssToInlineStyles->convert($this->config['xhtmlOutput']);
if ($this->config['removeCss']) {
$html = $this->stripOnly($html, ['style', 'script'], true);
}
if (!empty($incomplete)) {
$html = substr($html, strpos($html, $separator) + 20);
$html = substr($html, 0, strpos($html, $separator));
$html = trim($html);
}
return $html;
}
/**
* Some reverse function of strip_tags with blacklisting instead of whitelisting
* //maybe move to Tools.Utility/String/Text?
*
* @param string $str
* @param array|string $tags
* @param bool $stripContent
* @return string Cleaned string
*/
public function stripOnly($str, $tags, $stripContent = false) {
$content = '';
if (!is_array($tags)) {
$tags = (strpos($str, '>') !== false ? explode('>', str_replace('<', '', $tags)) : [$tags]);
if (end($tags) === '') {
array_pop($tags);
}
}
foreach ($tags as $tag) {
if ($stripContent) {
$content = '(.+' . $tag . '[^>]*>|)';
}
$str = preg_replace('#?' . $tag . '[^>]*>' . $content . '#is', '', $str);
}
return $str;
}
/**
* _extractAndRemoveCss - extracts any CSS from the rendered view and
* removes it from the $html
*
* @param string $html
* @return string
*/
protected function _extractAndRemoveCss($html) {
$css = null;
$DOM = new DOMDocument();
$DOM->loadHTML($html);
// DOM removal queue
$removeDoms = [];
// catch style sheet content
$links = $DOM->getElementsByTagName('link');
foreach ($links as $link) {
if ($link->hasAttribute('href') && preg_match("/\\.css$/i", $link->getAttribute('href'))) {
// find the css file and load contents
if ($link->hasAttribute('media')) {
// FOR NOW
continue;
foreach ($this->mediaTypes as $cssLinkMedia) {
if (strstr($link->getAttribute('media'), $cssLinkMedia)) {
$css .= $this->_findAndLoadCssFile($link->getAttribute('href')) . "\n\n";
$removeDoms[] = $link;
}
}
} else {
$css .= $this->_findAndLoadCssFile($link->getAttribute('href')) . "\n\n";
$removeDoms[] = $link;
}
}
}
// Catch embedded