diff --git a/src/Templado.php b/src/Templado.php index 40dcd85..f1f4a55 100644 --- a/src/Templado.php +++ b/src/Templado.php @@ -8,6 +8,7 @@ class Templado { public static function loadHtmlFile(FileName $fileName): Html { libxml_use_internal_errors(true); $dom = new DOMDocument(); + $dom->preserveWhiteSpace = false; $tmp = $dom->load($fileName->asString()); if (!$tmp || libxml_get_last_error()) { throw new TempladoException( diff --git a/src/viewmodel/SnapshotDOMNodelist.php b/src/viewmodel/SnapshotDOMNodelist.php index 75c6e33..ea7baf4 100644 --- a/src/viewmodel/SnapshotDOMNodelist.php +++ b/src/viewmodel/SnapshotDOMNodelist.php @@ -11,7 +11,7 @@ * takes a snapshot of the list first and then turns that into an * iterator. */ -class SnapshotDOMNodelist implements Iterator { +class SnapshotDOMNodelist implements Iterator, \Countable { /** * @var DOMNode[] @@ -24,6 +24,10 @@ public function __construct(DOMNodeList $list) { $this->extractItemsFromNodeList($list); } + public function count() { + return count($this->items); + } + public function hasNode(DOMNode $node) { foreach($this->items as $pos => $item) { if ($item->isSameNode($node)) { @@ -38,22 +42,24 @@ public function removeNode(DOMNode $node) { foreach($this->items as $pos => $item) { if ($item->isSameNode($node)) { array_splice($this->items, $pos, 1); - + if ($pos <= $this->pos) { + $this->pos--; + } return; } } throw new SnapshotDOMNodelistException('Node not found in list'); } - public function current() { + public function current(): DOMNode { return $this->items[$this->pos]; } - public function next() { + public function next(): void { $this->pos++; } - public function key() { + public function key(): int { return $this->pos; } @@ -61,7 +67,7 @@ public function valid(): bool { return count($this->items) > $this->pos; } - public function rewind() { + public function rewind(): void { $this->pos = 0; } @@ -70,4 +76,14 @@ private function extractItemsFromNodeList(DOMNodeList $list) { $this->items[] = $item; } } + + public function hasNext(): bool { + return $this->pos < count($this->items); + } + + public function getNext(): DOMNode { + $node = $this->current(); + $this->next(); + return $node; + } } diff --git a/src/viewmodel/ViewModelRenderer.php b/src/viewmodel/ViewModelRenderer.php index 06d3ffa..be752eb 100644 --- a/src/viewmodel/ViewModelRenderer.php +++ b/src/viewmodel/ViewModelRenderer.php @@ -49,7 +49,9 @@ private function walk(DOMNode $context) { if ($context->hasChildNodes()) { $list = new SnapshotDOMNodelist($context->childNodes); $this->listStack[] = $list; - foreach($list as $pos => $childNode) { + + while($list->hasNext()) { + $childNode = $list->getNext(); /** @var \DOMNode $childNode */ $this->walk($childNode); } diff --git a/tests/issues/issue-#5/Issue5Test.php b/tests/issues/issue-#5/Issue5Test.php new file mode 100644 index 0000000..76e69f9 --- /dev/null +++ b/tests/issues/issue-#5/Issue5Test.php @@ -0,0 +1,23 @@ +applyViewModel(new Issue5_ViewData()); + + $this->assertXmlStringEqualsXmlString( + file_get_contents(__DIR__ . '/expected.html'), + $html->asString() + ); + + } +} + diff --git a/tests/issues/issue-#5/expected.html b/tests/issues/issue-#5/expected.html new file mode 100644 index 0000000..56af97a --- /dev/null +++ b/tests/issues/issue-#5/expected.html @@ -0,0 +1,18 @@ + + + + Title + + +
+
+
+ + + + +
+
+
+ + diff --git a/tests/issues/issue-#5/formTest.xhtml b/tests/issues/issue-#5/formTest.xhtml new file mode 100644 index 0000000..d5929d7 --- /dev/null +++ b/tests/issues/issue-#5/formTest.xhtml @@ -0,0 +1,22 @@ + + + + + Title + + + +
+
+
+ + + + +
+
+
+ + + + diff --git a/tests/issues/issue-#5/viewmodel.php b/tests/issues/issue-#5/viewmodel.php new file mode 100644 index 0000000..5c898a7 --- /dev/null +++ b/tests/issues/issue-#5/viewmodel.php @@ -0,0 +1,31 @@ +action = $action; + } + public function getFormaction() { + return $this->action; + } + + public function asString(): string { + return 'Changed action to: ' . $this->action; + } +} + +class Issue5_ViewData { + public function getButton1() { + return new Issue5_Button('/target1'); + } + public function getButton2() { + return new Issue5_Button('/target2'); + } + public function getButton3() { + return new Issue5_Button('/target3'); + } + public function getButton4() { + return new Issue5_Button('/target4'); + } +}