Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add HtmlPruner::removeRedundantClasses #708

Merged
merged 6 commits into from
Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## x.y.z

### Added
- Add `HtmlPruner::removeRedundantClasses`
([#380](https://github.com/MyIntervals/emogrifier/issues/380),
[#708](https://github.com/MyIntervals/emogrifier/pull/708))
- Support multiple attributes selectors
([#385](https://github.com/MyIntervals/emogrifier/issues/385),
[#721](https://github.com/MyIntervals/emogrifier/pull/721))
Expand Down
68 changes: 68 additions & 0 deletions src/Emogrifier/HtmlProcessor/HtmlPruner.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace Pelago\Emogrifier\HtmlProcessor;

use Pelago\Emogrifier\Utilities\ArrayIntersector;

/**
* This class can remove things from HTML.
*
* @author Oliver Klee <[email protected]>
* @author Jake Hotson <[email protected]>
*/
class HtmlPruner extends AbstractHtmlProcessor
{
Expand Down Expand Up @@ -41,4 +44,69 @@ public function removeElementsWithDisplayNone()

return $this;
}

/**
* Removes classes that are no longer required (e.g. because there are no longer any CSS rules that reference them)
* from `class` attributes.
*
* Note that this does not inspect the CSS, but expects to be provided with a list of classes that are still in use.
*
* This method also has the (presumably beneficial) side-effect of minifying (removing superfluous whitespace from)
* `class` attributes.
*
* @param string[] $classesToKeep names of classes that should not be removed
*
* @return self fluent interface
*/
public function removeRedundantClasses(array $classesToKeep = [])
{
$elementsWithClassAttribute = $this->xPath->query('//*[@class]');

if ($classesToKeep !== []) {
$this->removeClassesFromElements($elementsWithClassAttribute, $classesToKeep);
} else {
// Avoid unnecessary processing if there are no classes to keep.
$this->removeClassAttributeFromElements($elementsWithClassAttribute);
}

return $this;
}

/**
* Removes classes from the `class` attribute of each element in `$elements`, except any in `$classesToKeep`,
* removing the `class` attribute itself if the resultant list is empty.
*
* @param \DOMNodeList $elements
* @param string[] $classesToKeep
*
* @return void
*/
private function removeClassesFromElements(\DOMNodeList $elements, array $classesToKeep)
{
$classesToKeepIntersector = new ArrayIntersector($classesToKeep);

foreach ($elements as $element) {
$elementClasses = \preg_split('/\\s++/', \trim($element->getAttribute('class')));
$elementClassesToKeep = $classesToKeepIntersector->intersectWith($elementClasses);
if ($elementClassesToKeep !== []) {
$element->setAttribute('class', \implode(' ', $elementClassesToKeep));
} else {
$element->removeAttribute('class');
}
}
}

/**
* Removes the `class` attribute from each element in `$elements`.
*
* @param \DOMNodeList $elements
*
* @return void
*/
private function removeClassAttributeFromElements(\DOMNodeList $elements)
{
foreach ($elements as $element) {
$element->removeAttribute('class');
}
}
}
2 changes: 1 addition & 1 deletion src/Emogrifier/Utilities/ArrayIntersector.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct(array $array)
*
* @param (int|string)[] $array
*
* @return (int|string)[] Returns an array containing all of the values in `$array` whose values exist the array
* @return (int|string)[] Returns an array containing all of the values in `$array` whose values exist in the array
* with which this object was constructed. Note that keys are preserved, order is maintained, but
* duplicates are removed.
*/
Expand Down
Loading