From eaef00da6491b4a3ed6a03f64731ff00d4fe9fde Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Tue, 28 Jan 2020 20:43:47 +0000 Subject: [PATCH] Unbound lists are made empty (#127) * Isolate bug for #126 * Update tests to use latest DOM release * Tidy up template next/prev sibling usage * Assert nested lists are emptied with no data * Assert nested lists are emptied with empty nested data Closes #126 --- composer.lock | 26 ++++++++++---------- src/DocumentFragment.php | 30 +++++++---------------- src/HTMLDocument.php | 10 ++++---- src/TemplateParent.php | 26 +++++++++++++------- test/unit/Helper/Helper.php | 20 ++++++++++++++++ test/unit/TemplateParentTest.php | 41 ++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 47 deletions(-) diff --git a/composer.lock b/composer.lock index 723285a..375224d 100644 --- a/composer.lock +++ b/composer.lock @@ -1,7 +1,7 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], "content-hash": "c07f070d57106e34d9309d88fa29f50d", @@ -239,16 +239,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { @@ -283,7 +283,7 @@ "object", "object graph" ], - "time": "2019-12-15T19:12:40+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "phar-io/manifest", @@ -540,24 +540,24 @@ }, { "name": "phpspec/prophecy", - "version": "1.10.1", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc", - "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { "phpspec/phpspec": "^2.5 || ^3.2", @@ -599,7 +599,7 @@ "spy", "stub" ], - "time": "2019-12-22T21:05:45+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/src/DocumentFragment.php b/src/DocumentFragment.php index 75fa212..8c83dfe 100644 --- a/src/DocumentFragment.php +++ b/src/DocumentFragment.php @@ -16,23 +16,23 @@ class DocumentFragment extends BaseDocumentFragment { /** @var BaseElement */ public $templateParentNode; /** @var BaseElement */ - public $templateNextSibling; + public $templateNextElementSibling; /** @var BaseElement */ - public $templatePreviousSibling; + public $templatePreviousElementSibling; /** * @param BaseNode $parentNode - * @param BaseNode $nextSibling - * @param BaseNode $previousSibling + * @param BaseNode $nextElementSibling + * @param BaseNode $previousElementSibling */ public function setTemplateProperties( $parentNode = null, - $nextSibling = null, - $previousSibling = null + $nextElementSibling = null, + $previousElementSibling = null ):void { $this->templateParentNode = $parentNode; - $this->templateNextSibling = $nextSibling; - $this->templatePreviousSibling = $previousSibling; + $this->templateNextElementSibling = $nextElementSibling; + $this->templatePreviousElementSibling = $previousElementSibling; } /** @@ -43,7 +43,7 @@ public function insertTemplate(DOMNode $insertInto = null) { if(is_null($insertInto)) { $insertInto = $this->templateParentNode; - $insertBefore = $this->templateNextSibling; + $insertBefore = $this->templateNextElementSibling; } if(is_null($insertInto)) { throw new TemplateHasNoParentException(); @@ -59,16 +59,4 @@ public function insertTemplate(DOMNode $insertInto = null) { return $inserted; } - - public function prop_get_templateNextSibling() { - return $this->templateNextSibling; - } - - public function prop_get_templatePreviousSibling() { - return $this->templatePreviousSibling; - } - - public function prop_get_templateParentNode() { - return $this->templateParentNode; - } } diff --git a/src/HTMLDocument.php b/src/HTMLDocument.php index 0104534..9519493 100644 --- a/src/HTMLDocument.php +++ b/src/HTMLDocument.php @@ -61,8 +61,8 @@ public function getNamedTemplate(string $name):?DocumentFragment { $clone = $fragment->cloneNode(true); $clone->setTemplateProperties( $fragment->templateParentNode, - $fragment->templateNextSibling, - $fragment->templatePreviousSibling + $fragment->templateNextElementSibling, + $fragment->templatePreviousElementSibling ); return $clone; @@ -105,8 +105,8 @@ public function getUnnamedTemplate( $clone = $fragment->cloneNode(true); $clone->setTemplateProperties( $fragment->templateParentNode, - $fragment->templateNextSibling, - $fragment->templatePreviousSibling + $fragment->templateNextElementSibling, + $fragment->templatePreviousElementSibling ); return $clone; @@ -120,7 +120,6 @@ public function getParentOfUnnamedTemplate( // Unnamed templates can't have sibling elements of the same path, otherwise // they would need to be named. Remove any index from the path. $path = preg_replace("/\[\d+\]/", "", $path); - $matches = []; $pathToReturn = null; foreach($this->templateFragmentMap as $name => $t) { @@ -149,6 +148,7 @@ public function getParentOfUnnamedTemplate( return null; } + /** @var Element[] $matchingElements */ $matchingElements = $this->xPath($pathToReturn); return $matchingElements[count($matchingElements) - 1]; } diff --git a/src/TemplateParent.php b/src/TemplateParent.php index 8d32c64..ae16189 100644 --- a/src/TemplateParent.php +++ b/src/TemplateParent.php @@ -24,8 +24,8 @@ public function extractTemplates(BaseElement $context = null):int { $name = $this->getTemplateNameFromElement($templateElement); $parentNode = $templateElement->parentNode; - $nextSibling = $templateElement->nextSibling; - $previousSibling = $templateElement->previousSibling; + $nextElementSibling = $templateElement->nextElementSibling; + $previousElementSibling = $templateElement->previousElementSibling; $templateNodePath = $templateElement->getNodePath(); $nestedTemplateElementList = $templateElement->querySelectorAll( @@ -45,8 +45,8 @@ public function extractTemplates(BaseElement $context = null):int { ); $fragment->setTemplateProperties( $parentNode, - $nextSibling, - $previousSibling + $nextElementSibling, + $previousElementSibling ); $fragment->expandComponents(); @@ -67,6 +67,10 @@ public function extractTemplates(BaseElement $context = null):int { $parentNode->removeChild($templateElement); } + if(count($parentNode->children) === 0) { + $parentNode->innerHTML = ""; + } + if($name[0] !== "/") { $templateElement->classList->add("t-$name"); } @@ -88,11 +92,17 @@ public function getTemplate( string $templateDirectory = null, bool $addTemplatePrefix = true ):DocumentFragment { + /** @var Element $element */ + $element = $this; + /** @var HTMLDocument $rootDocument */ - $rootDocument = $this->getRootDocument(); + $rootDocument = $element->getRootDocument(); if(is_null($name)) { - $docTemplate = $rootDocument->getUnnamedTemplate($this, false); + $docTemplate = $rootDocument->getUnnamedTemplate( + $element, + false + ); } else { $docTemplate = $rootDocument->getNamedTemplate($name); @@ -102,7 +112,7 @@ public function getTemplate( } if(is_null($templateDirectory)) { - $templateDirectory = $this->componentDirectory; + $templateDirectory = $element->componentDirectory; } if(is_dir($templateDirectory)) { @@ -115,7 +125,7 @@ public function getTemplate( $fileName = strtok($fileName, "."); if($name === $fileName) { - $component = $this->loadComponent( + $component = $element->loadComponent( $name, dirname($fileInfo->getRealPath()) ); diff --git a/test/unit/Helper/Helper.php b/test/unit/Helper/Helper.php index 31fb60a..a5540d9 100644 --- a/test/unit/Helper/Helper.php +++ b/test/unit/Helper/Helper.php @@ -356,6 +356,26 @@ class Helper { HTML; + const HTML_NESTED_LIST = << + +Nested list +
+ +
+HTML; + + const HTML_PARENT_HAS_DATA_BIND_ATTR = << diff --git a/test/unit/TemplateParentTest.php b/test/unit/TemplateParentTest.php index 9da4616..fe45750 100644 --- a/test/unit/TemplateParentTest.php +++ b/test/unit/TemplateParentTest.php @@ -446,4 +446,45 @@ public function testTemplateWithinComponentIsAddedCorrectly() { self::assertCount(3, $componentElement->children); } + + public function testExtractTemplatesSetsParentInnerHTMLToEmpty() { + $document = new HTMLDocument(Helper::HTML_TODO_LIST); + $document->extractTemplates(); + $todoListElement = $document->getElementById("todo-list"); + self::assertEmpty($todoListElement->innerHTML); + } + + public function testExtractTemplatesSetsNestedParentInnerHTMLToEmpty() { + $document = new HTMLDocument(Helper::HTML_NESTED_LIST); + $document->extractTemplates(); + $outerListElement = $document->querySelector("ul"); + self::assertEmpty($outerListElement->innerHTML); + } + + public function testExtractTemplatesSetsNestedParentInnerHTMLPartiallyToEmpty() { + $document = new HTMLDocument(Helper::HTML_NESTED_LIST); + $document->extractTemplates(); + $outerListElement = $document->querySelector("ul"); + $document->bindNestedList([ + "Outer 1" => [ + "1:1" => [], + "1:2" => [], + "1:3" => [], + ], + "Outer 2" => [], + "Outer 3" => [ + "3:1" => [ + "Example" => (object)[ + "name" => "Here I am!" + ] + ], + "3:2" => [], + ], + ]); + + self::assertNotEmpty($outerListElement->innerHTML); + self::assertNotEmpty($outerListElement->querySelectorAll("ol")[0]->innerHTML); + self::assertNotEmpty($outerListElement->querySelectorAll("ol")[2]->innerHTML); + self::assertEmpty($outerListElement->querySelectorAll("ol")[1]->innerHTML); + } } \ No newline at end of file