Skip to content

Commit

Permalink
Auto closing tags if they allows only inline nodes as child nodes
Browse files Browse the repository at this point in the history
Fixes #68
  • Loading branch information
goetas committed Dec 14, 2014
1 parent c158103 commit 025f331
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/HTML5/Elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class Elements
*/
const BLOCK_TAG = 64;

/**
* Indicates that the tag allows only inline elements as child nodes.
*/
const BLOCK_ONLY_INLINE = 128;

/**
* The HTML5 elements as defined in http://dev.w3.org/html5/markup/elements.html.
*
Expand Down Expand Up @@ -120,7 +125,7 @@ class Elements
"head" => 1,
"header" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
"hgroup" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
"hr" => 73, // NORMAL | VOID_TAG | BLOCK_TAG
"hr" => 73, // NORMAL | VOID_TAG
"html" => 1,
"i" => 1,
"iframe" => 3, // NORMAL | TEXT_RAW
Expand All @@ -145,7 +150,7 @@ class Elements
"optgroup" => 1,
"option" => 1,
"output" => 65, // NORMAL | BLOCK_TAG
"p" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
"p" => 209, // NORMAL | AUTOCLOSE_P | BLOCK_TAG | BLOCK_ONLY_INLINE
"param" => 9, // NORMAL | VOID_TAG
"pre" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
"progress" => 1,
Expand Down
15 changes: 15 additions & 0 deletions src/HTML5/Parser/DOMTreeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ class DOMTreeBuilder implements EventHandler

protected $insertMode = 0;

/**
* Track if we are in an element that allows only inline child nodes
* @var string|null
*/
protected $onlyInline;

/**
* Quirks mode is enabled by default.
* Any document that is missing the
Expand Down Expand Up @@ -320,6 +326,11 @@ public function startTag($name, $attributes = array(), $selfClosing = false)
}
}

if ($this->onlyInline && Elements::isA($lname, Elements::BLOCK_TAG)) {
$this->autoclose($this->onlyInline);
$this->onlyInline = null;
}

try {
$prefix = ($pos = strpos($lname, ':')) ? substr($lname, 0, $pos) : '';

Expand All @@ -346,6 +357,10 @@ public function startTag($name, $attributes = array(), $selfClosing = false)
$ele = $this->doc->createElement('invalid');
}

if (Elements::isA($lname, Elements::BLOCK_ONLY_INLINE)) {
$this->onlyInline = $lname;
}

// When we add some namespacess, we have to track them. Later, when "endElement" is invoked, we have to remove them.
// When we are on a void tag, we do not need to care about namesapce nesting.
if ($pushes > 0 && !Elements::isA($name, Elements::VOID_TAG)) {
Expand Down
9 changes: 9 additions & 0 deletions test/HTML5/Parser/DOMTreeBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ public function testXmlNamespaceNesting()
$this->assertEquals("http://www.prefixed.com/bar5_x", $prefixed->namespaceURI);
}

public function testMoveNonInlineElements()
{
$doc = $this->parse('<p>line1<br/><hr/>line2</p>');
$this->assertEquals('<html xmlns="http://www.w3.org/1999/xhtml"><p>line1<br/></p><hr/>line2</html>', $doc->saveXML($doc->documentElement), 'Move non-inline elements outside of inline containers.');

$doc = $this->parse('<p>line1<div>line2</div></p>');
$this->assertEquals('<html xmlns="http://www.w3.org/1999/xhtml"><p>line1</p><div>line2</div></html>', $doc->saveXML($doc->documentElement), 'Move non-inline elements outside of inline containers.');
}

public function testAttributes()
{
$html = "<!DOCTYPE html>
Expand Down

0 comments on commit 025f331

Please sign in to comment.