diff --git a/lib/HTMLCollection.php b/lib/HTMLCollection.php index 6ae41f3..eb8aa81 100644 --- a/lib/HTMLCollection.php +++ b/lib/HTMLCollection.php @@ -43,10 +43,43 @@ class HTMLCollection extends Collection { } public function offsetGet($offset): ?Element { - return (is_int($offset)) ? $this->item($offset) : $this->namedItem($offset); + if (is_int($offset)) { + return $this->item($offset); + } + + # The supported property names are the values from the list returned by these + # steps: + # 1. Let result be an empty list. + # 2. For each element represented by the collection, in tree order: + # 1. If element has an ID which is not in result, append element’s ID to + # result. + # 2. If element is in the HTML namespace and has a name attribute whose value is + # neither the empty string nor is in result, append element’s name attribute value + # to result. + # 3. Return result. + // The spec is extremely vague as to what to do here, but it seems to expect + // this to be some sort of live private property that the class will poll to + // check for valid property names when trying to access them. This is + // inefficient. Going to do basically the same thing but not return a list of + // every one. It will just search the list instead using the same process. + + $document = $this->innerDocument->wrapperNode; + foreach ($this->innerCollection as $node) { + if ($node->getAttribute('id') === $offset) { + return $this->innerDocument->getWrapperNode($node); + } + } + + foreach ($this->innerCollection as $node) { + if (!$document instanceof XMLDocument && $node->namespaceURI === null && $node->getAttribute('name') === $offset) { + return $this->innerDocument->getWrapperNode($node); + } + } + + return null; } public function offsetExists($offset): bool { - return (((is_int($offset)) ? $this->item($offset) : $this->namedItem($offset)) !== null); + return ($this->offsetGet($offset) !== null); } } \ No newline at end of file diff --git a/lib/NamedNodeMap.php b/lib/NamedNodeMap.php index bc812d2..19c69f4 100644 --- a/lib/NamedNodeMap.php +++ b/lib/NamedNodeMap.php @@ -56,8 +56,6 @@ class NamedNodeMap extends Collection { # A NamedNodeMap object’s supported property names are the return value of running # these steps: - # 1. Let names be the qualified names of the attributes in this NamedNodeMap object’s - # attribute list, with duplicates omitted, in order. // The spec is extremely vague as to what to do here, but it seems to expect // this to be some sort of live private property that the class will poll to // check for valid property names when trying to access them. This is @@ -65,6 +63,8 @@ class NamedNodeMap extends Collection { // every one. It will just search the element's attribute list instead using the // same process. + # 1. Let names be the qualified names of the attributes in this NamedNodeMap object’s + # attribute list, with duplicates omitted, in order. # 2. If this NamedNodeMap object’s element is in the HTML namespace and its node # document is an HTML document, then for each name in names: # 1. Let lowercaseName be name, in ASCII lowercase. @@ -105,7 +105,7 @@ class NamedNodeMap extends Collection { } public function offsetExists($offset): bool { - return (((is_int($offset)) ? $this->item($offset) : $this->getNamedItem($offset)) !== null); + return ($this->offsetGet($offset) !== null); } public function removeNamedItem(string $qualifiedName): ?Attr { diff --git a/tests/cases/TestHTMLCollection.php b/tests/cases/TestHTMLCollection.php new file mode 100644 index 0000000..a786f6c --- /dev/null +++ b/tests/cases/TestHTMLCollection.php @@ -0,0 +1,126 @@ + + + +
Ook
+
Eek
+
Ack
+
Ook
+
poop💩
+ + + HTML, 'UTF-8'); + $body = $d->body; + + $children = $body->children; + foreach ($children as $key => $child) { + $this->assertTrue($child instanceof Element); + } + } + + + /** + * @covers \MensBeam\HTML\DOM\HTMLCollection::namedItem + * @covers \MensBeam\HTML\DOM\HTMLCollection::offsetGet + * + * @covers \MensBeam\HTML\DOM\CharacterData::__get_data + * @covers \MensBeam\HTML\DOM\Collection::__construct + * @covers \MensBeam\HTML\DOM\Document::__construct + * @covers \MensBeam\HTML\DOM\Document::__get_body + * @covers \MensBeam\HTML\DOM\Document::load + * @covers \MensBeam\HTML\DOM\DOMImplementation::__construct + * @covers \MensBeam\HTML\DOM\Element::__construct + * @covers \MensBeam\HTML\DOM\Node::__construct + * @covers \MensBeam\HTML\DOM\Node::__get_firstChild + * @covers \MensBeam\HTML\DOM\Node::getInnerDocument + * @covers \MensBeam\HTML\DOM\Node::hasChildNodes + * @covers \MensBeam\HTML\DOM\Node::postParsingTemplatesFix + * @covers \MensBeam\HTML\DOM\ParentNode::__get_children + * @covers \MensBeam\HTML\DOM\Text::__construct + * @covers \MensBeam\HTML\DOM\Inner\Document::__construct + * @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode + * @covers \MensBeam\HTML\DOM\Inner\Document::__get_xpath + * @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode + * @covers \MensBeam\HTML\DOM\Inner\NodeCache::get + * @covers \MensBeam\HTML\DOM\Inner\NodeCache::has + * @covers \MensBeam\HTML\DOM\Inner\NodeCache::key + * @covers \MensBeam\HTML\DOM\Inner\NodeCache::set + * @covers \MensBeam\HTML\DOM\Inner\Reflection::createFromProtectedConstructor + */ + public function testMethod_namedItem_offsetGet(): void { + $d = new Document(<< + + +
Ook
+
Eek
+
Ack
+
Ook
+
poop💩
+ + + HTML, 'UTF-8'); + $body = $d->body; + + $children = $body->children; + $this->assertSame($children[0], $children['ook']); + $this->assertSame($children[0], $children->namedItem('ook')); + $this->assertSame('Ook', $children['ook']->firstChild->data); + $this->assertSame('poop💩', $children['poop💩']->firstChild->data); + $this->assertNull($children['fail']); + $this->assertNull($children->namedItem('fail')); + $this->assertNull($children->namedItem('')); + } +} \ No newline at end of file diff --git a/tests/phpunit.dist.xml b/tests/phpunit.dist.xml index 76b14c8..c29e2d9 100644 --- a/tests/phpunit.dist.xml +++ b/tests/phpunit.dist.xml @@ -25,6 +25,7 @@ cases/TestDOMImplementation.php cases/TestDOMTokenList.php cases/TestElement.php + cases/TestHTMLCollection.php cases/TestInnerDocument.php cases/TestNamedNodeMap.php cases/TestNode.php