Skip to content

Commit d26ef81

Browse files
committed
Add FIX_DUPLICATE_STYLES option to modify() to remove duplicate <style> tags.
1 parent 32c5ba7 commit d26ef81

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/HTML5DOMDocument.php

+28
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class HTML5DOMDocument extends \DOMDocument
5353
*/
5454
const OPTIMIZE_HEAD = 32;
5555

56+
/**
57+
* A modification (passed to modify()) that removes all but first styles with duplicate content.
58+
*/
59+
const FIX_DUPLICATE_STYLES = 64;
60+
5661
/**
5762
*
5863
* @var array
@@ -612,6 +617,7 @@ public function insertHTMLMulti(array $sources)
612617
* - HTML5DOMDocument::FIX_MULTIPLE_HEADS - merges multiple head elements.
613618
* - HTML5DOMDocument::FIX_MULTIPLE_BODIES - merges multiple body elements.
614619
* - HTML5DOMDocument::OPTIMIZE_HEAD - moves charset metatag and title elements first.
620+
* - HTML5DOMDocument::FIX_DUPLICATE_STYLES - removes all but first styles with duplicate content.
615621
*/
616622
public function modify($modifications = 0)
617623
{
@@ -621,6 +627,7 @@ public function modify($modifications = 0)
621627
$fixMultipleHeads = ($modifications & self::FIX_MULTIPLE_HEADS) !== 0;
622628
$fixMultipleBodies = ($modifications & self::FIX_MULTIPLE_BODIES) !== 0;
623629
$optimizeHead = ($modifications & self::OPTIMIZE_HEAD) !== 0;
630+
$fixDuplicateStyles = ($modifications & self::FIX_DUPLICATE_STYLES) !== 0;
624631

625632
/** @var \DOMNodeList<HTML5DOMElement> */
626633
$headElements = $this->getElementsByTagName('head');
@@ -696,6 +703,27 @@ public function modify($modifications = 0)
696703
}
697704
}
698705

706+
if ($fixDuplicateStyles) {
707+
$styles = $headElement->getElementsByTagName('style');
708+
if ($styles->length > 0) {
709+
$stylesToRemove = [];
710+
$list = [];
711+
foreach ($styles as $style) {
712+
$innerHTML = trim($style->innerHTML);
713+
if (array_search($innerHTML, $list) === false) {
714+
$list[] = $innerHTML;
715+
} else {
716+
$stylesToRemove[] = $style;
717+
}
718+
}
719+
foreach ($stylesToRemove as $styleToRemove) {
720+
$styleToRemove->parentNode->removeChild($styleToRemove);
721+
}
722+
unset($list);
723+
}
724+
unset($styles);
725+
}
726+
699727
if ($optimizeHead) { // Moves charset metatag and title elements first.
700728
$titleElement = $headElement->getElementsByTagName('title')->item(0);
701729
$hasTitleElement = false;

tests/Test.php

+19
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,25 @@ public function testDuplicateTags()
796796
. '<meta content="video.movie" property="og:type">'
797797
. '</head></html>';
798798
$this->assertEquals($expectedSource, $this->removeNewLines($dom->saveHTML()));
799+
800+
$dom = new HTML5DOMDocument();
801+
$dom->loadHTML('<!DOCTYPE html><html><head>'
802+
. '<style>body{color:red;}</style>'
803+
. '<style>body{color:red;}</style>'
804+
. '<style>div{color:blue;}</style>'
805+
. '<style>span{color:green;}</style>'
806+
. '<style>body{color:red;}</style>'
807+
. '</head></html>');
808+
$dom->insertHTML('<head>'
809+
. '<style>div{color:blue;}</style>'
810+
. '</head>');
811+
$dom->modify(HTML5DOMDocument::FIX_DUPLICATE_STYLES);
812+
$expectedSource = '<!DOCTYPE html><html><head>'
813+
. '<style>body{color:red;}</style>'
814+
. '<style>div{color:blue;}</style>'
815+
. '<style>span{color:green;}</style>'
816+
. '</head></html>';
817+
$this->assertEquals($expectedSource, $this->removeNewLines($dom->saveHTML()));
799818
}
800819

801820
/**

0 commit comments

Comments
 (0)