Skip to content

Commit

Permalink
Merge pull request MyIntervals#85 from jdchmiel/master
Browse files Browse the repository at this point in the history
Prevent incorrectly capitalized CSS selectors from being stripped
  • Loading branch information
oliverklee committed Jun 19, 2014
2 parents 0817486 + ccd31b7 commit 17eb967
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 59 deletions.
60 changes: 36 additions & 24 deletions Classes/Emogrifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,42 +315,27 @@ function (array $m) {

foreach ($this->caches[self::CACHE_KEY_CSS][$cssKey] as $value) {
// query the body for the xpath selector
$nodesMatchingCssSelectors = $xpath->query($this->translateCssToXpath(trim($value['selector'])));
$nodesMatchingCssSelectors = $xpath->query($this->translateCssToXpath($value['selector']));

/** @var $node \DOMNode */
foreach ($nodesMatchingCssSelectors as $node) {
// if it has a style attribute, get it, process it, and append (overwrite) new stuff
if ($node->hasAttribute('style')) {
// break it up into an associative array
$oldStyleDeclarations = $this->parseCssDeclarationBlock($node->getAttribute('style'));
$newStyleDeclarations = $this->parseCssDeclarationBlock($value['attributes']);

// new styles overwrite the old styles (not technically accurate, but close enough)
$combinedArray = array_merge($oldStyleDeclarations, $newStyleDeclarations);
$style = '';
foreach ($combinedArray as $attributeName => $attributeValue) {
$style .= (strtolower($attributeName) . ':' . $attributeValue . ';');
}
} else {
// otherwise create a new style
$style = trim($value['attributes']);
$oldStyleDeclarations = array();
}
$node->setAttribute('style', $style);
$newStyleDeclarations = $this->parseCssDeclarationBlock($value['attributes']);
$node->setAttribute('style', $this->generateStyleStringFromDeclarationsArrays($oldStyleDeclarations, $newStyleDeclarations));
}
}

// now iterate through the nodes that contained inline styles in the original HTML
foreach ($this->styleAttributesForNodes as $nodePath => $styleAttributesForNode) {
$node = $this->visitedNodes[$nodePath];
$currentStyleAttributes = $this->parseCssDeclarationBlock($node->getAttribute('style'));

$combinedArray = array_merge($currentStyleAttributes, $styleAttributesForNode);
$style = '';
foreach ($combinedArray as $attributeName => $attributeValue) {
$style .= (strtolower($attributeName) . ':' . $attributeValue . ';');
}

$node->setAttribute('style', $style);
$node->setAttribute('style', $this->generateStyleStringFromDeclarationsArrays($currentStyleAttributes, $styleAttributesForNode));
}

// This removes styles from your email that contain display:none.
Expand Down Expand Up @@ -378,6 +363,26 @@ function (array $m) {
}
}


/**
* This method merges old or existing name/value array with new name/value array
* and then generates a string of the combined style suitable for placing inline.
* This becomes the single point for CSS string generation allowing for consistent
* CSS output no matter where the CSS originally came from.
* @param array $oldStyles
* @param array $newStyles
* @return string
*/
private function generateStyleStringFromDeclarationsArrays(array $oldStyles, array $newStyles) {
$combinedStyles = array_merge($oldStyles, $newStyles);
$style = '';
foreach ($combinedStyles as $attributeName => $attributeValue) {
$style .= (strtolower(trim($attributeName)) . ': ' . trim($attributeValue) . '; ');
}
return trim($style);
}


/**
* Copies the media part from CSS array parts to $xmlDocument.
*
Expand Down Expand Up @@ -591,11 +596,18 @@ private function getCssSelectorPrecedence($selector) {
*
* @see http://plasmasturm.org/log/444/
*
* @param string $cssSelector
* @param string $paramCssSelector
*
* @return string
*/
private function translateCssToXpath($cssSelector) {
private function translateCssToXpath($paramCssSelector) {
$cssSelector = ' ' . $paramCssSelector . ' ';
$cssSelector = preg_replace_callback('/\s+\w+\s+/',
function(array $matches) {
return strtolower($matches[0]);
},
$cssSelector
);
$cssSelector = trim($cssSelector);
$xpathKey = md5($cssSelector);
if (!isset($this->caches[self::CACHE_KEY_XPATH][$xpathKey])) {
Expand Down Expand Up @@ -779,10 +791,10 @@ private function parseCssDeclarationBlock($cssDeclarationBlock) {
$declarations = explode(';', $cssDeclarationBlock);
foreach ($declarations as $declaration) {
$matches = array();
if (!preg_match('/ *([a-z\\-]+) *: *([^;]+) */', $declaration, $matches)) {
if (!preg_match('/ *([A-Za-z\\-]+) *: *([^;]+) */', $declaration, $matches)) {
continue;
}
$propertyName = $matches[1];
$propertyName = strtolower($matches[1]);
$propertyValue = $matches[2];
$properties[$propertyName] = $propertyValue;
}
Expand Down
Loading

0 comments on commit 17eb967

Please sign in to comment.