Browse Source

Element fully tested & feature complete

wrapper-classes
Dustin Wilson 3 years ago
parent
commit
87635ea36d
  1. 2
      README.md
  2. 4
      lib/Element.php
  3. 4
      lib/Node.php
  4. 59
      tests/cases/TestElement.php

2
README.md

@ -44,7 +44,7 @@ Coming soon
The primary aim of this library is accuracy. However, due either to limitations imposed by PHP's DOM, by assumptions made by the specification that aren't applicable to a PHP library, or simply because of impractability some changes have needed to be made. These are as follows:
1. Any mention of scripting or anything necessary because of scripting (such as the `ElementCreationOptions` options dictionary on `Document::createElement`) will not be implemented.
2. Due to a PHP bug which severely degrades performance with large documents and in consideration of existing PHP software, HTML elements in HTML documents are placed in the null namespace internally rather than in the HTML namespace. However, externally they will be shown as having the HTML namespace. Even though null namespaced elements do not exist in the HTML specification one can create them using the DOM. However, in this implementation they will be treated as HTML namespaced elements due to the HTML namespace limitation.
2. Due to a PHP bug which severely degrades performance with large documents and in consideration of existing PHP software and because of bizarre uncircumventable `xmlns` attribute bugs when the document is in the HTML namespace, HTML elements in HTML documents are placed in the null namespace internally rather than in the HTML namespace. However, externally they will be shown as having the HTML namespace. Even though null namespaced elements do not exist in the HTML specification one can create them using the DOM. However, in this implementation they will be treated as HTML namespaced elements due to the HTML namespace limitation.
3. The specification is written entirely with browsers in mind and aren't concerned with the DOM's being used outside of the browser. In browser there is always a document created by parsing serialized markup, and the DOM spec always assumes such. This is impossible in the way this PHP library is intended to be used. The default when creating a new `Document` is to set its content type to "application/xml". This isn't ideal when creating an HTML document entirely through the DOM, so this implementation will instead default to "text/html" unless using `XMLDocument`.
4. Again, because the specification assumes the implementation will be a browser, processing instructions are supposed to be parsed as comments. While it makes sense for a browser, this is impractical for a DOM library used outside of the browser where one may want to manipulate them; this library will instead preserve them when parsing a document but will convert them to comments when using `Element::innerHTML`.
5. Per the specification an actual HTML document cannot be created outside of the parser itself unless created via `DOMImplementation::createHTMLDocument`. Also, per the spec `DOMImplementation` cannot be instantiated via its constructor. This would require in this library's use case first creating a document then creating an HTML document via the first document's implementation. This is impractical and stupid, so in this library (like PHP DOM itself) a `DOMImplementation` can be instantiated independent of a document.

4
lib/Element.php

@ -500,7 +500,7 @@ class Element extends Node {
}
protected function insertAdjacent(Element $element, string $where, Node $node): Node {
protected function insertAdjacent(Element $element, string $where, Node $node): ?Node {
# To insert adjacent, given an element element, string where, and a node node,
# run the steps associated with the first ASCII case-insensitive match for
# where:
@ -518,7 +518,7 @@ class Element extends Node {
case 'afterbegin':
# Return the result of pre-inserting node into element before element’s first
# child.
return $element->parentNode->insertBefore($node, $element->firstChild);
return $element->insertBefore($node, $element->firstChild);
break;
case 'beforeend':

4
lib/Node.php

@ -466,7 +466,7 @@ abstract class Node {
# The insertBefore(node, child) method steps are to return the result of
# pre-inserting node into this before child.
$this->preInsertionValidity($node, $child);
$this->innerNode->insertBefore($this->getInnerNode($node), $this->getInnerNode($child));
$this->innerNode->insertBefore($this->getInnerNode($node), ($child !== null) ? $this->getInnerNode($child) : null);
$this->postInsertionBugFixes();
return $node;
}
@ -986,7 +986,7 @@ abstract class Node {
}
protected function getInnerNode(?Node $node = null): \DOMNode {
if ($node === null || $node === $this) {
if ($node === $this) {
return $this->innerNode;
}

59
tests/cases/TestElement.php

@ -342,6 +342,65 @@ class TestElement extends \PHPUnit\Framework\TestCase {
}
public function testMethod_insertAdjacent__errors() {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::SYNTAX_ERROR);
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->insertAdjacentText('fail', 'fail');
}
public function testMethod_insertAdjacentElement() {
$d = new Document('<!DOCTYPE html><html><body><p>Ook</p></body></html>', 'UTF-8');
$body = $d->body;
$p = $d->getElementsByTagName('p')[0];
$dd = $d->createElement('div');
$dd->appendChild($d->createTextNode('beforebegin'));
$p->insertAdjacentElement('beforebegin', $dd);
$this->assertSame('<body><div>beforebegin</div><p>Ook</p></body>', (string)$body);
$dd = $d->createElement('div');
$dd->appendChild($d->createTextNode('afterbegin'));
$p->insertAdjacentElement('afterbegin', $dd);
$this->assertSame('<body><div>beforebegin</div><p><div>afterbegin</div>Ook</p></body>', (string)$body);
$dd = $d->createElement('div');
$dd->appendChild($d->createTextNode('beforeend'));
$p->insertAdjacentElement('beforeend', $dd);
$this->assertSame('<body><div>beforebegin</div><p><div>afterbegin</div>Ook<div>beforeend</div></p></body>', (string)$body);
$dd = $d->createElement('div');
$dd->appendChild($d->createTextNode('afterend'));
$p->insertAdjacentElement('afterend', $dd);
$this->assertSame('<body><div>beforebegin</div><p><div>afterbegin</div>Ook<div>beforeend</div></p><div>afterend</div></body>', (string)$body);
$p = $d->createElement('p');
$this->assertNull($p->insertAdjacentElement('beforebegin', $dd));
$this->assertNull($p->insertAdjacentElement('afterend', $dd));
}
public function testMethod_insertAdjacentText() {
$d = new Document('<!DOCTYPE html><html><body><p>Ook</p></body></html>', 'UTF-8');
$body = $d->body;
$p = $d->getElementsByTagName('p')[0];
$p->insertAdjacentText('beforebegin', 'beforebegin');
$this->assertSame('<body>beforebegin<p>Ook</p></body>', (string)$body);
$p->insertAdjacentText('afterbegin', 'afterbegin');
$this->assertSame('<body>beforebegin<p>afterbeginOok</p></body>', (string)$body);
$p->insertAdjacentText('beforeend', 'beforeend');
$this->assertSame('<body>beforebegin<p>afterbeginOokbeforeend</p></body>', (string)$body);
$p->insertAdjacentText('afterend', 'afterend');
$this->assertSame('<body>beforebegin<p>afterbeginOokbeforeend</p>afterend</body>', (string)$body);
}
/**
* @covers \MensBeam\HTML\DOM\Element::matches
* @covers \MensBeam\HTML\DOM\Element::webkitMatchesSelector

Loading…
Cancel
Save