diff --git a/lib/DOM.php b/lib/DOM.php index caa0db6..725c8c9 100644 --- a/lib/DOM.php +++ b/lib/DOM.php @@ -9,7 +9,8 @@ class DOM { // Instance used to pass around the implementation and the document. PHP's DOM // cannot append a DOCTYPE to a DOMDocument, so the document must be created // when the DOCTYPE is. This creates a problem where the Parser sometimes needs - // an implementation before the TreeBuilder is initiated. + // an implementation before the TreeBuilder is initiated. This instance is used + // to work around that problem. public function __construct($document = null) { if (is_null($document)) { $this->implementation = new \DOMImplementation(); diff --git a/lib/Parser.php b/lib/Parser.php index 1213d5d..4deee2c 100644 --- a/lib/Parser.php +++ b/lib/Parser.php @@ -24,6 +24,8 @@ class Parser { protected $parseError; // The stack of open elements, uses Stack protected $stack; + // Used to store the template insertion modes + protected $templateInsertionModes; // Instance of the Tokenizer class used for creating tokens protected $tokenizer; // Instance of the TreeBuilder class used for building the document @@ -78,10 +80,14 @@ class Parser { // Initialize the stack of open elements. static::$instance->stack = new OpenElementsStack(static::$instance->fragmentCase, static::$instance->fragmentContext); + // Initialize the template insertion modes stack if necessary. + if (is_null(static::$instance->templateInsertionModes)) { + static::$instance->templateInsertionModes = new Stack(); + } // Initialize the tokenizer. static::$instance->tokenizer = new Tokenizer(static::$instance->data, static::$instance->stack); // Initialize the tree builder. - static::$instance->treeBuilder = new TreeBuilder(static::$instance->DOM, static::$instance->formElement, static::$instance->fragmentCase, static::$instance->fragmentContext, static::$instance->stack, static::$instance->tokenizer); + static::$instance->treeBuilder = new TreeBuilder(static::$instance->DOM, static::$instance->formElement, static::$instance->fragmentCase, static::$instance->fragmentContext, static::$instance->stack, static::$instance->templateInsertionModes, static::$instance->tokenizer); // Initialize the parse error handler. static::$instance->parseError = new ParseError(static::$instance->data); @@ -151,7 +157,10 @@ class Parser { # If the context element is a template element, push "in template" onto the # stack of template insertion modes so that it is the new current template # insertion mode. - // DEVIATION: No scripting. + if ($context instanceof \DOMelement && $context->nodeName === 'template') { + static::$templateInsertionModes = new Stack(); + static::$templateInsertionModes[] = TreeBuilder::IN_TEMPLATE_MODE; + } # Reset the parser's insertion mode appropriately. // DEVIATION: The insertion mode will be always 'in body', not 'before head' if diff --git a/lib/Stack.php b/lib/Stack.php index 2c8c598..0443956 100644 --- a/lib/Stack.php +++ b/lib/Stack.php @@ -2,7 +2,7 @@ declare(strict_types=1); namespace dW\HTML5; -abstract class Stack implements \ArrayAccess { +class Stack implements \ArrayAccess { protected $_storage = []; protected $fragmentCase; protected $fragmentContext; diff --git a/lib/TreeBuilder.php b/lib/TreeBuilder.php index 76ded6c..c5db58f 100644 --- a/lib/TreeBuilder.php +++ b/lib/TreeBuilder.php @@ -36,6 +36,8 @@ class TreeBuilder { protected $tokenizer; // Used to check if the document is in quirks mode protected $quirksMode; + // Used to store the template insertion modes + protected $templateInsertionModes; // Instance used with the static token insertion methods. @@ -73,7 +75,7 @@ class TreeBuilder { const QUIRKS_MODE_LIMITED = 2; - public function __construct(DOM $dom, $formElement, bool $fragmentCase = false, $fragmentContext = null, OpenElementsStack $stack, Tokenizer $tokenizer) { + public function __construct(DOM $dom, $formElement, bool $fragmentCase = false, $fragmentContext = null, OpenElementsStack $stack, Stack $templateInsertionModes, Tokenizer $tokenizer) { // If the form element isn't an instance of DOMElement that has a node name of // "form" or null then there's a problem. if (!is_null($formElement) && !($formElement instanceof DOMElement && $formElement->nodeName === 'form')) { @@ -94,6 +96,7 @@ class TreeBuilder { $this->fragmentCase = $fragmentCase; $this->fragmentContext = $fragmentContext; $this->stack = $stack; + $this->templateInsertionModes = $templateInsertionModes; $this->tokenizer = $tokenizer; // Initialize the list of active formatting elements. @@ -641,7 +644,7 @@ class TreeBuilder { $this->insertionMode = self::IN_TEMPLATE_MODE; # Push "in template" onto the stack of template insertion modes so that it is # the new current template insertion mode. - // DEVIATION: No scripting. + $this->templateInsertionModes = self::IN_TEMPLATE_MODE; } # A start tag whose tag name is "head" elseif ($token->name === 'head') { @@ -710,7 +713,7 @@ class TreeBuilder { $this->activeFormattingElementsList->clearToTheLastMarker(); # 5. Pop the current template insertion mode off the stack of template insertion modes. - // DEVIATION: No scripting. + $this->templateInsertionModes->pop(); # 6. Reset the insertion mode appropriately. $this->resetInsertionMode();