J. King
3 years ago
98 changed files with 112 additions and 8509 deletions
File diff suppressed because it is too large
@ -1,15 +0,0 @@ |
|||
{ |
|||
"title": "HTML", |
|||
"tagline": "Tools for parsing and printing HTML5 documents and fragments.", |
|||
"author": "Dustin Wilson", |
|||
"languages": { |
|||
"en": "English" |
|||
}, |
|||
"themes_directory": "docs/theme", |
|||
"html": { |
|||
"theme":"php", |
|||
"float": false, |
|||
"toggle_code": false, |
|||
"search": false |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
HTML is a library which provides tools for parsing and printing of HTML5 documents and fragments. Unlike PHP's DOM and other similar libraries the goal of the project is to parse HTML as accurate to the specification as possible given the limitations of PHP's DOM and of the uses of the library. Therefore, there is no scripting in this implementation, and there likely never will be. |
@ -1,8 +0,0 @@ |
|||
We try to make the installation of the MensBeam HTML library as easy and straightforward as possible. |
|||
|
|||
## Requirements ## |
|||
|
|||
HTML intentionally has few requirements. It only requires PHP 7.1.0 or later with the [dom](http://php.net/manual/en/book.dom.php) extension installed. It is recommended to install the [ctype](https://www.php.net/manual/en/book.ctype.php) extension for performance improvements, but it is not required. |
|||
|
|||
TODO: Add Installation instructions once there are releases and a package is available on Packagist. |
|||
|
@ -1,63 +0,0 @@ |
|||
--- |
|||
title: Comment |
|||
--- |
|||
|
|||
# The Comment Class # |
|||
|
|||
## Introduction ## |
|||
|
|||
<div class="admonition info"><p><strong>Info</strong> Only new methods and methods which make outward-facing changes from <a href="https://www.php.net/manual/en/class.domcomment.php">\DOMComment</a> will be documented here, otherwise they will be linked back to PHP's documentation.</p></div> |
|||
|
|||
## Class Synopsis ## |
|||
|
|||
<pre><code class="php">MensBeam\HTML\Comment extends <a href="https://www.php.net/manual/en/class.domcomment.php">\DOMComment</a> { |
|||
|
|||
use <a href="../LeafNode/index.html">LeafNode</a>, <a href="../Moonwalk/index.html">Moonwalk</a>; |
|||
|
|||
/* Inherited properties */ |
|||
public string <a href="https://www.php.net/manual/en/class.domcharacterdata.php#domcharacterdata.props.data">$data</a> ; |
|||
public readonly int <a href="https://www.php.net/manual/en/class.domcharacterdata.php#domcharacterdata.props.length">$length</a> ; |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodename">$nodeName</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodevalue">$nodeValue</a> ; |
|||
public readonly int <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodetype">$nodeType</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.parentnode">$parentNode</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.childnodes">$childNodes</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.firstchild">$firstChild</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.lastchild">$lastChild</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.previoussibling">$previousSibling</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nextsibling">$nextSibling</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnamednodemap.php">\DOMNamedNodeMap</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.attributes">$attributes</a> ; |
|||
public readonly Document|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.ownerdocument">$ownerDocument</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.namespaceuri">$namespaceURI</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.prefix">$prefix</a> ; |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.localname">$localName</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.baseuri">$baseURI</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.textcontent">$textContent</a> ; |
|||
|
|||
/* Trait Methods */ |
|||
public <a href="../LeafNode/appendChild.html">LeafNode::appendChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node ) : DOMException; |
|||
public <a href="../Node/C14N.html">Node::C14N</a> ( bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../Node/C14NFile.html">Node::C14NFile</a> ( string $uri , bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../LeafNode/insertBefore.html">LeafNode::insertBefore</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $child = null ) : DOMException |
|||
public <a href="../Moonwalk/moonwalk.html">Moonwalk::moonwalk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
public <a href="../LeafNode/removeChild.html">LeafNode::removeChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : DOMException |
|||
public <a href="../LeafNode/replaceChild.html">LeafNode::replaceChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : DOMException |
|||
|
|||
/* Magic Methods */ |
|||
public __toString() : string |
|||
|
|||
/* Inherited Methods */ |
|||
public <a href="https://www.php.net/manual/en/domcomment.construct.php">__construct</a> ( string $data = "" ) |
|||
public <a href="https://www.php.net/manual/en/domnode.clonenode.php">\DOMNode::cloneNode</a> ( bool $deep = false ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domnode.getlineno.php">\DOMNode::getLineNo</a> ( ) : int |
|||
public <a href="https://www.php.net/manual/en/domnode.getnodepath.php">\DOMNode::getNodePath</a> ( ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domnode.hasattributes.php">\DOMNode::hasAttributes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.haschildnodes.php">\DOMNode::hasChildNodes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.isdefaultnamespace.php">\DOMNode::isDefaultNamespace</a> ( string $namespace ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issamenode.php">\DOMNode::isSameNode</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $otherNode ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issupported.php">\DOMNode::isSupported</a> ( string $feature , string $version ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupnamespaceuri.php">\DOMNode::lookupNamespaceUri</a> ( string $prefix ) : string |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupprefix.php">\DOMNode::lookupPrefix</a> ( string $namespace ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domnode.normalize.php">\DOMNode::normalize</a> ( ) : void |
|||
|
|||
}</code></pre> |
@ -1,28 +0,0 @@ |
|||
--- |
|||
title: Document::__construct |
|||
--- |
|||
|
|||
Document::__construct — Creates a new Document object |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::__construct ( ) |
|||
``` |
|||
|
|||
Creates a new Document object. |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Creating a new Document** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
echo $dom; |
|||
|
|||
?> |
|||
``` |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Document::createEntityReference |
|||
--- |
|||
|
|||
Document::createEntityReference — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::createEntityReference ( string $name ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. Documented to show difference from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php). DOM4 does not have entity references or entity nodes. |
@ -1,46 +0,0 @@ |
|||
--- |
|||
title: Document::load |
|||
--- |
|||
|
|||
Document::load — Load HTML from a file |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::load ( string $filename , null $options = null , string|null $encodingOrContentType = null ) : bool |
|||
``` |
|||
|
|||
Loads an HTML document from a file. |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>filename</code></dt> |
|||
<dd>The path to the HTML document.</dd> |
|||
|
|||
<dt><code>options</code></dt> |
|||
<dd>Always <code>null</code>. Was used for option constants in <a href="https://www.php.net/manual/en/class.domdocument.php"><code>\DOMDocument</code></a>.</dd> |
|||
|
|||
<dt><code>encodingOrContentType</code></dt> |
|||
<dd>The encoding of the document that is being loaded. If not specified it will be determined automatically.</dd> |
|||
</dl> |
|||
|
|||
## Return Values ## |
|||
|
|||
Returns <code>true</code> on success or <code>false</code> on failure. |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Creating a Document** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->load('ook.html'); |
|||
echo $dom; |
|||
|
|||
?> |
|||
``` |
@ -1,46 +0,0 @@ |
|||
--- |
|||
title: Document::loadHTML |
|||
--- |
|||
|
|||
Document::loadHTML — Load HTML from a string |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::loadHTML ( string $source , null $options = null , string|null $encodingOrContentType = null ) : bool |
|||
``` |
|||
|
|||
The function parses the HTML contained in the string <var>source</var>. |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>source</code></dt> |
|||
<dd>The HTML string.</dd> |
|||
|
|||
<dt><code>options</code></dt> |
|||
<dd>Always <code>null</code>. Was used for option constants in <a href="https://www.php.net/manual/en/class.domdocument.php"><code>\DOMDocument</code></a>.</dd> |
|||
|
|||
<dt><code>encodingOrContentType</code></dt> |
|||
<dd>The encoding of the document that is being loaded. If not specified it will be determined automatically.</dd> |
|||
</dl> |
|||
|
|||
## Return Values ## |
|||
|
|||
Returns <code>true</code> on success or <code>false</code> on failure. |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Creating a Document** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->loadHTML('<!DOCTYPE html><html><head><title>Ook!</title></head><body><h1>Eek</h1></body></html>'); |
|||
echo $dom; |
|||
|
|||
?> |
|||
``` |
@ -1,9 +0,0 @@ |
|||
--- |
|||
title: Document::loadHTMLFile |
|||
--- |
|||
|
|||
Document::loadHTMLFile — Alias of <a href="Document_load.html"><code>Document::load()</code></a> |
|||
|
|||
## Description ## |
|||
|
|||
This function is an alias of <a href="Document_load.html"><code>Document::load()</code></a>. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Document::loadXML |
|||
--- |
|||
|
|||
Document::loadXML — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::loadXML ( string $source , null $options = null ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. Documented to show difference from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php). |
@ -1,43 +0,0 @@ |
|||
--- |
|||
title: Document::save |
|||
--- |
|||
|
|||
Document::save — Serializes the DOM tree into a file |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::save ( string $filename , null $options = null ) : int|false |
|||
``` |
|||
|
|||
Creates an HTML document from the DOM representation. |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>filename</code></dt> |
|||
<dd>The path to the saved HTML document</dd> |
|||
|
|||
<dt><code>options</code></dt> |
|||
<dd>Always <code>null</code>. Was used for option constants in <a href="https://www.php.net/manual/en/class.domdocument.php"><code>\DOMDocument</code></a>.</dd> |
|||
</dl> |
|||
|
|||
## Return Values ## |
|||
|
|||
Returns the number of bytes written or <code>false</code> on failure. |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Saving a DOM tree into a file** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->loadHTML('<!DOCTYPE html><html><head><title>Ook!</title></head><body><h1>Eek</h1></body></html>'); |
|||
echo 'Wrote: ' . $dom->save('/tmp/test.html') . ' bytes'; // Wrote: 85 bytes |
|||
|
|||
?> |
|||
``` |
@ -1,9 +0,0 @@ |
|||
--- |
|||
title: Document::saveHTMLFile |
|||
--- |
|||
|
|||
Document::saveHTMLFile — Alias of <a href="Document_save.html"><code>Document::save()</code></a> |
|||
|
|||
## Description ## |
|||
|
|||
This function is an alias of <a href="Document_save.html"><code>Document::save()</code></a>. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Document::saveXML |
|||
--- |
|||
|
|||
Document::saveXML — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::saveXML ( DOMNode|null $node = null , null $options = null ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. Documented to show difference from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php). |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Document::validate |
|||
--- |
|||
|
|||
Document::validate — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::validate ( ) : true |
|||
``` |
|||
|
|||
This function has been disabled and will always return `true`. Documented to show difference from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php). |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Document::xinclude |
|||
--- |
|||
|
|||
Document::xinclude — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Document::xinclude ( null $options = null ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. Documented to show difference from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php). |
@ -1,147 +0,0 @@ |
|||
--- |
|||
title: Document |
|||
--- |
|||
|
|||
# The Document Class # |
|||
|
|||
## Introduction ## |
|||
|
|||
Represents an entire HTML document; serves as the root of the document tree. Unlike the PHP [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php) class in which it inherits from it cannot be used to represent an XML document. It is strictly used to represent HTML. |
|||
|
|||
<div class="admonition"><p><strong>Note:</strong> Only new methods and methods which make outward-facing changes from <a href="https://www.php.net/manual/en/class.domdocument.php">\DOMDocument</a> will be documented here, otherwise they will be linked back to PHP's documentation.</p></div> |
|||
|
|||
## Class Synopsis ## |
|||
|
|||
<pre><code class="php">MensBeam\HTML\Document extends <a href="https://www.php.net/manual/en/class.domdocument.php">\DOMDocument</a> { |
|||
|
|||
use <a href="../ContainerNode/index.html">ContainerNode</a>, <a href="../Walk/index.html">Walk</a>; |
|||
|
|||
/* Constants */ |
|||
public const NO_QUIRKS_MODE = 0 ; |
|||
public const QUIRKS_MODE = 1 ; |
|||
public const LIMITED_QUIRKS_MODE = 2 ; |
|||
|
|||
/* Properties */ |
|||
public <a href="../Element/index.html">Element</a>|null <a href="#document-props-body">$body</a> = null ; |
|||
public string|null <a href="#document-props-documentencoding">$documentEncoding</a> = null ; |
|||
public int <a href="#document-props-quirksmode">$quirksMode</a> = 0 ; |
|||
|
|||
/* Inherited properties */ |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnamednodemap.php">\DOMNamedNodeMap</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.attributes">$attributes</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.baseuri">$baseURI</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.childnodes">$childNodes</a> ; |
|||
public readonly DocumentType <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.doctype">$doctype</a> ; |
|||
public readonly Element <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.documentelement">$documentElement</a> ; |
|||
public string|null <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.documenturi">$documentURI</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.firstchild">$firstChild</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domimplementation.php">\DOMImplementation</a> <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.implementation">$implementation</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.lastchild">$lastChild</a> ; |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.localname">$localName</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.namespaceuri">$namespaceURI</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nextsibling">$nextSibling</a> ; |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodename">$nodeName</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodevalue">$nodeValue</a> ; |
|||
public readonly int <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodetype">$nodeType</a> ; |
|||
public readonly Document|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.ownerdocument">$ownerDocument</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.parentnode">$parentNode</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.prefix">$prefix</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.previoussibling">$previousSibling</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.textcontent">$textContent</a> ; |
|||
|
|||
/* Methods */ |
|||
public <a href="construct.html">__construct</a> ( ) |
|||
public <a href="createEntityReference.html">createEntityReference</a> ( string $name ) : false |
|||
public <a href="load.html">load</a> ( string $filename , null $options = null , string|null $encodingOrContentType = null ) : bool |
|||
public <a href="loadHTML.html">loadHTML</a> ( string $source , null $options = null , string|null $encodingOrContentType = null ) : bool |
|||
public <a href="loadHTMLFile.html">loadHTMLFile</a> ( string $filename , null $options = null , string|null $encodingOrContentType = null ) : bool |
|||
public <a href="loadHTML.html">loadXML</a> ( string $source , null $options = null ) : false |
|||
public <a href="save.html">save</a> ( string $filename , null $options = null ) : int|false |
|||
public <a href="saveHTMLFile.html">saveHTMLFile</a> ( string $filename , null $options = null ) : int|false |
|||
public <a href="saveXML.html">saveXML</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $node = null , null $options = null ) : false |
|||
public <a href="validate.html">validate</a> ( ) : true |
|||
public <a href="xinclude.html">xinclude</a> ( null $options = null ) : false |
|||
|
|||
/* Trait Methods */ |
|||
public <a href="../ContainerNode/appendChild.html">ContainerNode::appendChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="../Node/C14N.html">Node::C14N</a> ( bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../Node/C14NFile.html">Node::C14NFile</a> ( string $uri , bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../ContainerNode/insertBefore.html">ContainerNode::insertBefore</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $child = null ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="../Walk/walk.html">Walk::walk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
|
|||
/* Magic Methods */ |
|||
public __toString() : string |
|||
|
|||
/* Inherited methods */ |
|||
public <a href="https://www.php.net/manual/en/domnode.clonenode.php">\DOMNode::cloneNode</a> ( bool $deep = false ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createattribute.php">\DOMDocument::createAttribute</a> ( string $localName ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createattributens.php">\DOMDocument::createAttributeNS</a> ( string|null $namespace , string $qualifiedName ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createcdatasection.php">\DOMDocument::createCDATASection</a> ( string $data ) : <a href="https://www.php.net/manual/en/class.domcdatasection.php">\DOMCdataSection</a>|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createcomment.php">\DOMDocument::createComment</a> ( string $data ) : Comment|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createdocumentfragment.php">\DOMDocument::createDocumentFragment</a> ( ) : DocumentFragment|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createelement.php">\DOMDocument::createElement</a> ( string $localName , string $value = "" ) : Element|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createelementns.php">\DOMDocument::createElementNS</a> ( string|null $namespace , string $qualifiedName , string $value = "" ) : Element|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createprocessinginstruction.php">\DOMDocument::createProcessingInstruction</a> ( string $target , string $data = "" ) : ProcessingInstruction|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.createtextnode.php"\DOMDocument::>\DOMDocument::createTextNode</a> ( string $data ) : Text|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.getelementbyid.php">\DOMDocument::getElementById</a> ( string $elementId ) : Element|null |
|||
public <a href="https://www.php.net/manual/en/domdocument.getelementsbytagname.php">\DOMDocument:getElementsByTagName</a> ( string $qualifiedName ) : <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> |
|||
public <a href="https://www.php.net/manual/en/domdocument.createelementsbytagnamens.php">getElementsByTagNameNS</a> ( string $namespace , string $localName ) : <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> |
|||
public <a href="https://www.php.net/manual/en/domnode.getlineno.php">\DOMNode::getLineNo</a> ( ) : int |
|||
public <a href="https://www.php.net/manual/en/domnode.getnodepath.php">\DOMNode::getNodePath</a> ( ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domnode.hasattributes.php">\DOMNode::hasAttributes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.haschildnodes.php">\DOMNode::hasChildNodes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domdocument.importnode.php">\DOMDocument::importNode</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , bool $deep = false ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domnode.isdefaultnamespace.php">\DOMNode::isDefaultNamespace</a> ( string $namespace ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issamenode.php">\DOMNode::isSameNode</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $otherNode ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issupported.php">\DOMNode::isSupported</a> ( string $feature , string $version ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupnamespaceuri.php">\DOMNode::lookupNamespaceUri</a> ( string $prefix ) : string |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupprefix.php">\DOMNode::lookupPrefix</a> ( string $namespace ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domnode.normalize.php">\DOMNode::normalize</a> ( ) : void |
|||
public <a href="https://www.php.net/manual/en/domdocument.normalizedocument.php">\DOMDocument::normalizeDocument</a> ( ) : void |
|||
public <a href="https://www.php.net/manual/en/domdocument.registernodeclass.php">\DOMDocument::registerNodeClass</a> ( string $baseClass , string|null $extendedClass ) : bool |
|||
public <a href="https://www.php.net/manual/en/domdocument.relaxngvalidate.php">\DOMDocument::relaxNGValidate</a> ( string $filename ) : bool |
|||
public <a href="https://www.php.net/manual/en/domdocument.relaxngvalidatesource.php">\DOMDocument::relaxNGValidateSource</a> ( string $source ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.removechild.php">\DOMNode::removeChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domnode.replacechild.php">\DOMNode::replaceChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.savehtml.php">\DOMDocument::saveHTML</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $node = null ) : string|false |
|||
public <a href="https://www.php.net/manual/en/domdocument.schemavalidate.php">\DOMDocument::schemaValidate</a> ( string $filename , int $flags = 0 ) : bool |
|||
public <a href="https://www.php.net/manual/en/domdocument.schemavalidatesource.php">\DOMDocument::schemaValidateSource</a> ( string $source , int $flags = 0 ) : bool |
|||
}</code></pre> |
|||
|
|||
## Constants ## |
|||
|
|||
| Constant | Value | Description | |
|||
| ----------------------------------------------------- | ----- | ------------------------------------- | |
|||
| <var>MensBeam\HTML\Document::NO_QUIRKS_MODE</var> | 0 | Document not in quirks mode | |
|||
| <var>MensBeam\HTML\Document::QUIRKS_MODE</var> | 1 | Document is in quirks mode | |
|||
| <var>MensBeam\HTML\Document::LIMITEDQUIRKS_MODE</var> | 2 | Document is in limited quirks mode | |
|||
|
|||
## Properties ## |
|||
|
|||
<dl> |
|||
<dt id="document-props-body"><var>body</var></dt> |
|||
<dd>Represents the <code>body</code> or <code>frameset</code> node of the current document, or <code>null</code> if no such element exists.</dd> |
|||
|
|||
<dt id="document-props-documentencoding"><var>documentEncoding</var></dt> |
|||
<dd>Encoding of the document, as specified when parsing or when determining encoding type. Use this instead of <a href="https://php.net/manual/en/class.domdocument.php#domdocument.props.encoding"><code>\DOMDocument::encoding</code></a>.</dd> |
|||
|
|||
<dt id="document-props-quirksmode"><var>quirksMode</var></dt> |
|||
<dd>Used when parsing. Specifies which mode the document was parsed in. One of the <a href="#page_Constants">predefined quirks mode constants</a>.</dd> |
|||
</dl> |
|||
|
|||
The following properties inherited from [`\DOMDocument`](https://www.php.net/manual/en/class.domdocument.php) have no effect in `Mensbeam\HTML\Document`, so therefore are not listed in the schema above: |
|||
|
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.actualencoding"><var>actualEncoding</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.config"><var>config</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.encoding"><var>encoding</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.formatoutput"><var>formatOutput</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.preservewhitespace"><var>preserveWhiteSpace</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.recover"><var>recover</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.resolveexternals"><var>resolveExternals</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.standalone"><var>standalone</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.stricterrorchecking"><var>strictErrorChecking</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.substituteentities"><var>substituteEntities</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.validateonparse"><var>validateOnParse</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.version"><var>version</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.xmlencoding"><var>xmlEncoding</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.xmlstandalone"><var>xmlStandalone</var></a> |
|||
* <a href="https://www.php.net/manual/en/class.domdocument.php#domdocument.props.xmlversion"><var>xmlVersion</var></a> |
@ -1,24 +0,0 @@ |
|||
--- |
|||
title: Element::getAttribute |
|||
--- |
|||
|
|||
Element::getAttribute — Returns value of attribute |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Element::getAttribute ( string $qualifiedName ) : string|null |
|||
``` |
|||
|
|||
Gets the value of the attribute with name `qualifiedName` for the current node. |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>qualifiedName</code></dt> |
|||
<dd>The name of the attribute.</dd> |
|||
</dl> |
|||
|
|||
## Return Values ## |
|||
|
|||
Returns a string on success or <code>null</code> if no attribute with the given `qualifiedName` is found. `\DOMElement::getAttribute` returns an empty string on failure which is incorrect in newer versions of the DOM. |
@ -1,26 +0,0 @@ |
|||
--- |
|||
title: Element::getAttributeNS |
|||
--- |
|||
|
|||
Element::getAttributeNS — Returns value of attribute |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Element::getAttribute ( string|null $namespace , string $localName ) : string|null |
|||
``` |
|||
|
|||
Gets the value of the attribute in namespace `namespace` with local name `localName` for the current node. |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>namespace</code></dt> |
|||
<dd>The namespace URI.</dd> |
|||
<dt><code>localName</code></dt> |
|||
<dd>The local name of the attribute.</dd> |
|||
</dl> |
|||
|
|||
## Return Values ## |
|||
|
|||
Returns a string on success or <code>null</code> if no attribute with the given `localName` and `namespace` is found. `\DOMElement::getAttribute` returns an empty string on failure which is incorrect in newer versions of the DOM. |
@ -1,100 +0,0 @@ |
|||
--- |
|||
title: Element |
|||
--- |
|||
|
|||
# The Element Class # |
|||
|
|||
## Introduction ## |
|||
|
|||
<div class="admonition"><p><strong>Note:</strong> Only new methods and methods which make outward-facing changes from <a href="https://www.php.net/manual/en/class.domelement.php">\DOMElement</a> will be documented here, otherwise they will be linked back to PHP's documentation.</p></div> |
|||
|
|||
## Class Synopsis ## |
|||
|
|||
<pre><code class="php">MensBeam\HTML\Element extends <a href="https://www.php.net/manual/en/class.domelement.php">\DOMElement</a> { |
|||
|
|||
use <a href="../ContainerNode/index.html">ContainerNode</a>, <a href="../Moonwalk/index.html">Moonwalk</a>, <a href="../Walk/index.html">Walk</a>; |
|||
|
|||
/* Properties */ |
|||
public readonly NodeList|null <a href="#element-props-classlist">$classList</a> ; |
|||
public string <a href="#element-props-innerhtml">$innerHTML</a> ; |
|||
public string <a href="#element-props-outerhtml">$outerHTML</a> ; |
|||
|
|||
/* Inherited properties */ |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodename">$nodeName</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodevalue">$nodeValue</a> ; |
|||
public readonly int <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nodetype">$nodeType</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.parentnode">$parentNode</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.childnodes">$childNodes</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.firstchild">$firstChild</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.lastchild">$lastChild</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.previoussibling">$previousSibling</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.nextsibling">$nextSibling</a> ; |
|||
public readonly <a href="https://www.php.net/manual/en/class.domnamednodemap.php">\DOMNamedNodeMap</a>|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.attributes">$attributes</a> ; |
|||
public readonly Document|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.ownerdocument">$ownerDocument</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.namespaceuri">$namespaceURI</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.prefix">$prefix</a> ; |
|||
public readonly string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.localname">$localName</a> ; |
|||
public readonly string|null <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.baseuri">$baseURI</a> ; |
|||
public string <a href="https://www.php.net/manual/en/class.domnode.php#domnode.props.textcontent">$textContent</a> ; |
|||
|
|||
/* Methods */ |
|||
public <a href="getAttribute.html">getAttribute</a> ( string $qualifiedName ) : string|null |
|||
public <a href="getAttributeNS.html">getAttributeNS</a> ( string|null $namespace , string $localName ) : string|null |
|||
|
|||
/* Trait Methods */ |
|||
public <a href="../ContainerNode/appendChild.html">ContainerNode::appendChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="../Node/C14N.html">Node::C14N</a> ( bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../Node/C14NFile.html">Node::C14NFile</a> ( string $uri , bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="../ContainerNode/insertBefore.html">ContainerNode::insertBefore</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $child = null ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="../Moonwalk/moonwalk.html">Moonwalk::moonwalk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
public <a href="../Walk/walk.html">Walk::walk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
|
|||
/* Magic Methods */ |
|||
public __toString() : string |
|||
|
|||
/* Inherited Methods */ |
|||
public <a href="https://www.php.net/manual/en/domelement.construct.php">__construct</a> ( string $qualifiedName , string|null $value = null , string $namespace = "" ) |
|||
public <a href="https://www.php.net/manual/en/domnode.clonenode.php">\DOMNode::cloneNode</a> ( bool $deep = false ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domelement.getattributenode.php">\DOMElement::getAttributeNode</a> ( string $qualifiedName ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|false |
|||
public <a href="https://www.php.net/manual/en/domelement.getattributenodens.php">\DOMElement::getAttributeNodeNS</a> ( string|null $namespace , string $localName ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|null |
|||
public <a href="https://www.php.net/manual/en/domelement.getelementsbytagname.php">\DOMElement::getElementsByTagName</a> ( string $qualifiedName ) : <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> |
|||
public <a href="https://www.php.net/manual/en/domelement.getelementsbytagnamens.php">\DOMElement::getElementsByTagNameNS</a> ( string $namespace , string $localName ) : <a href="https://www.php.net/manual/en/class.domnodelist.php">\DOMNodeList</a> |
|||
public <a href="https://www.php.net/manual/en/domnode.getlineno.php">\DOMNode::getLineNo</a> ( ) : int |
|||
public <a href="https://www.php.net/manual/en/domnode.getnodepath.php">\DOMNode::getNodePath</a> ( ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domelement.hasattribute.php">\DOMElement::hasAttribute</a> ( string $qualifiedName ) : bool |
|||
public <a href="https://www.php.net/manual/en/domelement.hasattributens.php">\DOMElement::hasAttributeNS</a> ( string|null $namespace , string $localName ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.hasattributes.php">\DOMNode::hasAttributes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.haschildnodes.php">\DOMNode::hasChildNodes</a> ( ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.isdefaultnamespace.php">\DOMNode::isDefaultNamespace</a> ( string $namespace ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issamenode.php">\DOMNode::isSameNode</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $otherNode ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.issupported.php">\DOMNode::isSupported</a> ( string $feature , string $version ) : bool |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupnamespaceuri.php">\DOMNode::lookupNamespaceUri</a> ( string $prefix ) : string |
|||
public <a href="https://www.php.net/manual/en/domnode.lookupprefix.php">\DOMNode::lookupPrefix</a> ( string $namespace ) : string|null |
|||
public <a href="https://www.php.net/manual/en/domnode.normalize.php">\DOMNode::normalize</a> ( ) : void |
|||
public <a href="https://www.php.net/manual/en/domelement.removeattribute.php">\DOMElement::removeAttribute</a> ( string $qualifiedName ) : bool |
|||
public <a href="https://www.php.net/manual/en/domelement.removeattributenode.php">\DOMElement::removeAttributeNode</a> ( <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a> $attr ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|false |
|||
public <a href="https://www.php.net/manual/en/domelement.removeattributenodens.php">\DOMElement::removeAttributeNS</a> ( string|null $namespace , string $localName ) : void |
|||
public <a href="https://www.php.net/manual/en/domelement.setattribute.php">\DOMElement::setAttribute</a> ( string $qualifiedName , string $value ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|bool |
|||
public <a href="https://www.php.net/manual/en/domnode.removechild.php">\DOMNode::removeChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domnode.replacechild.php">\DOMNode::replaceChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="https://www.php.net/manual/en/domelement.setattributenode.php">\DOMElement::setAttributeNode</a> ( <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a> $attr ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|null|false |
|||
public <a href="https://www.php.net/manual/en/domelement.setattributenodens.php">\DOMElement::setAttributeNodeNS</a> ( <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a> $attr ) : <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a>|null|false |
|||
public <a href="https://www.php.net/manual/en/domelement.setattributens.php">\DOMElement::setAttributeNS</a> ( string|null $namespace , string $qualifiedName , string $value ) : void |
|||
public <a href="https://www.php.net/manual/en/domelement.setidattribute.php">\DOMElement::setIdAttribute</a> ( string $qualifiedName , bool $isId ) : void |
|||
public <a href="https://www.php.net/manual/en/domelement.setidattributenode.php">\DOMElement::setIdAttributeNode</a> ( <a href="https://www.php.net/manual/en/class.domattr.php">\DOMAttr</a> $attr , bool $isId ) : void |
|||
public <a href="https://www.php.net/manual/en/domelement.setidattributens.php">\DOMElement::setIdAttributeNS</a> ( string $namespace , string $qualifiedName , bool $isId ) : void |
|||
|
|||
}</code></pre> |
|||
|
|||
## Properties ## |
|||
|
|||
<dl> |
|||
<dt id="element-props-classlist"><var>classList</var></dt> |
|||
<dd>A live <a href="../TokenList/TokenList.html">TokenList</a> collection of the class attributes of the element. This can then be used to manipulate the class list.</dd> |
|||
|
|||
<dt id="element-props-innerhtml"><var>innerHTML</var></dt> |
|||
<dd>Gets or sets the HTML or XML markup contained within the element</dd> |
|||
|
|||
<dt id="element-props-outerhtml"><var>outerHTML</var></dt> |
|||
<dd>Gets the serialized HTML fragment describing the element including its descendants. It can also be set to replace the element with nodes parsed from the given string.</dd> |
|||
</dl> |
@ -1,55 +0,0 @@ |
|||
--- |
|||
title: ContainerNode::appendChild |
|||
--- |
|||
|
|||
ContainerNode::appendChild — Adds new child at the end of the children |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public ContainerNode::appendChild ( \DOMNode $node ) : \DOMNode|false |
|||
``` |
|||
|
|||
This function appends a child to an existing list of children or creates a new list of children. The child can be created with e.g. [`Document::createElement()`](https://www.php.net/manual/en/domdocument.createelement.php), [`Document::createTextNode()`](https://www.php.net/manual/en/domdocument.createtextnode.php) etc. or simply by using any other node. |
|||
|
|||
When using an existing node it will be moved. |
|||
|
|||
<div class="warning"> |
|||
<p><strong>Warning</strong> Only the following element types may be appended to any node using <code>Node</code> and subject to hierarchy restrictions depending on the type of node being appended to:</p> |
|||
|
|||
<ul> |
|||
<li><code>Comment</code></li> |
|||
<li><code>DocumentFragment</code></li> |
|||
<li><a href="https://www.php.net/manual/en/class.domdocumenttype.php"><code>\DOMDocumentType</code></a></li> |
|||
<li><code>Element</code></li> |
|||
<li><code>ProcessingInstruction</code></li> |
|||
<li><code>Text</code></li> |
|||
</ul> |
|||
|
|||
<p>Note that <code>\DOMAttr</code> is missing from this list.</p> |
|||
</div> |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>node</code></dt> |
|||
<dd>The new node.</dd> |
|||
</dl> |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Adding a child to the body** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->loadHTML('<!DOCTYPE html><html><head><title>Ook!</title></head><body></body></html>'); |
|||
|
|||
$node = $dom->createElement('br'); |
|||
$dom->body->appendChild($node); |
|||
|
|||
?> |
|||
``` |
@ -1,40 +0,0 @@ |
|||
--- |
|||
title: ContainerNode::insertBefore |
|||
--- |
|||
|
|||
ContainerNode::insertBefore — Adds a new child before a reference node |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public ContainerNode::insertBefore ( \DOMNode $node , \DOMNode|null $child = null ) : \DOMNode|false |
|||
``` |
|||
|
|||
This function inserts a new node right before the reference node. If you plan to do further modifications on the appended child you must use the returned node. |
|||
|
|||
When using an existing node it will be moved. |
|||
|
|||
<div class="warning"> |
|||
<p><strong>Warning</strong> Only the following element types may be appended to any node using <code>Node</code> and subject to hierarchy restrictions depending on the type of node being appended to:</p> |
|||
|
|||
<ul> |
|||
<li><code>Comment</code></li> |
|||
<li><code>DocumentFragment</code></li> |
|||
<li><a href="https://www.php.net/manual/en/class.domdocumenttype.php"><code>\DOMDocumentType</code></a></li> |
|||
<li><code>Element</code></li> |
|||
<li><code>ProcessingInstruction</code></li> |
|||
<li><code>Text</code></li> |
|||
</ul> |
|||
|
|||
<p>Note that <code>\DOMAttr</code> is missing from this list.</p> |
|||
</div> |
|||
|
|||
## Parameters ## |
|||
|
|||
<dl> |
|||
<dt><code>node</code></dt> |
|||
<dd>The new node.</dd> |
|||
|
|||
<dt><code>child</code></dt> |
|||
<dd>The reference node. If not supplied, <code>node</code> is appended to the children.</dd> |
|||
</dl> |
@ -1,14 +0,0 @@ |
|||
# The ContainerNode trait # |
|||
|
|||
## Introduction ## |
|||
|
|||
Allows the extended PHP DOM classes to simulate inheriting from a theoretical extended [\DOMNode](https://www.php.net/manual/en/class.domnode.php). This one implements improved DOM child insertion methods. |
|||
|
|||
<pre><code class="php">trait MensBeam\HTML\ContainerNode { |
|||
|
|||
use <a href="../Node/index.html">Node</a>; |
|||
|
|||
public <a href="appendChild.html">appendChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
public <a href="insertBefore.html">insertBefore</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $child = null ) : <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|false |
|||
|
|||
}</code></pre> |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: LeafNode::appendChild |
|||
--- |
|||
|
|||
LeafNode::appendChild — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public LeafNode::appendChild ( \DOMNode $node ) : DOMException |
|||
``` |
|||
|
|||
Throws a `DOMException` upon use. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: LeafNode::insertBefore |
|||
--- |
|||
|
|||
LeafNode::insertBefore — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public LeafNode::insertBefore ( \DOMNode $node , \DOMNode|null $child = null ) : DOMException |
|||
``` |
|||
|
|||
Throws a `DOMException` upon use. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: LeafNode::removeChild |
|||
--- |
|||
|
|||
LeafNode::removeChild — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public LeafNode::removeChild ( \DOMNode $node ) : DOMException |
|||
``` |
|||
|
|||
Throws a `DOMException` upon use. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: LeafNode::replaceChild |
|||
--- |
|||
|
|||
LeafNode::replaceChild — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public LeafNode::replaceChild ( \DOMNode $node , \DOMNode $child ) : DOMException |
|||
``` |
|||
|
|||
Throws a `DOMException` upon use. |
@ -1,16 +0,0 @@ |
|||
# The LeafNode trait # |
|||
|
|||
## Introduction ## |
|||
|
|||
Allows the extended PHP DOM classes to simulate inheriting from a theoretical extended [\DOMNode](https://www.php.net/manual/en/class.domnode.php). This one disables all DOM child insertion methods. |
|||
|
|||
<pre><code class="php">trait MensBeam\HTML\LeafNode { |
|||
|
|||
use <a href="../Node/index.html">Node</a>; |
|||
|
|||
public <a href="appendChild.html">appendChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node ) : DOMException |
|||
public <a href="Node_insertBefore.html">insertBefore</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node , <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a>|null $child = null ) : DOMException |
|||
public <a href="removeChild.html">removeChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : DOMException |
|||
public <a href="replaceChild.html">replaceChild</a> ( <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $node, <a href="https://www.php.net/manual/en/class.domnode.php">\DOMNode</a> $child ) : DOMException |
|||
|
|||
}</code></pre> |
@ -1,43 +0,0 @@ |
|||
--- |
|||
title: Moonwalk::moonwalk |
|||
--- |
|||
|
|||
Moonwalk::moonwalk — Output generator for walking up the DOM tree |
|||
|
|||
## Description ## |
|||
|
|||
<pre><code class="php">public Moonwalk::moonwalk ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
</code></pre> |
|||
|
|||
Non-standard. Creates a [`\Generator`](https://www.php.net/manual/en/class.generator.php) object for walking up the DOM tree. This is in lieu of recreating the awful [DOM TreeWalker API](https://developer.mozilla.org/en-US/docs/Web/API/Treewalker). |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Print name of all ancestors of the H1 element** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->loadHTML('<!DOCTYPE html><html><head><title>Ook!</title></head><body><h1>Eek</h1></body></html>'); |
|||
$h1 = $dom->getElementsByTagName('h1')->item(0); |
|||
|
|||
// All ancestors will be elements so there's no reason to have a filter. |
|||
$tree = $h1->moonwalk(); |
|||
|
|||
foreach ($tree as $t) { |
|||
echo "{$t->nodeName}\n"; |
|||
} |
|||
|
|||
?> |
|||
``` |
|||
|
|||
The above example will output something similar to: |
|||
|
|||
```php |
|||
body |
|||
html |
|||
|
|||
``` |
@ -1,11 +0,0 @@ |
|||
# The Moonwalk trait # |
|||
|
|||
## Introduction ## |
|||
|
|||
Allows the extended PHP DOM classes to Moonwalk up the DOM via a [`\Generator`](https://www.php.net/manual/en/class.generator.php). This is in lieu of recreating the awful [DOM TreeMoonwalker API](https://developer.mozilla.org/en-US/docs/Web/API/TreeMoonwalker). |
|||
|
|||
<pre><code class="php">trait MensBeam\HTML\Moonwalk { |
|||
|
|||
public <a href="Moonwalk.html">Moonwalk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a> $filter ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
|
|||
}</code></pre> |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Node::C14N |
|||
--- |
|||
|
|||
Node::C14N — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Node::C14N ( bool $exclusive = false , bool $withComments = false , array|null $xpath = null , array|null $nsPrefixes = null ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. `\DOMNode::C14N` is an extremely slow and inefficient method to serialize DOM and never should be used. |
@ -1,13 +0,0 @@ |
|||
--- |
|||
title: Node::C14NFile |
|||
--- |
|||
|
|||
Document::C14NFile — **DISABLED** |
|||
|
|||
## Description ## |
|||
|
|||
```php |
|||
public Node::C14NFile ( string $uri , bool $exclusive = false , bool $withComments = false , array|null $xpath = null , array|null $nsPrefixes = null ) : false |
|||
``` |
|||
|
|||
This function has been disabled and will always return `false`. `\DOMNode::C14NFile` is an extremely slow and inefficient method to serialize DOM and never should be used. |
@ -1,12 +0,0 @@ |
|||
# The Node trait # |
|||
|
|||
## Introduction ## |
|||
|
|||
Allows the extended PHP DOM classes to simulate inheriting from a theoretical extended [\DOMNode](https://www.php.net/manual/en/class.domnode.php). It is used to disable [C14N](C14N.html) and [C14NFile](C14NFile.html). |
|||
|
|||
<pre><code class="php">trait MensBeam\HTML\Node { |
|||
|
|||
public <a href="C14N.html">C14N</a> ( bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
public <a href="C14NFile.html">C14NFile</a> ( string $uri , bool $exclusive = false , bool $withComments = false , null $xpath = null , null $nsPrefixes = null ) : false |
|||
|
|||
}</code></pre> |
@ -1,45 +0,0 @@ |
|||
--- |
|||
title: Walk::walk |
|||
--- |
|||
|
|||
Walk::walk — Output generator for walking down the DOM tree |
|||
|
|||
## Description ## |
|||
|
|||
<pre><code class="php">public Walk::walk ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a>|null $filter = null ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
</code></pre> |
|||
|
|||
Non-standard. Creates a [`\Generator`](https://www.php.net/manual/en/class.generator.php) object for walking down the DOM tree. This is in lieu of recreating the awful [DOM TreeWalker API](https://developer.mozilla.org/en-US/docs/Web/API/Treewalker). |
|||
|
|||
## Examples ## |
|||
|
|||
**Example \#1 Print name of every Element** |
|||
|
|||
```php |
|||
<?php |
|||
|
|||
namespace MensBeam\HTML; |
|||
|
|||
$dom = new Document(); |
|||
$dom->loadHTML('<!DOCTYPE html><html><head><title>Ook!</title></head><body><h1>Eek</h1></body></html>'); |
|||
$tree = $dom->walk(function($node) { |
|||
return ($node instanceof Element); |
|||
}); |
|||
|
|||
foreach ($tree as $t) { |
|||
echo "{$t->nodeName}\n"; |
|||
} |
|||
|
|||
?> |
|||
``` |
|||
|
|||
The above example will output something similar to: |
|||
|
|||
```php |
|||
html |
|||
head |
|||
title |
|||
body |
|||
h1 |
|||
|
|||
``` |
@ -1,11 +0,0 @@ |
|||
# The Walk trait # |
|||
|
|||
## Introduction ## |
|||
|
|||
Allows the extended PHP DOM classes to walk down the DOM via a [`\Generator`](https://www.php.net/manual/en/class.generator.php). This is in lieu of recreating the awful [DOM TreeWalker API](https://developer.mozilla.org/en-US/docs/Web/API/Treewalker). |
|||
|
|||
<pre><code class="php">trait MensBeam\HTML\Walk { |
|||
|
|||
public <a href="walk.html">walk</a> ( <a href="https://www.php.net/manual/en/class.closure.php">\Closure</a> $filter ) : <a href="https://www.php.net/manual/en/class.generator.php">\Generator</a> |
|||
|
|||
}</code></pre> |
@ -1 +0,0 @@ |
|||
The MensBeam HTML library works by parsing HTML strings into PHP's existing XML DOM. It, however, has to force the antiquated PHP DOM extension into working properly with modern HTML DOM by extending many of the node types. The documentation below follows PHP's doc style guide as closely as possible. Each class should be listed separately in the menu under this section. |
@ -1 +0,0 @@ |
|||
Welcome to the user manual for HTML. It is included with each copy of the software, and is also [available online](https://mensbeam.com/html/en/). Please select a language above. |
@ -1,9 +0,0 @@ |
|||
{ |
|||
"favicon": "<theme_url>favicon.png", |
|||
"js": [ |
|||
"<theme_url>daux.min.js" |
|||
], |
|||
"css": [ |
|||
"<theme_url>php.css" |
|||
] |
|||
} |
@ -1,2 +0,0 @@ |
|||
var e=document.querySelectorAll(".s-content pre"),t=document.querySelector(".CodeToggler"),n="daux_code_blocks_hidden";function a(t){for(var a=0;a<e.length;a++)e[a].classList.toggle("Hidden",t);try{localStorage.setItem(n,t)}catch(e){}}t&&(e.length?function(){var e=t.querySelector(".CodeToggler__button--main");e.addEventListener("change",(function(e){a(!e.target.checked)}),!1);var r=!1;try{"false"===(r=localStorage.getItem(n))?r=!1:"true"===r&&(r=!0),r&&(a(!!r),e.checked=!r)}catch(e){}}():t.classList.add("Hidden"));var r=document.querySelector(".Collapsible__trigger");if(r){var o=document.querySelector(".Collapsible__content");r.addEventListener("click",(function(e){o.classList.contains("Collapsible__content--open")?(o.style.height=0,o.classList.remove("Collapsible__content--open"),r.setAttribute("aria-expanded","false")):(r.setAttribute("aria-expanded","true"),o.style.transitionDuration="150ms",o.style.height="".concat(o.scrollHeight,"px"),o.classList.add("Collapsible__content--open"))}))}var l=document.querySelectorAll("pre > code:not(.hljs)");if(l.length){var i=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.async=!0,c.src="".concat(window.base_url,"daux_libraries/highlight.pack.js"),c.onload=function(e){[].forEach.call(l,window.hljs.highlightBlock)},i.appendChild(c)}function s(e){var t=void 0!==e.preventDefault;t&&e.preventDefault();var n=function(e){for(var t=e;(t=t.parentNode)&&9!==t.nodeType;)if(1===t.nodeType&&t.classList.contains("Nav__item"))return t;throw new Error("Could not find a NavItem...")}(e.target),a=n.querySelector("ul.Nav");t&&n.classList.contains("Nav__item--open")?(a.style.height="".concat(a.scrollHeight,"px"),a.style.transitionDuration="150ms",a.style.height="0px",n.classList.remove("Nav__item--open")):t?(a.style.transitionDuration="150ms",a.addEventListener("transitionend",(function e(t){"0px"!==t.target.style.height&&(t.target.style.height="auto"),t.target.removeEventListener("transitionend",e)})),a.style.height="".concat(a.scrollHeight,"px"),n.classList.add("Nav__item--open")):a.style.height="auto"}for(var d,u=document.querySelectorAll(".Nav__item.has-children i.Nav__arrow"),h=u.length-1;h>=0;h--)(d=u[h]).addEventListener("click",s),d.parentNode.parentNode.classList.contains("Nav__item--open")&&s({target:d});var g=document.querySelectorAll(".Nav__item__link--nopage"),v=!0,p=!1,_=void 0;try{for(var y,m=g[Symbol.iterator]();!(v=(y=m.next()).done);v=!0){y.value.addEventListener("click",s)}}catch(e){p=!0,_=e}finally{try{v||null==m.return||m.return()}finally{if(p)throw _}} |
|||
//# sourceMappingURL=daux.min.js.map
|
File diff suppressed because one or more lines are too long
@ -1,324 +0,0 @@ |
|||
/* Daux imports; fonts are omitted */ |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/vendor/normalize.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_variables.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_mixins.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_structure.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_typography.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_components.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_homepage.scss"; |
|||
@import "../../../vendor/daux/daux.io/src/css/theme_daux/_print.scss" print; |
|||
|
|||
/* Overrides */ |
|||
|
|||
:root { |
|||
--font-family-text: sans-serif; |
|||
--font-family-monospace: "Operator Mono SSm", "Operator Mono", monospace; |
|||
--font-family-heading: sans-serif; |
|||
|
|||
--type-size-1: 1.75rem; |
|||
--type-size-2: 1.5rem; |
|||
--type-size-3: 1.25rem; |
|||
--type-size-4: 1.125rem; |
|||
--type-size-5: 1rem; |
|||
--type-size-6: 1rem; |
|||
|
|||
--purple: #4f5b93; |
|||
--tyrian: #793862; |
|||
--light-purple: #8892bf; |
|||
--lighter-purple: #c4c9df; |
|||
--danger: #f4dfdf; |
|||
|
|||
--page: #f2f2f2; |
|||
--text: #333; |
|||
|
|||
--red: #e63c2f; |
|||
--blue: #15284b; |
|||
--light-blue: #93b7bb; |
|||
--beige: #e8d5d3; |
|||
--green: #2c9a42; |
|||
|
|||
--dark-gray: color(var(--page) blend(var(--text) 75%)); |
|||
--gray: color(var(--page) blend(var(--text) 50%)); |
|||
--light-gray: color(var(--page) blend(var(--text) 25%)); |
|||
--lighter-gray: color(var(--page) blend(var(--text) 12.5%)); |
|||
--lightest-gray: color(#fff blend(var(--page) 75%)); |
|||
|
|||
--dark: var(--text); |
|||
--light: var(--light-purple); |
|||
|
|||
--sidebar-background: var(--text); |
|||
--sidebar-link-active-background: var(--tyrian); |
|||
--sidebar-link-color: var(--page); |
|||
--sidebar-link-secondary-color: var(--page); |
|||
--sidebar-collapsible--hamburger-color: var(--beige); |
|||
|
|||
--link-color: #369; |
|||
--brand-color: #fff; |
|||
--brand-background: var(--purple); |
|||
|
|||
--code-tag-background-color: transparent; |
|||
--code-tag-border-radius: 0; |
|||
--code-tag-box-shadow: none; |
|||
|
|||
--homepage-navbar-background: var(--red); |
|||
--hero-button-block-background: var(--beige); |
|||
--homepage-hero-background: #fff; |
|||
--content-floating-blocks-background: var(--blue); |
|||
} |
|||
|
|||
body { |
|||
line-height: 1.618; |
|||
font-size: 16px; |
|||
color: var(--text) !important; |
|||
} |
|||
|
|||
body, .Columns__right__content { |
|||
background-color: var(--page); |
|||
} |
|||
|
|||
a.Link--external::after { |
|||
content: ''; |
|||
} |
|||
|
|||
.Page__header h1 { |
|||
font-size: var(--type-size-6); |
|||
border-bottom: 0; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.s-content { |
|||
h1, h2, h3, h4, h5, h6 { |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
h1 { |
|||
font-size: var(--type-size-1); |
|||
} |
|||
|
|||
h2 { |
|||
font-size: var(--type-size-2); |
|||
} |
|||
|
|||
h3 { |
|||
font-size: var(--type-size-3); |
|||
} |
|||
|
|||
h4 { |
|||
font-size: var(--type-size-4); |
|||
} |
|||
|
|||
h5 { |
|||
font-size: var(--type-size-5); |
|||
} |
|||
|
|||
h6 { |
|||
font-size: var(--type-size-6); |
|||
} |
|||
|
|||
|
|||
code { |
|||
padding-top: 0; |
|||
padding-bottom: 0; |
|||
padding: 0; |
|||
border: 0; |
|||
margin: 0; |
|||
|
|||
&::before, &::after { |
|||
display: none; |
|||
} |
|||
|
|||
pre & { |
|||
display: inline; |
|||
} |
|||
} |
|||
|
|||
table { |
|||
border-collapse: separate; |
|||
border-spacing: 2px; |
|||
border: 2px solid var(--gray); |
|||
|
|||
thead, tbody { |
|||
background-color: #fff; |
|||
} |
|||
|
|||
tr { |
|||
border-top: 0; |
|||
|
|||
&:nth-child(2n) { |
|||
background-color: transparent; |
|||
|
|||
td { |
|||
background-color: #fff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
th, td { |
|||
border: 0; |
|||
} |
|||
|
|||
th { |
|||
background-color: var(--lighter-purple); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.s-content table, .Nav__item .Nav__item { |
|||
font-size: 1rem; |
|||
} |
|||
|
|||
.Brand, h1, h2, h3, h4, h5, h6 { |
|||
font-weight: 600; |
|||
font-stretch: condensed; |
|||
} |
|||
|
|||
h1, h2, h3, h4, h5, h6 { |
|||
color: var(--tyrian); |
|||
border-bottom: 1px dotted var(--text); |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
.Button { |
|||
border-radius: 0; |
|||
} |
|||
|
|||
.HomepageButtons .Button--hero { |
|||
font-weight: normal; |
|||
font-size: var(--type-size-6); |
|||
} |
|||
|
|||
.Page__header { |
|||
border-bottom: 0; |
|||
} |
|||
|
|||
.Pager li > a { |
|||
border: 2px solid var(--lighter-gray); |
|||
border-radius: 0; |
|||
|
|||
&:hover, &:focus { |
|||
background-color: var(--lighter-gray); |
|||
} |
|||
} |
|||
|
|||
.Pager--prev a::before { |
|||
content: "\2190\00a0"; |
|||
} |
|||
.Pager--next a::after { |
|||
content: "\00a0\2192"; |
|||
} |
|||
|
|||
.Navbar { |
|||
height: auto; |
|||
box-shadow: none; |
|||
|
|||
.Brand { |
|||
float: none; |
|||
line-height: inherit; |
|||
height: auto; |
|||
} |
|||
} |
|||
|
|||
.Homepage { |
|||
padding-top: 10px !important; |
|||
} |
|||
|
|||
.Nav__item { |
|||
font-size: var(--type-size-6); |
|||
} |
|||
|
|||
.Nav .Nav .Nav__item a { |
|||
padding-left: 35px; |
|||
} |
|||
|
|||
.Nav__arrow:before { |
|||
margin: 0 0 0 -.25em; |
|||
top: auto; |
|||
bottom: calc(50% - 0.0625em); |
|||
width: 0.375em; |
|||
height: 0.375em; |
|||
transform-origin: center; |
|||
} |
|||
|
|||
.Nav__arrow:before, .Nav .Nav .Nav__item a .Nav__arrow:before { |
|||
border-right-color: var(--page); |
|||
border-top-color: var(--page); |
|||
} |
|||
|
|||
.admonition { |
|||
padding: 0.75rem; |
|||
margin: 1.5rem 0; |
|||
border: 1px solid var(--light-gray); |
|||
background-color: #fff; |
|||
|
|||
p:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.danger { |
|||
background-color: var(--danger); |
|||
border-color: color(var(--danger) blend(var(--text) 25%)); |
|||
} |
|||
} |
|||
|
|||
.hljs, .s-content pre { |
|||
background: var(--blue); |
|||
color: var(--beige); |
|||
} |
|||
|
|||
.hljs { |
|||
display: block; |
|||
overflow-x: auto; |
|||
padding: 0.5em; |
|||
} |
|||
|
|||
.hljs-emphasis { |
|||
font-style: italic; |
|||
} |
|||
|
|||
.hljs-strong { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.hljs-comment, .hljs-quote { |
|||
color: #978e9c; |
|||
} |
|||
|
|||
/* Green */ |
|||
.hljs-keyword, .hljs-selector-tag, .hljs-addition { |
|||
color: #acb39a; |
|||
} |
|||
|
|||
/* Cyan */ |
|||
.hljs-number, .hljs-string, .hljs-meta .hljs-meta-string, .hljs-literal, .hljs-doctag, .hljs-regexp { |
|||
color: var(--light-blue); |
|||
} |
|||
|
|||
/* Blue */ |
|||
.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class { |
|||
color: #82b7e5; |
|||
} |
|||
|
|||
/* Yellow */ |
|||
.hljs-attribute, .hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-class .hljs-title, .hljs-type { |
|||
color: #c5b031; |
|||
} |
|||
|
|||
/* Orange */ |
|||
.hljs-symbol, .hljs-bullet, .hljs-subst, .hljs-meta, .hljs-meta .hljs-keyword, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-link { |
|||
color: #ea8031; |
|||
} |
|||
|
|||
/* Red */ |
|||
.hljs-built_in, .hljs-deletion { |
|||
color: var(--red); |
|||
} |
|||
|
|||
.hljs-formula { |
|||
background: #686986; |
|||
} |
|||
|
|||
@media (--viewport-large) { |
|||
.Columns__left { |
|||
border: 0; |
|||
} |
|||
} |
@ -1,12 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// Exists so Document can extend methods from its traits. |
|||
abstract class AbstractDocument extends \DOMDocument { |
|||
use ContainerNode, DocumentOrElement, EscapeString, MagicProperties, MoonwalkShallow, ParentNode, Walk, WalkShallow; |
|||
} |
@ -1,11 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class Comment extends \DOMComment { |
|||
use LeafNode, Moonwalk, ToString; |
|||
} |
@ -1,65 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class DOMException extends \Exception { |
|||
// From PHP's DOMException; keeping error codes consistent |
|||
const HIERARCHY_REQUEST_ERROR = 3; |
|||
const WRONG_DOCUMENT = 4; |
|||
const INVALID_CHARACTER = 5; |
|||
const NO_MODIFICATION_ALLOWED = 7; |
|||
const NOT_FOUND = 8; |
|||
const SYNTAX_ERROR = 12; |
|||
|
|||
const ARGUMENT_TYPE_ERROR = 100; |
|||
const OUTER_HTML_FAILED_NOPARENT = 101; |
|||
|
|||
protected static $messages = [ |
|||
3 => 'Hierarchy request error; supplied node is not allowed here', |
|||
4 => 'Supplied node does not belong to this document', |
|||
5 => 'Invalid character', |
|||
7 => 'Modification not allowed here', |
|||
8 => 'Not found error', |
|||
12 => 'Syntax error', |
|||
100 => 'Argument #%s (\$%s) must be of type %s, %s given', |
|||
101 => 'Failed to set the "outerHTML" property; the element does not have a parent node' |
|||
]; |
|||
|
|||
public function __construct(int $code, ...$args) { |
|||
if (!isset(self::$messages[$code])) { |
|||
throw new Exception(Exception::INVALID_CODE); |
|||
} |
|||
|
|||
$message = self::$messages[$code]; |
|||
$previous = null; |
|||
|
|||
if ($args) { |
|||
// Grab a previous exception if there is one. |
|||
if ($args[0] instanceof \Throwable) { |
|||
$previous = array_shift($args); |
|||
} elseif (end($args) instanceof \Throwable) { |
|||
$previous = array_pop($args); |
|||
} |
|||
} |
|||
|
|||
// Count the number of replacements needed in the message. |
|||
preg_match_all('/(\%(?:\d+\$)?s)/', $message, $matches); |
|||
$count = count($matches[1]); |
|||
|
|||
// If the number of replacements don't match the arguments then oops. |
|||
if (count($args) !== $count) { |
|||
throw new Exception(Exception::INCORRECT_PARAMETERS_FOR_MESSAGE, $count); |
|||
} |
|||
|
|||
if ($count > 0) { |
|||
// Go through each of the arguments and run sprintf on the strings. |
|||
$message = call_user_func_array('sprintf', array_merge([$message], $args)); |
|||
} |
|||
|
|||
parent::__construct($message, $code, $previous); |
|||
} |
|||
} |
@ -1,755 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class Document extends AbstractDocument { |
|||
protected ?Element $_body = null; |
|||
/** Nonstandard */ |
|||
protected ?\DOMXPath $_xpath = null; |
|||
|
|||
// List of elements that are treated as block elements for the purposes of |
|||
// output formatting when serializing |
|||
protected const BLOCK_ELEMENTS = [ 'address', 'article', 'aside', 'blockquote', 'base', 'body', 'details', 'dialog', 'dd', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'isindex', 'li', 'link', 'main', 'meta', 'nav', 'ol', 'p', 'picture', 'pre', 'section', 'script', 'source', 'style', 'table', 'template', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'ul' ]; |
|||
// List of h-elements used when determining extra spacing for the purposes of |
|||
// output formatting when serializing |
|||
protected const H_ELEMENTS = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ]; |
|||
// List of preformatted elements where content is ignored for the purposes of |
|||
// output formatting when serializing |
|||
protected const PREFORMATTED_ELEMENTS = [ 'iframe', 'listing', 'noembed', 'noframes', 'noscript', 'plaintext', 'pre', 'style', 'script', 'textarea', 'title', 'xmp' ]; |
|||
// List of elements which are self-closing; used when serializing |
|||
protected const VOID_ELEMENTS = [ 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'embed', 'frame', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' ]; |
|||
|
|||
|
|||
public function __get_body(): \DOMNode { |
|||
if ($this->documentElement === null || $this->documentElement->childNodes->length === 0) { |
|||
return null; |
|||
} |
|||
|
|||
$body = null; |
|||
|
|||
# The body element of a document is the first of the html element's children |
|||
# that is either a body element or a frameset element, or null if there is no |
|||
# such element. |
|||
$n = $this->documentElement->firstChild; |
|||
do { |
|||
if ($n instanceof Element && $n->namespaceURI === null && ($n->nodeName === 'body' || $n->nodeName === 'frameset')) { |
|||
$body = $n; |
|||
break; |
|||
} |
|||
} while ($n = $n->nextSibling); |
|||
|
|||
if ($body !== null) { |
|||
// References are handled weirdly by PHP's DOM. Return a stored body element |
|||
// unless it is changed so operations (like classList) can be done without |
|||
// losing the reference. |
|||
if ($body !== $this->_body) { |
|||
$this->_body = $body; |
|||
} |
|||
|
|||
return $this->_body; |
|||
} |
|||
|
|||
$this->_body = null; |
|||
return null; |
|||
} |
|||
|
|||
public function __set_body($value) { |
|||
# On setting, the following algorithm must be run: |
|||
# |
|||
# 1. If the new value is not a body or frameset element, then throw a |
|||
# "HierarchyRequestError" DOMException. |
|||
if (!$value instanceof Element || $value->namespaceURI !== null) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
if ($value->nodeName !== 'body' && $value->nodeName !== 'frameset') { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
if ($this->_body !== null) { |
|||
# 2. Otherwise, if the new value is the same as the body element, return. |
|||
if ($value->isSameNode($this->_body)) { |
|||
return; |
|||
} |
|||
|
|||
# 3. Otherwise, if the body element is not null, then replace the body element |
|||
# with the new value within the body element's parent and return. |
|||
$this->documentElement->replaceChild($value, $this->_body); |
|||
$this->_body = $value; |
|||
return; |
|||
} |
|||
|
|||
# 4. Otherwise, if there is no document element, throw a "HierarchyRequestError" |
|||
# DOMException. |
|||
if ($this->documentElement === null) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
# 5. Otherwise, the body element is null, but there's a document element. Append |
|||
# the new value to the document element. |
|||
$this->documentElement->appendChild($value); |
|||
$this->_body = $value; |
|||
} |
|||
|
|||
public function __get_xpath(): \DOMXPath { |
|||
if ($this->_xpath === null) { |
|||
$this->_xpath = new \DOMXPath($this); |
|||
} |
|||
return $this->_xpath; |
|||
} |
|||
|
|||
|
|||
public function __construct($source = null, ?string $encodingOrContentType = null) { |
|||
// Because we cannot have union types until php 8... :) |
|||
if ($source !== null && !$source instanceof \DOMDocument && !is_string($source)) { |
|||
throw new DOMException(DOMException::ARGUMENT_TYPE_ERROR, 1, 'source', 'string|\DOMDocument', gettype($source)); |
|||
} elseif ($source instanceof self) { |
|||
return $source; |
|||
} |
|||
|
|||
parent::__construct(); |
|||
|
|||
$this->registerNodeClass('DOMDocument', '\MensBeam\HTML\Document'); |
|||
$this->registerNodeClass('DOMComment', '\MensBeam\HTML\Comment'); |
|||
$this->registerNodeClass('DOMDocumentFragment', '\MensBeam\HTML\DocumentFragment'); |
|||
$this->registerNodeClass('DOMElement', '\MensBeam\HTML\Element'); |
|||
$this->registerNodeClass('DOMProcessingInstruction', '\MensBeam\HTML\ProcessingInstruction'); |
|||
$this->registerNodeClass('DOMText', '\MensBeam\HTML\Text'); |
|||
|
|||
if ($source !== null) { |
|||
if (is_string($source)) { |
|||
$source = Parser::parse($source, null, $encodingOrContentType); |
|||
} |
|||
|
|||
foreach ($source->childNodes as $child) { |
|||
if (!$child instanceof \DOMDocumentType) { |
|||
$this->appendChild($this->importNode($child, true)); |
|||
} else { |
|||
$this->appendChild($this->implementation->createDocumentType($child->name ?? ' ', $child->public ?? '', $child->system ?? '')); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
public function createAttribute($name) { |
|||
return $this->createAttributeNS(null, $name); |
|||
} |
|||
|
|||
public function createAttributeNS($namespaceURI, $qualifiedName) { |
|||
// Normalize the attribute name and namespace URI per modern DOM specifications. |
|||
if ($namespaceURI !== null) { |
|||
$namespaceURI = trim($namespaceURI); |
|||
} |
|||
$qualifiedName = trim($qualifiedName); |
|||
|
|||
try { |
|||
return parent::createAttributeNS($namespaceURI, $qualifiedName); |
|||
} catch (\DOMException $e) { |
|||
// The element name is invalid for XML |
|||
// Replace any offending characters with "UHHHHHH" where H are the |
|||
// uppercase hexadecimal digits of the character's code point |
|||
$this->mangledAttributes = true; |
|||
if ($namespaceURI !== null) { |
|||
$qualifiedName = implode(":", array_map([$this, "coerceName"], explode(":", $qualifiedName, 2))); |
|||
} else { |
|||
$qualifiedName = $this->coerceName($qualifiedName); |
|||
} |
|||
return parent::createAttributeNS($namespaceURI, $qualifiedName); |
|||
} |
|||
} |
|||
|
|||
public function createElement($name, $value = "") { |
|||
return $this->createElementNS(null, $name, $value); |
|||
} |
|||
|
|||
public function createElementNS($namespaceURI, $qualifiedName, $value = "") { |
|||
// Normalize the element name and namespace URI per modern DOM specifications. |
|||
if ($namespaceURI !== null) { |
|||
$namespaceURI = trim($namespaceURI); |
|||
$namespaceURI = ($namespaceURI === Parser::HTML_NAMESPACE) ? null : $namespaceURI; |
|||
} |
|||
$qualifiedName = ($namespaceURI === null) ? strtolower(trim($qualifiedName)) : trim($qualifiedName); |
|||
|
|||
try { |
|||
if ($qualifiedName !== 'template' || $namespaceURI !== null) { |
|||
$e = parent::createElementNS($namespaceURI, $qualifiedName, $value); |
|||
} else { |
|||
$e = new TemplateElement($this, $qualifiedName, $value); |
|||
// Template elements need to have a reference kept in userland |
|||
ElementMap::set($e); |
|||
$e->content = $this->createDocumentFragment(); |
|||
} |
|||
|
|||
return $e; |
|||
} catch (\DOMException $e) { |
|||
// The element name is invalid for XML |
|||
// Replace any offending characters with "UHHHHHH" where H are the |
|||
// uppercase hexadecimal digits of the character's code point |
|||
$this->mangledElements = true; |
|||
if ($namespaceURI !== null) { |
|||
$qualifiedName = implode(":", array_map([$this, "coerceName"], explode(":", $qualifiedName, 2))); |
|||
} else { |
|||
$qualifiedName = $this->coerceName($qualifiedName); |
|||
} |
|||
return parent::createElementNS($namespaceURI, $qualifiedName, $value); |
|||
} |
|||
} |
|||
|
|||
public function createEntityReference($name): bool { |
|||
return false; |
|||
} |
|||
|
|||
public function load($filename, $options = null, ?string $encodingOrContentType = null): bool { |
|||
$data = Parser::fetchFile($filename, $encodingOrContentType); |
|||
if (!$data) { |
|||
return false; |
|||
} |
|||
[$data, $encodingOrContentType] = $data; |
|||
Parser::parse($data, $this, $encodingOrContentType, null, (string)$filename); |
|||
return true; |
|||
} |
|||
|
|||
public function loadHTML($source, $options = null, ?string $encodingOrContentType = null): bool { |
|||
if (!is_string($source)) { |
|||
throw new DOMException(DOMException::ARGUMENT_TYPE_ERROR, 1, 'source', 'string', gettype($source)); |
|||
} |
|||
|
|||
if (is_string($source)) { |
|||
$source = Parser::parse($source, null, $encodingOrContentType); |
|||
} |
|||
|
|||
foreach ($source->childNodes as $child) { |
|||
if (!$child instanceof \DOMDocumentType) { |
|||
$this->appendChild($this->importNode($child, true)); |
|||
} else { |
|||
$this->appendChild($this->implementation->createDocumentType($child->name ?? ' ', $child->public ?? '', $child->system ?? '')); |
|||
} |
|||
} |
|||
|
|||
assert(is_string($source), new DOMException(DOMException::STRING_EXPECTED, 'source', gettype($source))); |
|||
Parser::parse($source, $this, $encodingOrContentType); |
|||
return true; |
|||
} |
|||
|
|||
public function loadHTMLFile($filename, $options = null, ?string $encodingOrContentType = null): bool { |
|||
return $this->load($filename, $options, $encodingOrContentType); |
|||
} |
|||
|
|||
public function loadXML($source, $options = null): bool { |
|||
return false; |
|||
} |
|||
|
|||
public function save($filename, $options = null) { |
|||
return file_put_contents($filename, $this->serialize()); |
|||
} |
|||
|
|||
public function saveHTML(\DOMNode $node = null): string { |
|||
return $node->serialize($node); |
|||
} |
|||
|
|||
public function saveHTMLFile($filename): int { |
|||
return $this->save($filename); |
|||
} |
|||
|
|||
public function saveXML(?\DOMNode $node = null, $options = null): bool { |
|||
return false; |
|||
} |
|||
|
|||
public function serialize(\DOMNode $node = null): string { |
|||
$node = $node ?? $this; |
|||
$formatOutput = $this->formatOutput; |
|||
|
|||
if ($node !== $this) { |
|||
if (!$node->ownerDocument->isSameNode($this)) { |
|||
throw new DOMException(DOMException::WRONG_DOCUMENT); |
|||
} |
|||
|
|||
// This method is used to serialize any node. If not a Document or a |
|||
// DocumentFragment or a DocumentType clone the node in a fragment and serialize |
|||
// that. Otherwise, if a DocumentFragment create a new Document with a clone of |
|||
// the DocumentFragment as its doctype and then serialize the new document. |
|||
if (!$node instanceof Document && !$node instanceof DocumentFragment) { |
|||
// If the node isn't an element disable output formatting |
|||
if ($formatOutput && !$node instanceof Element) { |
|||
$formatOutput = false; |
|||
} |
|||
|
|||
if (!$node instanceof \DOMDocumentType) { |
|||
$frag = $this->createDocumentFragment(); |
|||
$frag->appendChild($node->cloneNode(true)); |
|||
$node = $frag; |
|||
} else { |
|||
$newDoc = new self(); |
|||
$newDoc->appendChild($newDoc->implementation->createDocumentType($node->name, $node->publicId, $node->systemId)); |
|||
$node = $newDoc; |
|||
} |
|||
} |
|||
} elseif ($formatOutput && $node instanceof DocumentFragment) { |
|||
// If node is a document fragment disable output formatting if the |
|||
// DocumentFragment doesn't have any Element children. |
|||
$formatOutput = ($node->childElementCount > 0); |
|||
} |
|||
|
|||
return $this->serializeFragment($node, $formatOutput); |
|||
} |
|||
|
|||
public function validate(): bool { |
|||
return true; |
|||
} |
|||
|
|||
public function xinclude($options = null): bool { |
|||
return false; |
|||
} |
|||
|
|||
|
|||
protected function preInsertionValidity(\DOMNode $node, ?\DOMNode $child = null) { |
|||
parent::preInsertionValidity($node, $child); |
|||
|
|||
# 6. If parent is a document, and any of the statements below, switched on node, |
|||
# are true, then throw a "HierarchyRequestError" DOMException. |
|||
# |
|||
# DocumentFragment node |
|||
# If node has more than one element child or has a Text node child. |
|||
# Otherwise, if node has one element child and either parent has an element |
|||
# child, child is a doctype, or child is non-null and a doctype is following |
|||
# child. |
|||
if ($node instanceof \DOMDocumentType) { |
|||
if ($node->childNodes->length > 1 || $node->firstChild instanceof Text) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} else { |
|||
if ($node->firstChild instanceof \DOMDocumentType) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
foreach ($this->childNodes as $c) { |
|||
if ($c instanceof Element) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
|
|||
if ($child !== null) { |
|||
$n = $child; |
|||
while ($n = $n->nextSibling) { |
|||
if ($n instanceof \DOMDocumentType) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
# element |
|||
# parent has an element child, child is a doctype, or child is non-null and a |
|||
# doctype is following child. |
|||
elseif ($node instanceof Element) { |
|||
if ($child instanceof \DOMDocumentType) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
if ($child !== null) { |
|||
$n = $child; |
|||
while ($n = $n->nextSibling) { |
|||
if ($n instanceof \DOMDocumentType) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
} |
|||
|
|||
foreach ($this->childNodes as $c) { |
|||
if ($c instanceof Element) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
} |
|||
|
|||
# doctype |
|||
# parent has a doctype child, child is non-null and an element is preceding |
|||
# child, or child is null and parent has an element child. |
|||
elseif ($node instanceof \DOMDocumentType) { |
|||
foreach ($this->childNodes as $c) { |
|||
if ($c instanceof \DOMDocumentType) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
|
|||
if ($child !== null) { |
|||
$n = $child; |
|||
while ($n = $n->prevSibling) { |
|||
if ($n instanceof Element) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
} else { |
|||
foreach ($this->childNodes as $c) { |
|||
if ($c instanceof Element) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected function serializeBlockElementFilter(\DOMNode $ignoredNode): \Closure { |
|||
$blockElementFilter = function($n) use ($ignoredNode) { |
|||
if (!$n->isSameNode($ignoredNode) && $n instanceof Element && $n->namespaceURI === null && (in_array($n->nodeName, self::BLOCK_ELEMENTS) || $n->walk(function($nn) { |
|||
if ($nn instanceof Element && $nn->namespaceURI === null && in_array($nn->nodeName, self::BLOCK_ELEMENTS)) { |
|||
return true; |
|||
} |
|||
})->current() !== null)) { |
|||
return true; |
|||
} |
|||
}; |
|||
|
|||
return $blockElementFilter; |
|||
} |
|||
|
|||
protected function serializeFragment(\DOMNode $node, bool $formatOutput = false): string { |
|||
if ($formatOutput) { |
|||
// Stores the root foreign element when parsing its descendants |
|||
static $foreignElement = null; |
|||
// Flag used if the root foreign element above has block element siblings |
|||
static $foreignElementWithBlockElementSiblings = false; |
|||
// Stores the indention level |
|||
static $indent = 0; |
|||
// Stores the root preformatted element when parsing its descendants |
|||
static $preformattedElement = null; |
|||
// Stores the previous non text node name so it can be used to check for adding |
|||
// additional space. |
|||
static $previousNonTextNodeSiblingName = null; |
|||
} |
|||
|
|||
# 13.3. Serializing HTML fragments |
|||
# |
|||
# 1. If the node serializes as void, then return the empty string. |
|||
if (in_array($node->nodeName, self::VOID_ELEMENTS)) { |
|||
return ''; |
|||
} |
|||
|
|||
# 2. Let s be a string, and initialize it to the empty string. |
|||
$s = ''; |
|||
|
|||
# 3. If the node is a template element, then let the node instead be the |
|||
# template element’s template contents (a DocumentFragment node). |
|||
if ($node instanceof TemplateElement) { |
|||
$node = $node->content; |
|||
} |
|||
|
|||
$nodesLength = $node->childNodes->length; |
|||
# 4. For each child node of the node, in tree order, run the following steps: |
|||
## 1. Let current node be the child node being processed. |
|||
foreach ($node->childNodes as $currentNode) { |
|||
$foreign = ($currentNode->namespaceURI !== null); |
|||
|
|||
if ($this->formatOutput) { |
|||
// Filter meant to be used with DOM walker generator methods which checks if |
|||
// elements are block or if elements are inline with block descendants |
|||
$blockElementFilter = self::serializeBlockElementFilter($currentNode->parentNode); |
|||
} |
|||
|
|||
# 2. Append the appropriate string from the following list to s: |
|||
# If current node is an Element |
|||
if ($currentNode instanceof Element) { |
|||
# If current node is an element in the HTML namespace, the MathML namespace, or |
|||
# the SVG namespace, then let tagname be current node's local name. Otherwise, |
|||
# let tagname be current node's qualified name. |
|||
$tagName = (!$foreign || $currentNode->namespaceURI === Parser::MATHML_NAMESPACE || $currentNode->namespaceURI === Parser::SVG_NAMESPACE) ? $currentNode->localName : $currentNode->nodeName; |
|||
|
|||
// Since tag names can contain characters that are invalid in PHP's XML DOM |
|||
// uncoerce the name when printing if necessary. |
|||
if (strpos($tagName, 'U') !== false) { |
|||
$tagName = $this->uncoerceName($tagName); |
|||
} |
|||
|
|||
if ($formatOutput) { |
|||
$blockElementFilter = self::serializeBlockElementFilter($currentNode); |
|||
$hasChildNodes = ($currentNode->hasChildNodes()); |
|||
$modify = false; |
|||
|
|||
if (!$foreign) { |
|||
if ($hasChildNodes && $preformattedElement === null && in_array($tagName, self::PREFORMATTED_ELEMENTS)) { |
|||
$preformattedElement = $currentNode; |
|||
} |
|||
|
|||
// If a block element, an inline element with block element siblings, or an |
|||
// inline element with block element descendants... |
|||
if (in_array($tagName, self::BLOCK_ELEMENTS) || $currentNode->parentNode->walkShallow($blockElementFilter)->current() !== null || ($hasChildNodes && $currentNode->walk($blockElementFilter)->current() !== null)) { |
|||
$modify = true; |
|||
} |
|||
} else { |
|||
// If a foreign element with block element siblings |
|||
if ($hasChildNodes && $foreignElement === null) { |
|||
$foreignElement = $currentNode; |
|||
if ($currentNode->parentNode->walkShallow($blockElementFilter)->current() !== null) { |
|||
$foreignElementWithBlockElementSiblings = true; |
|||
$modify = true; |
|||
} |
|||
} |
|||
// If a foreign element with a foreign element ancestor with block element |
|||
// siblings |
|||
elseif ($foreignElement !== null && $foreignElementWithBlockElementSiblings) { |
|||
$modify = true; |
|||
} |
|||
} |
|||
|
|||
if ($modify) { |
|||
// If the previous non text node sibling doesn't have the same name as the |
|||
// current node and neither are h1-h6 elements then add an additional newline. |
|||
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $tagName && !(in_array($previousNonTextNodeSiblingName, self::H_ELEMENTS) && in_array($tagName, self::H_ELEMENTS))) { |
|||
$s .= "\n"; |
|||
} |
|||
|
|||
$s .= "\n" . str_repeat(' ', $indent); |
|||
} |
|||
} |
|||
|
|||
|
|||
# Append a U+003C LESS-THAN SIGN character (<), followed by tagname. |
|||
$s .= "<$tagName"; |
|||
|
|||
# If current node's is value is not null, and the element does not have an is |
|||
# attribute in its attribute list, then append the string " is="", followed by |
|||
# current node's is value escaped as described below in attribute mode, followed |
|||
# by a U+0022 QUOTATION MARK character ("). |
|||
// DEVIATION: There is no scripting support in this implementation. |
|||
|
|||
# For each attribute that the element has, append a U+0020 SPACE character, |
|||
# the attribute’s serialized name as described below, a U+003D EQUALS SIGN |
|||
# character (=), a U+0022 QUOTATION MARK character ("), the attribute’s value, |
|||
# escaped as described below in attribute mode, and a second U+0022 QUOTATION |
|||
# MARK character ("). |
|||
foreach ($currentNode->attributes as $attr) { |
|||
# An attribute’s serialized name for the purposes of the previous paragraph |
|||
# must be determined as follows: |
|||
switch ($attr->namespaceURI) { |
|||
# If the attribute has no namespace |
|||
case null: |
|||
# The attribute’s serialized name is the attribute’s local name. |
|||
$name = $attr->localName; |
|||
break; |
|||
# If the attribute is in the XML namespace |
|||
case Parser::XML_NAMESPACE: |
|||
# The attribute’s serialized name is the string "xml:" followed by the |
|||
# attribute’s local name. |
|||
$name = 'xml:' . $attr->localName; |
|||
break; |
|||
# If the attribute is in the XMLNS namespace... |
|||
case Parser::XMLNS_NAMESPACE: |
|||
# ...and the attribute’s local name is xmlns |
|||
if ($attr->localName === 'xmlns') { |
|||
# The attribute’s serialized name is the string "xmlns". |
|||
$name = 'xmlns'; |
|||
} |
|||
# ... and the attribute’s local name is not xmlns |
|||
else { |
|||
# The attribute’s serialized name is the string "xmlns:" followed by the |
|||
# attribute’s local name. |
|||
$name = 'xmlns:' . $attr->localName; |
|||
} |
|||
break; |
|||
# If the attribute is in the XLink namespace |
|||
case Parser::XLINK_NAMESPACE: |
|||
# The attribute’s serialized name is the string "xlink:" followed by the |
|||
# attribute’s local name. |
|||
$name = 'xlink:' . $attr->localName; |
|||
break; |
|||
# If the attribute is in some other namespace |
|||
default: |
|||
# The attribute’s serialized name is the attribute’s qualified name. |
|||
$name = $attr->nodeName; |
|||
} |
|||
// undo any name mangling |
|||
if (strpos($name, 'U') !== false) { |
|||
$name = $this->uncoerceName($name); |
|||
} |
|||
$value = $this->escapeString($attr->value, true); |
|||
$s .= " $name=\"$value\""; |
|||
} |
|||
|
|||
# While the exact order of attributes is UA-defined, and may depend on factors |
|||
# such as the order that the attributes were given in the original markup, the |
|||
# sort order must be stable, such that consecutive invocations of this |
|||
# algorithm serialize an element’s attributes in the same order. |
|||
// Okay. |
|||
|
|||
// When formatting output set the previous non text node sibling name to the |
|||
// current node name so void elements and empty foreign elements will be |
|||
// recognized by their next sibling. |
|||
if ($formatOutput) { |
|||
$previousNonTextNodeSiblingName = $tagName; |
|||
} |
|||
|
|||
# Append a U+003E GREATER-THAN SIGN character (>). |
|||
// DEVIATION: Printing XML-based content such as SVG as if it's HTML might be |
|||
// practical when a browser is serializing, but it's not in this library's |
|||
// usage. So, if the element is foreign and doesn't contain any children close |
|||
// the element instead and continue on to the next child node. |
|||
$hasChildNodes = $currentNode->hasChildNodes(); |
|||
if (!$foreign || $hasChildNodes) { |
|||
$s .= '>'; |
|||
} elseif (!$hasChildNodes) { |
|||
$s .= '/>'; |
|||
continue; |
|||
} |
|||
|
|||
# If current node serializes as void, then continue on to the next child node at |
|||
# this point. |
|||
if (in_array($currentNode->nodeName, self::VOID_ELEMENTS)) { |
|||
continue; |
|||
} |
|||
|
|||
if ($formatOutput) { |
|||
// If formatting output set the previous non text node sibling to null before |
|||
// serializing children. |
|||
$previousNonTextNodeSiblingName = null; |
|||
|
|||
// If formatting output and the element has already been modified increment the |
|||
// indention level |
|||
if ($modify) { |
|||
$indent++; |
|||
} |
|||
} |
|||
|
|||
# Append the value of running the HTML fragment serialization algorithm on the |
|||
# current node element (thus recursing into this algorithm for that element), |
|||
# followed by a U+003C LESS-THAN SIGN character (<), a U+002F SOLIDUS character (/), |
|||
# tagname again, and finally a U+003E GREATER-THAN SIGN character (>). |
|||
$s .= $this->serializeFragment($currentNode, $formatOutput); |
|||
|
|||
if ($formatOutput) { |
|||
if ($modify) { |
|||
// Decrement the indention level. |
|||
$indent--; |
|||
|
|||
if ($preformattedElement === null) { |
|||
// If a foreign element with a foreign element ancestor with block element |
|||
// siblings and has at least one element child or any element with a block |
|||
// element descendant... |
|||
if (($foreign && $foreignElementWithBlockElementSiblings && $currentNode->firstElementChild !== null) || ($currentNode->walk($blockElementFilter)->current() !== null)) { |
|||
$s .= "\n" . str_repeat(' ', $indent); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if ($foreignElement !== null && $currentNode->isSameNode($foreignElement)) { |
|||
$foreignElement = null; |
|||
$foreignElementWithBlockElementSiblings = false; |
|||
} elseif ($preformattedElement !== null && $currentNode->isSameNode($preformattedElement)) { |
|||
$preformattedElement = null; |
|||
} |
|||
|
|||
// Set the previous text node sibling name to the current node's name so it may |
|||
// be recognized by the following sibling. |
|||
$previousNonTextNodeSiblingName = $tagName; |
|||
} |
|||
|
|||
$s .= "</$tagName>"; |
|||
} |
|||
# If current node is a Text node |
|||
elseif ($currentNode instanceof Text) { |
|||
$text = $currentNode->data; |
|||
|
|||
# If the parent of current node is a style, script, xmp, iframe, noembed, |
|||
# noframes, or plaintext element, or if the parent of current node is a noscript |
|||
# element and scripting is enabled for the node, then append the value of |
|||
# current node’s data IDL attribute literally. |
|||
if ($currentNode->parentNode->namespaceURI === null && in_array($currentNode->parentNode->nodeName, [ 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'plaintext' ])) { |
|||
$s .= $text; |
|||
} |
|||
# Otherwise, append the value of current node’s data IDL attribute, escaped as |
|||
# described below. |
|||
else { |
|||
if ($formatOutput) { |
|||
if ($preformattedElement === null) { |
|||
// Condense spaces and tabs into a single space. |
|||
$text = preg_replace('/ +/', ' ', str_replace("\t", ' ', $text)); |
|||
if ($foreignElementWithBlockElementSiblings || $currentNode->parentNode->walk($blockElementFilter)->current() !== null) { |
|||
// If the text node's data is made up of only whitespace characters continue |
|||
// onto the next node |
|||
if (strspn($text, Data::WHITESPACE) === strlen($text)) { |
|||
continue; |
|||
} |
|||
|
|||
// Otherwise, remove newlines from the text node's data; if that causes the data |
|||
// to be empty then continue onto the next node. |
|||
$text = preg_replace('/[\n\x0C\x0D]+/', '', $text); |
|||
if ($text === '') { |
|||
continue; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
$s .= $this->escapeString($text); |
|||
} |
|||
} |
|||
# If current node is a Comment |
|||
elseif ($currentNode instanceof Comment) { |
|||
if ($formatOutput) { |
|||
if ($preformattedElement === null && $foreignElementWithBlockElementSiblings || $currentNode->parentNode->walk($blockElementFilter)->current() !== null) { |
|||
// Add an additional newline if the previous sibling wasn't a comment. |
|||
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $this->nodeName) { |
|||
$s .= "\n"; |
|||
} |
|||
|
|||
$s .= "\n" . str_repeat(' ', $indent); |
|||
} |
|||
|
|||
$previousNonTextNodeSiblingName = $this->nodeName; |
|||
} |
|||
|
|||
# Append the literal string "<!--" (U+003C LESS-THAN SIGN, U+0021 EXCLAMATION |
|||
# MARK, U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS), followed by the value of |
|||
# current node’s data IDL attribute, followed by the literal string "-->" |
|||
# (U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN). |
|||
$s .= "<!--{$currentNode->data}-->"; |
|||
} |
|||
# If current node is a ProcessingInstruction |
|||
elseif ($currentNode instanceof ProcessingInstruction) { |
|||
if ($formatOutput) { |
|||
if ($preformattedElement === null && $foreignElementWithBlockElementSiblings || $currentNode->parentNode->walk($blockElementFilter)->current() !== null) { |
|||
// Add an additional newline if the previous sibling wasn't a processing |
|||
// instruction. |
|||
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $this->nodeName) { |
|||
$s .= "\n"; |
|||
} |
|||
|
|||
$s .= "\n" . str_repeat(' ', $indent); |
|||
} |
|||
|
|||
$previousNonTextNodeSiblingName = $this->nodeName; |
|||
} |
|||
|
|||
# Append the literal string "<?" (U+003C LESS-THAN SIGN, U+003F QUESTION MARK),
|
|||
# followed by the value of current node’s target IDL attribute, followed by a |
|||
# single U+0020 SPACE character, followed by the value of current node’s data |
|||
# IDL attribute, followed by a single U+003E GREATER-THAN SIGN character (>). |
|||
$s .= "<?{$currentNode->target} {$currentNode->data}>";
|
|||
} |
|||
# If current node is a DocumentFragment |
|||
elseif ($currentNode instanceof \DOMDocumentType) { |
|||
# Append the literal string "<!DOCTYPE" (U+003C LESS-THAN SIGN, U+0021 |
|||
# EXCLAMATION MARK, U+0044 LATIN CAPITAL LETTER D, U+004F LATIN CAPITAL LETTER |
|||
# O, U+0043 LATIN CAPITAL LETTER C, U+0054 LATIN CAPITAL LETTER T, U+0059 |
|||
# LATIN CAPITAL LETTER Y, U+0050 LATIN CAPITAL LETTER P, U+0045 LATIN CAPITAL |
|||
# LETTER E), followed by a space (U+0020 SPACE), followed by the value of |
|||
# current node's name IDL attribute, followed by the literal string ">" (U+003E |
|||
# GREATER-THAN SIGN). |
|||
// DEVIATION: The name is trimmed because PHP's DOM does not |
|||
// accept the empty string as a DOCTYPE name |
|||
$name = trim($node->childNodes->item(0)->name, ' '); |
|||
$s .= "<!DOCTYPE $name>"; |
|||
} |
|||
} |
|||
|
|||
# 5. Return s. |
|||
return $s; |
|||
} |
|||
|
|||
|
|||
public function __toString() { |
|||
return $this->serialize(); |
|||
} |
|||
} |
@ -1,11 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class DocumentFragment extends \DOMDocumentFragment { |
|||
use ContainerNode, MoonwalkShallow, ParentNode, ToString, Walk, WalkShallow; |
|||
} |
@ -1,313 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class Element extends \DOMElement { |
|||
use ContainerNode, DocumentOrElement, EscapeString, MagicProperties, Moonwalk, MoonwalkShallow, ParentNode, ToString, Walk, WalkShallow; |
|||
|
|||
protected $_classList; |
|||
|
|||
|
|||
public function __get_classList(): ?TokenList { |
|||
// MensBeam\HTML\TokenList uses WeakReference to prevent a circular reference, |
|||
// so it requires PHP 7.4 to work. |
|||
if (version_compare(\PHP_VERSION, '7.4.0', '>=')) { |
|||
// Only create the class list if it is actually used. |
|||
if ($this->_classList === null) { |
|||
$this->_classList = new TokenList($this, 'class'); |
|||
} |
|||
return $this->_classList; |
|||
} |
|||
return null; // @codeCoverageIgnore |
|||
} |
|||
|
|||
public function __get_innerHTML(): string { |
|||
### DOM Parsing Specification ### |
|||
# 2.3 The InnerHTML mixin |
|||
# |
|||
# On getting, return the result of invoking the fragment serializing algorithm |
|||
# on the context object providing true for the require well-formed flag (this |
|||
# might throw an exception instead of returning a string). |
|||
// DEVIATION: Parsing of XML documents will not be handled by this |
|||
// implementation, so there's no need for the well-formed flag. |
|||
return $this->ownerDocument->serialize($this); |
|||
} |
|||
|
|||
public function __set_innerHTML(string $value) { |
|||
### DOM Parsing Specification ### |
|||
# 2.3 The InnerHTML mixin |
|||
# |
|||
# On setting, these steps must be run: |
|||
# 1. Let context element be the context object's host if the context object is a |
|||
# ShadowRoot object, or the context object otherwise. |
|||
// DEVIATION: There is no scripting in this implementation. |
|||
|
|||
# 2. Let fragment be the result of invoking the fragment parsing algorithm with |
|||
# the new value as markup, and with context element. |
|||
$fragment = Parser::parseFragment($value, $this->ownerDocument, 'UTF-8', $this); |
|||
|
|||
# 3. If the context object is a template element, then let context object be the |
|||
# template's template contents (a DocumentFragment). |
|||
if ($this->nodeName === 'template') { |
|||
$this->content = $fragment; |
|||
} |
|||
# 4. Replace all with fragment within the context object. |
|||
else { |
|||
# To replace all with a node within a parent, run these steps: |
|||
# |
|||
# 1. Let removedNodes be parent’s children. |
|||
// DEVIATION: removedNodes is used below for scripting. There is no scripting in |
|||
// this implementation. |
|||
|
|||
# 2. Let addedNodes be parent’s children. |
|||
// DEVIATION: addedNodes is used below for scripting. There is no scripting in |
|||
// this implementation. |
|||
|
|||
# 3. If node is a DocumentFragment node, then set addedNodes to node’s |
|||
# children. |
|||
|
|||
// DEVIATION: Again, there is no scripting in this implementation. |
|||
# 4. Otherwise, if node is non-null, set addedNodes to « node ». |
|||
// DEVIATION: Yet again, there is no scripting in this implementation. |
|||
|
|||
# 5. Remove all parent’s children, in tree order, with the suppress observers |
|||
# flag set. |
|||
// DEVIATION: There are no observers to suppress as there is no scripting in |
|||
// this implementation. |
|||
while ($this->hasChildNodes()) { |
|||
$this->removeChild($this->firstChild); |
|||
} |
|||
|
|||
# 6. Otherwise, if node is non-null, set addedNodes to « node ». |
|||
# If node is non-null, then insert node into parent before null with the |
|||
# suppress observers flag set. |
|||
// DEVIATION: Yet again, there is no scripting in this implementation. |
|||
|
|||
# 7. If either addedNodes or removedNodes is not empty, then queue a tree |
|||
# mutation record for parent with addedNodes, removedNodes, null, and null. |
|||
// DEVIATION: Normally the tree mutation record would do the actual replacement, |
|||
// but there is no scripting in this implementation. Going to simply append the |
|||
// fragment instead. |
|||
$this->appendChild($fragment); |
|||
} |
|||
} |
|||
|
|||
public function __get_nextElementSibling(): Element { |
|||
# The nextElementSibling getter steps are to return the first following sibling |
|||
# that is an element; otherwise null. |
|||
if ($this->parentNode !== null) { |
|||
$start = false; |
|||
foreach ($this->parentNode->childNodes as $child) { |
|||
if (!$start) { |
|||
if ($child->isSameNode($this)) { |
|||
$start = true; |
|||
} |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if (!$child instanceof Element) { |
|||
continue; |
|||
} |
|||
|
|||
return $child; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public function __get_outerHTML(): string { |
|||
### DOM Parsing Specification ### |
|||
# 2.4 Extensions to the Element interface |
|||
# outerHTML |
|||
# |
|||
# On getting, return the result of invoking the fragment serializing algorithm |
|||
# on a fictional node whose only child is the context object providing true for |
|||
# the require well-formed flag (this might throw an exception instead of |
|||
# returning a string). |
|||
// DEVIATION: Parsing of XML documents will not be handled by this |
|||
// implementation, so there's no need for the well-formed flag. |
|||
return $this->__toString(); |
|||
} |
|||
|
|||
public function __set_outerHTML(string $value) { |
|||
### DOM Parsing Specification ### |
|||
# 2.4 Extensions to the Element interface |
|||
# outerHTML |
|||
# |
|||
# On setting, the following steps must be run: |
|||
# 1. Let parent be the context object's parent. |
|||
$parent = $this->parentNode; |
|||
|
|||
# 2. If parent is null, terminate these steps. There would be no way to obtain a |
|||
# reference to the nodes created even if the remaining steps were run. |
|||
// The spec is unclear here as to what to do. What do you return? Most browsers |
|||
// throw an exception here, so that's what we're going to do. |
|||
if ($parent === null) { |
|||
throw new DOMException(DOMException::OUTER_HTML_FAILED_NOPARENT); |
|||
} |
|||
# 3. If parent is a Document, throw a "NoModificationAllowedError" DOMException. |
|||
elseif ($parent instanceof Document) { |
|||
throw new DOMException(DOMException::NO_MODIFICATION_ALLOWED); |
|||
} |
|||
# 4. parent is a DocumentFragment, let parent be a new Element with: |
|||
# • body as its local name, |
|||
# • The HTML namespace as its namespace, and |
|||
# • The context object's node document as its node document. |
|||
elseif ($parent instanceof DocumentFragment) { |
|||
$parent = $this->ownerDocument->createElement('body'); |
|||
} |
|||
|
|||
# 5. Let fragment be the result of invoking the fragment parsing algorithm with |
|||
# the new value as markup, and parent as the context element. |
|||
$fragment = Parser::parseFragment($value, $this->ownerDocument, 'UTF-8', $parent); |
|||
|
|||
# 6. Replace the context object with fragment within the context object's |
|||
# parent. |
|||
$this->parentNode->replaceChild($fragment, $this); |
|||
} |
|||
|
|||
public function __get_previousElementSibling(): Element { |
|||
# The previousElementSibling getter steps are to return the first preceding |
|||
# sibling that is an element; otherwise null. |
|||
if ($this->parentNode !== null) { |
|||
foreach ($this->parentNode->childNodes as $child) { |
|||
if ($child->isSameNode($this)) { |
|||
return null; |
|||
} |
|||
|
|||
if (!$child instanceof Element) { |
|||
continue; |
|||
} |
|||
|
|||
return $child; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
public function getAttribute($name) { |
|||
// Newer versions of the DOM spec have getAttribute return an empty string only |
|||
// when the attribute exists and is empty, otherwise null. This fixes that. |
|||
$value = parent::getAttribute($name); |
|||
if ($value === '' && !parent::hasAttribute($name)) { |
|||
// the PHP DOM does not acknowledge the presence of XMLNS-namespace attributes |
|||
foreach ($this->attributes as $a) { |
|||
if ($a->nodeName === $name) { |
|||
return $a->value; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
return $value; |
|||
} |
|||
|
|||
public function getAttributeNS($namespaceURI, $localName) { |
|||
// Newer versions of the DOM spec have getAttributeNS return an empty string |
|||
// only when the attribute exists and is empty, otherwise null. This fixes that. |
|||
$value = parent::getAttributeNS($namespaceURI, $localName); |
|||
if ($value === '' && !$this->hasAttributeNS($namespaceURI, $localName)) { |
|||
return null; |
|||
} |
|||
return $value; |
|||
} |
|||
|
|||
public function hasAttribute($name) { |
|||
if (!parent::hasAttribute($name)) { |
|||
foreach ($this->attributes as $a) { |
|||
if ($a->nodeName === $name) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
public function setAttribute($name, $value) { |
|||
$this->setAttributeNS(null, $name, $value); |
|||
} |
|||
|
|||
public function setAttributeNS($namespaceURI, $qualifiedName, $value) { |
|||
// Normalize the attribute name and namespace URI per modern DOM specifications. |
|||
if ($namespaceURI !== null) { |
|||
$namespaceURI = trim($namespaceURI); |
|||
} |
|||
$qualifiedName = trim($qualifiedName); |
|||
if ($namespaceURI === null && ($this->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE && !$this->hasAttributeNS($namespaceURI, $qualifiedName)) { |
|||
$qualifiedName = trim(strtolower($qualifiedName)); |
|||
} |
|||
// If setting a class attribute and classList has been invoked use classList to |
|||
// set it. |
|||
if ($qualifiedName === 'class' && $namespaceURI === null && $this->_classList !== null) { |
|||
$this->_classList->value = $value; |
|||
} elseif ($namespaceURI === Parser::XMLNS_NAMESPACE) { |
|||
// NOTE: We create attribute nodes so that xmlns attributes |
|||
// don't get lost; otherwise they cannot be serialized |
|||
$a = @$this->ownerDocument->createAttributeNS($namespaceURI, $qualifiedName); |
|||
if ($a === false) { |
|||
// The document element does not exist yet, so we need |
|||
// to insert this element into the document |
|||
$this->ownerDocument->appendChild($this); |
|||
$a = $this->ownerDocument->createAttributeNS($namespaceURI, $qualifiedName); |
|||
$this->ownerDocument->removeChild($this); |
|||
} |
|||
$a->value = $this->escapeString($value, true); |
|||
$this->setAttributeNodeNS($a); |
|||
} else { |
|||
try { |
|||
parent::setAttributeNS($namespaceURI, $qualifiedName, $value); |
|||
} catch (\DOMException $e) { |
|||
// The attribute name is invalid for XML |
|||
// Replace any offending characters with "UHHHHHH" where H are the |
|||
// uppercase hexadecimal digits of the character's code point |
|||
$this->ownerDocument->mangledAttributes = true; |
|||
if ($namespaceURI !== null) { |
|||
$qualifiedName = implode(":", array_map([$this, "coerceName"], explode(":", $qualifiedName, 2))); |
|||
} else { |
|||
$qualifiedName = $this->coerceName($qualifiedName); |
|||
} |
|||
parent::setAttributeNS($namespaceURI, $qualifiedName, $value); |
|||
} |
|||
if ($qualifiedName === "id" && $namespaceURI === null) { |
|||
$this->setIdAttribute($qualifiedName, true); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public function setAttributeNode(\DOMAttr $attribute) { |
|||
return $this->setAttributeNodeNS($attribute, null); |
|||
} |
|||
|
|||
public function setAttributeNodeNS(\DOMAttr $attribute) { |
|||
$fixId = false; |
|||
if ($attribute->namespaceURI === null) { |
|||
if ($attribute->name === 'id') { |
|||
$fixId = true; |
|||
} |
|||
// If appending a class attribute node, and classList has been invoked set |
|||
// the class using classList instead of appending the attribute node. Will |
|||
// return the created node instead. TokenList appends an attribute node |
|||
// internally to set the class attribute, so to prevent an infinite call loop |
|||
// from occurring, a check between the normalized value and classList's |
|||
// serialized value is performed. The spec is vague on how this is supposed to |
|||
// be handled. |
|||
elseif ($this->_classList !== null && $attribute->name === 'class' && preg_replace(Data::WHITESPACE_REGEX, ' ', $attribute->value) !== $this->_classList->value) { |
|||
$this->_classList->value = $attribute->value; |
|||
return $this->getAttributeNode('class'); |
|||
} |
|||
} |
|||
$result = parent::setAttributeNodeNS($attribute); |
|||
if ($fixId) { |
|||
$this->setIdAttribute($attribute->name, true); |
|||
} |
|||
return $result; |
|||
} |
|||
} |
@ -1,70 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// This is a write-only map of elements which need to be kept in memory; it |
|||
// exists because values of properties on derived DOM classes are lost unless at |
|||
// least one PHP reference is kept for the element somewhere in userspace. This |
|||
// is that somewhere. It is at present only used for template elements. |
|||
class ElementMap { |
|||
protected static $_storage = []; |
|||
|
|||
public static function delete(Element $element) { |
|||
foreach (self::$_storage as $k => $v) { |
|||
if ($v->isSameNode($element)) { |
|||
unset(self::$_storage[$k]); |
|||
self::$_storage = array_values(self::$_storage); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function destroy(Document $document) { |
|||
$changed = false; |
|||
foreach (self::$_storage as $k => $v) { |
|||
if ($v->ownerDocument->isSameNode($document)) { |
|||
unset(self::$_storage[$k]); |
|||
$changed = true; |
|||
} |
|||
} |
|||
|
|||
if ($changed) { |
|||
self::$_storage = array_values(self::$_storage); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function getIterator(): \Traversable { |
|||
foreach (self::$_storage as $v) { |
|||
yield $v; |
|||
} |
|||
} |
|||
|
|||
public static function has(Element $element) { |
|||
foreach (self::$_storage as $v) { |
|||
if ($v->isSameNode($element)) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function set(Element $element) { |
|||
if (!self::has($element)) { |
|||
self::$_storage[] = $element; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
@ -1,11 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class ProcessingInstruction extends \DOMProcessingInstruction { |
|||
use LeafNode, Moonwalk, ToString; |
|||
} |
@ -1,29 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
/** Class specifically for template elements to handle its content property. */ |
|||
class TemplateElement extends Element { |
|||
public $content = null; |
|||
|
|||
public function __construct(Document $ownerDocument, string $qualifiedName, ?string $value = null, string $namespace = '') { |
|||
parent::__construct($qualifiedName, $value, $namespace); |
|||
|
|||
// Elements that are created by their constructor in PHP aren't owned by any |
|||
// document and are readonly until owned by one. Temporarily append to a |
|||
// document fragment so the element will be owned by the supplied owner |
|||
// document. |
|||
$frag = $ownerDocument->createDocumentFragment(); |
|||
$frag->appendChild($this); |
|||
$frag->removeChild($this); |
|||
unset($frag); |
|||
} |
|||
|
|||
public function __destruct() { |
|||
ElementMap::delete($this); |
|||
} |
|||
} |
@ -1,317 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
class TokenList implements \ArrayAccess, \Countable, \Iterator { |
|||
use MagicProperties; |
|||
|
|||
protected $localName; |
|||
protected $element; |
|||
|
|||
protected $_length = 0; |
|||
protected $position = 0; |
|||
# A DOMTokenList object has an associated token set (a set), which is initially |
|||
# empty. |
|||
protected $tokenSet = []; |
|||
|
|||
private const ASCII_WHITESPACE_REGEX = '/[\t\n\x0c\r ]+/'; |
|||
|
|||
|
|||
public function __get_length(): int { |
|||
return $this->_length; |
|||
} |
|||
|
|||
public function __get_value(): string { |
|||
return $this->__toString(); |
|||
} |
|||
|
|||
public function __set_value(string $value) { |
|||
$this->tokenSet = $this->parseOrderedSet($value); |
|||
$this->_length = count($this->tokenSet); |
|||
} |
|||
|
|||
|
|||
public function __construct(\DOMElement $element, string $attributeLocalName) { |
|||
# A DOMTokenList object also has an associated element and an attribute’s local |
|||
# name. |
|||
|
|||
# When a DOMTokenList object is created, then: |
|||
# |
|||
# 1. Let element be associated element. |
|||
// Using a weak reference here to prevent a circular reference. |
|||
$this->element = \WeakReference::create($element); |
|||
# 2. Let localName be associated attribute’s local name. |
|||
$this->localName = $attributeLocalName; |
|||
# 3. Let value be the result of getting an attribute value given element and |
|||
# localName. |
|||
$value = $element->getAttribute($attributeLocalName); |
|||
# 4. Run the attribute change steps for element, localName, value, value, and |
|||
# null. |
|||
$this->attributeChange($attributeLocalName, $value, $value); |
|||
} |
|||
|
|||
public function add(...$tokens) { |
|||
# 1. For each token in tokens: |
|||
foreach ($tokens as $token) { |
|||
# 1. If token is the empty string, then throw a "SyntaxError" DOMException. |
|||
if ($token === '') { |
|||
throw new DOMException(DOMException::SYNTAX_ERROR); |
|||
} |
|||
|
|||
# 2. If token contains any ASCII whitespace, then throw an |
|||
# "InvalidCharacterError" DOMException. |
|||
if (preg_match(Data::WHITESPACE_REGEX, $token)) { |
|||
throw new DOMException(DOMException::INVALID_CHARACTER); |
|||
} |
|||
} |
|||
|
|||
# 2. For each token in tokens, append token to this’s token set. |
|||
foreach ($tokens as $token) { |
|||
if (!in_array($token, $this->tokenSet)) { |
|||
// The spec does not say to trim, but browsers do. |
|||
$this->tokenSet[] = trim($token); |
|||
$this->_length++; |
|||
} |
|||
} |
|||
|
|||
# 3. Run the update steps. |
|||
$this->update(); |
|||
} |
|||
|
|||
public function contains(string $token): bool { |
|||
return (in_array($token, $this->tokenSet)); |
|||
} |
|||
|
|||
public function count(): int { |
|||
return $this->_length; |
|||
} |
|||
|
|||
public function current() { |
|||
return $this->item($this->position); |
|||
} |
|||
|
|||
public function item(int $index): string { |
|||
return $this->tokenSet[$index]; |
|||
} |
|||
|
|||
public function key() { |
|||
return $this->position; |
|||
} |
|||
|
|||
public function next() { |
|||
++$this->position; |
|||
} |
|||
|
|||
public function rewind() { |
|||
$this->position = 0; |
|||
} |
|||
|
|||
public function offsetExists($offset) { |
|||
return $this->contains($offset); |
|||
} |
|||
|
|||
public function offsetGet($offset): string { |
|||
return $this->item($offset); |
|||
} |
|||
|
|||
public function offsetSet($offset, $value) { |
|||
$this->add($offset); |
|||
} |
|||
|
|||
public function offsetUnset($offset) { |
|||
$this->remove($offset); |
|||
} |
|||
|
|||
public function remove(...$tokens) { |
|||
# 1. For each token in tokens: |
|||
foreach ($tokens as $token) { |
|||
# 1. If token is the empty string, then throw a "SyntaxError" DOMException. |
|||
if ($token === '') { |
|||
throw new DOMException(DOMException::SYNTAX_ERROR); |
|||
} |
|||
|
|||
# 2. If token contains any ASCII whitespace, then throw an |
|||
# "InvalidCharacterError" DOMException. |
|||
if (preg_match(Data::WHITESPACE_REGEX, $token)) { |
|||
throw new DOMException(DOMException::INVALID_CHARACTER); |
|||
} |
|||
} |
|||
|
|||
# For each token in tokens, remove token from this’s token set. |
|||
$changed = false; |
|||
foreach ($tokens as $token) { |
|||
if (in_array($token, $this->tokenSet)) { |
|||
unset($this->tokenSet[$token]); |
|||
$this->_length--; |
|||
$changed = true; |
|||
} |
|||
} |
|||
|
|||
if ($changed) { |
|||
$this->tokenSet = array_values($this->tokenSet); |
|||
} |
|||
|
|||
# 3. Run the update steps. |
|||
$this->update(); |
|||
} |
|||
|
|||
public function replace(string $token, string $newToken): bool { |
|||
# 1. If either token or newToken is the empty string, then throw a "SyntaxError" |
|||
# DOMException. |
|||
if ($token === '' || $newToken === '') { |
|||
throw new DOMException(DOMException::SYNTAX_ERROR); |
|||
} |
|||
|
|||
# 2. If either token or newToken contains any ASCII whitespace, then throw an |
|||
# "InvalidCharacterError" DOMException. |
|||
if (preg_match(Data::WHITESPACE_REGEX, $token) || preg_match(Data::WHITESPACE_REGEX, $newToken)) { |
|||
throw new DOMException(DOMException::INVALID_CHARACTER); |
|||
} |
|||
|
|||
// The spec does not say to trim, but browsers do. |
|||
$token = trim($token); |
|||
$newToken = trim($token); |
|||
|
|||
# 3. If this’s token set does not contain token, then return false. |
|||
if (!isset($this->tokenSet[$token])) { |
|||
return false; |
|||
} |
|||
|
|||
# 4. Replace token in this’s token set with newToken. |
|||
$index = array_search($token, $this->tokenSet); |
|||
$this->tokenSet[$index] = $newToken; |
|||
|
|||
# 5. Run the update steps. |
|||
$this->update(); |
|||
|
|||
# 6. Return true. |
|||
return true; |
|||
} |
|||
|
|||
public function supports(string $token): bool { |
|||
# 1. Let result be the return value of validation steps called with token. |
|||
# 2. Return result. |
|||
# |
|||
# A DOMTokenList object’s validation steps for a given token are: |
|||
# |
|||
# 1. If the associated attribute’s local name does not define supported tokens, |
|||
# throw a TypeError. |
|||
# 2. Let lowercase token be a copy of token, in ASCII lowercase. |
|||
# 3. If lowercase token is present in supported tokens, return true. |
|||
# 4. Return false. |
|||
|
|||
// This class is presently only used for Element::classList, and it supports any |
|||
// valid class name as a token. So, there's nothing to do here at the moment. |
|||
// Just return true. |
|||
return true; |
|||
} |
|||
|
|||
public function toggle(string $token, ?bool $force = false): bool { |
|||
# 1. If token is the empty string, then throw a "SyntaxError" DOMException. |
|||
if ($token === '') { |
|||
throw new DOMException(DOMException::SYNTAX_ERROR); |
|||
} |
|||
|
|||
# 2. If token contains any ASCII whitespace, then throw an |
|||
# "InvalidCharacterError" DOMException. |
|||
if (preg_match(Data::WHITESPACE_REGEX, $token)) { |
|||
throw new DOMException(DOMException::INVALID_CHARACTER); |
|||
} |
|||
|
|||
# 3. If this’s token set[token] exists, then: |
|||
if (isset($this->tokenSet[$token])) { |
|||
# 1. If force is either not given or is false, then remove token from this’s |
|||
# token set, run the update steps and return false. |
|||
if (!$force) { |
|||
$this->remove($token); |
|||
return false; |
|||
} |
|||
|
|||
# 2. Return true. |
|||
return true; |
|||
} |
|||
# 4. Otherwise, if force not given or is true, append token to this’s token set, |
|||
# run the update steps, and return true. |
|||
else { |
|||
$this->add($token); |
|||
return true; |
|||
} |
|||
|
|||
# 5. Return false. |
|||
return false; |
|||
} |
|||
|
|||
public function valid() { |
|||
return array_key_exists($this->position, $this->tokenSet); |
|||
} |
|||
|
|||
|
|||
protected function attributeChange(string $localName, ?string $oldValue = null, ?string $value = null, ?string $namespace = null) { |
|||
# A DOMTokenList object has these attribute change steps for its associated |
|||
# element: |
|||
# |
|||
# 1. If localName is associated attribute’s local name, namespace is null, and |
|||
# value is null, then empty token set. |
|||
if ($localName !== $this->localName || $namespace !== null) { |
|||
return; |
|||
} |
|||
|
|||
if ($value === null) { |
|||
$this->tokenSet = []; |
|||
$this->tokenKeys = []; |
|||
$this->_length = 0; |
|||
} |
|||
# 2. Otherwise, if localName is associated attribute’s local name, namespace is |
|||
# null, then set token set to value, parsed. |
|||
else { |
|||
$this->tokenSet = $this->parseOrderedSet($value); |
|||
$this->_length = count($this->tokenSet); |
|||
} |
|||
} |
|||
|
|||
protected function parseOrderedSet(string $input) { |
|||
if ($input === '') { |
|||
return []; |
|||
} |
|||
|
|||
# The ordered set parser takes a string input and then runs these steps: |
|||
# |
|||
# 1. Let inputTokens be the result of splitting input on ASCII whitespace. |
|||
// There isn't a Set object in php, so make sure all the tokens are unique. |
|||
$inputTokens = array_unique(preg_split(Data::WHITESPACE_REGEX, $input)); |
|||
|
|||
# 2. Let tokens be a new ordered set. |
|||
# 3. For each token in inputTokens, append token to tokens. |
|||
# 4. Return tokens. |
|||
// There isn't a Set object in php, so just return the uniqued input tokens. |
|||
return $inputTokens; |
|||
} |
|||
|
|||
protected function update() { |
|||
# A DOMTokenList object’s update steps are: |
|||
# |
|||
# 1. If the associated element does not have an associated attribute and token |
|||
# set is empty, then return. |
|||
// Not sure what this is about. This class is constructed with a provided |
|||
// associated element and attribute; there is no need to do this. |
|||
|
|||
# 2. Set an attribute value for the associated element using associated |
|||
# attribute’s local name and the result of running the ordered set serializer |
|||
# for token set. |
|||
$element = $this->element->get(); |
|||
$class = $element->ownerDocument->createAttribute($this->localName); |
|||
$class->value = $this->__toString(); |
|||
$element->setAttributeNode($class); |
|||
} |
|||
|
|||
|
|||
public function __toString(): string { |
|||
# The ordered set serializer takes a set and returns the concatenation of set |
|||
# using U+0020 SPACE. |
|||
return implode(' ', $this->tokenSet); |
|||
} |
|||
} |
@ -1,104 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// Node in the DOM spec is dirty. Many nodes which inherit from it inherit |
|||
// methods it cannot use which all check for this and throw exceptions. This is |
|||
// for nodes which DO have child nodes. |
|||
trait ContainerNode { |
|||
use Node; |
|||
|
|||
public function appendChild($node) { |
|||
$this->preInsertionValidity($node); |
|||
|
|||
$result = parent::appendChild($node); |
|||
if ($result !== false && $result instanceof TemplateElement) { |
|||
if ($result instanceof TemplateElement) { |
|||
ElementMap::set($result); |
|||
} |
|||
} |
|||
return $result; |
|||
} |
|||
|
|||
public function insertBefore($node, $child = null) { |
|||
$this->preInsertionValidity($node, $child); |
|||
|
|||
$result = parent::insertBefore($node, $child); |
|||
if ($result !== false) { |
|||
if ($result instanceof TemplateElement) { |
|||
ElementMap::set($result); |
|||
} |
|||
if ($child instanceof TemplateElement) { |
|||
ElementMap::delete($child); |
|||
} |
|||
} |
|||
return $result; |
|||
} |
|||
|
|||
public function removeChild($child) { |
|||
$result = parent::removeChild($child); |
|||
if ($result !== false && $result instanceof TemplateElement) { |
|||
ElementMap::delete($child); |
|||
} |
|||
return $result; |
|||
} |
|||
|
|||
public function replaceChild($node, $child) { |
|||
$result = parent::replaceChild($node, $child); |
|||
if ($result !== false) { |
|||
if ($result instanceof TemplateElement) { |
|||
ElementMap::set($child); |
|||
} |
|||
if ($child instanceof TemplateElement) { |
|||
ElementMap::delete($child); |
|||
} |
|||
} |
|||
return $result; |
|||
} |
|||
|
|||
|
|||
protected function preInsertionValidity(\DOMNode $node, ?\DOMNode $child = null) { |
|||
// "parent" in the spec comments below is $this |
|||
|
|||
# 1. If parent is not a Document, DocumentFragment, or Element node, then throw |
|||
# a "HierarchyRequestError" DOMException. |
|||
// Not necessary because they've been disabled and return hierarchy request |
|||
// errors in "leaf nodes". |
|||
|
|||
# 2. If node is a host-including inclusive ancestor of parent, then throw a |
|||
# "HierarchyRequestError" DOMException. |
|||
# |
|||
# An object A is a host-including inclusive ancestor of an object B, if either |
|||
# A is an inclusive ancestor of B, or if B’s root has a non-null host and A is a |
|||
# host-including inclusive ancestor of B’s root’s host. |
|||
// DEVIATION: The baseline for this library is PHP 7.1, and without |
|||
// WeakReferences we cannot add a host property to DocumentFragment to check |
|||
// against. |
|||
// This is handled just fine by PHP's DOM. |
|||
|
|||
# 3. If child is non-null and its parent is not parent, then throw a |
|||
# "NotFoundError" DOMException. |
|||
// This is handled just fine by PHP's DOM. |
|||
|
|||
# 4. If node is not a DocumentFragment, DocumentType, Element, Text, |
|||
# ProcessingInstruction, or Comment node, then throw a "HierarchyRequestError" |
|||
# DOMException. |
|||
if (!$node instanceof DocumentFragment && !$node instanceof \DOMDocumentType && !$node instanceof Element && !$node instanceof Text && !$node instanceof ProcessingInstruction && !$node instanceof Comment) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
# 5. If either node is a Text node and parent is a document, or node is a |
|||
# doctype and parent is not a document, then throw a "HierarchyRequestError" |
|||
# DOMException. |
|||
// Not necessary because they've been disabled and return hierarchy request |
|||
// errors in "leaf nodes". |
|||
|
|||
# 6. If parent is a document, and any of the statements below, switched on node, |
|||
# are true, then throw a "HierarchyRequestError" DOMException. |
|||
// Handled by the Document class. |
|||
} |
|||
} |
@ -1,57 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// This exists because the DOM spec for some stupid reason doesn't give |
|||
// DocumentFragment some methods. |
|||
trait DocumentOrElement { |
|||
public function getElementsByClassName(string $classNames): \DOMNodeList { |
|||
# The list of elements with class names classNames for a node root is the |
|||
# HTMLCollection returned by the following algorithm: |
|||
// DEVIATION: There's no HTMLCollection. The result will be a DOMNodeList |
|||
// instead. It is, fortunately, almost exactly the same thing anyway. |
|||
|
|||
# 1. Let classes be the result of running the ordered set parser on classNames. |
|||
# |
|||
## The ordered set parser takes a string input and then runs these steps: |
|||
## |
|||
## 1. Let inputTokens be the result of splitting input on ASCII whitespace. |
|||
// There isn't a Set object in php, so make sure all the tokens are unique. |
|||
$inputTokens = ($classNames !== '') ? array_unique(preg_split(Data::WHITESPACE_REGEX, $classNames)) : []; |
|||
|
|||
$isDocument = ($this instanceof Document); |
|||
$document = ($isDocument) ? $this : $this->ownerDocument; |
|||
|
|||
## 2. Let tokens be a new ordered set. |
|||
## 3. For each token in inputTokens, append token to tokens. |
|||
## 4. Return tokens. |
|||
// There isn't a Set object in php, so just use the uniqued input tokens. |
|||
|
|||
# 2. If classes is the empty set, return an empty HTMLCollection. |
|||
// DEVIATION: We can't do that, so let's create a bogus Xpath query instead. |
|||
if ($inputTokens === []) { |
|||
$ook = $document->createElement('ook'); |
|||
$query = $document->xpath->query('//eek', $ook); |
|||
unset($ook); |
|||
return $query; |
|||
} |
|||
|
|||
# 3. Return a HTMLCollection rooted at root, whose filter matches descendant |
|||
# elements that have all their classes in classes. |
|||
# |
|||
# The comparisons for the classes must be done in an ASCII case-insensitive manner |
|||
# if root’s node document’s mode is "quirks"; otherwise in an identical to manner. |
|||
// DEVIATION: Since we can't just create a \DOMNodeList we must instead query the document with XPath with the root element to get a list. |
|||
|
|||
$query = '//*'; |
|||
foreach ($inputTokens as $token) { |
|||
$query .= "[@class=\"$token\"]"; |
|||
} |
|||
|
|||
return ($isDocument) ? $document->xpath->query($query) : $document->xpath->query($query, $this); |
|||
} |
|||
} |
@ -1,56 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
use MensBeam\Intl\Encoding\UTF8; |
|||
|
|||
trait EscapeString { |
|||
protected function escapeString(string $string, bool $attribute = false): string { |
|||
# Escaping a string (for the purposes of the algorithm above) consists of |
|||
# running the following steps: |
|||
|
|||
# 1. Replace any occurrence of the "&" character by the string "&". |
|||
# 2. Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the |
|||
# string " ". |
|||
$string = str_replace(['&', "\u{A0}"], ['&', ' '], $string); |
|||
# 3. If the algorithm was invoked in the attribute mode, replace any |
|||
# occurrences of the """ character by the string """. |
|||
# 4. If the algorithm was not invoked in the attribute mode, replace any |
|||
# occurrences of the "<" character by the string "<", and any |
|||
# occurrences of the ">" character by the string ">". |
|||
return ($attribute) ? str_replace('"', '"', $string) : str_replace(['<', '>'], ['<', '>'], $string); |
|||
} |
|||
|
|||
protected function coerceName(string $name): string { |
|||
// This matches the inverse of the production of NameChar in XML 1.0, |
|||
// with the added exclusion of ":" from allowed characters |
|||
// See https://www.w3.org/TR/REC-xml/#NT-NameStartChar |
|||
preg_match_all('/[^\-\.0-9\x{B7}\x{300}-\x{36F}\x{203F}-\x{2040}A-Za-z_\x{C0}-\x{D6}\x{D8}-\x{F6}\x{F8}-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}]/u', $name, $m); |
|||
foreach (array_unique($m[0], \SORT_STRING) as $c) { |
|||
$o = (new UTF8($c))->nextCode(); |
|||
$esc = "U".str_pad(strtoupper(dechex($o)), 6, "0", \STR_PAD_LEFT); |
|||
$name = str_replace($c, $esc, $name); |
|||
} |
|||
// Apply stricter rules to the first character |
|||
if (preg_match('/^[^A-Za-z_\x{C0}-\x{D6}\x{D8}-\x{F6}\x{F8}-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}]/u', $name, $m)) { |
|||
$c = $m[0]; |
|||
$o = (new UTF8($c))->nextCode(); |
|||
$esc = "U".str_pad(strtoupper(dechex($o)), 6, "0", \STR_PAD_LEFT); |
|||
$name = $esc.substr($name, strlen($c)); |
|||
} |
|||
return $name; |
|||
} |
|||
|
|||
protected function uncoerceName(string $name): string { |
|||
preg_match_all('/U[0-9A-F]{6}/', $name, $m); |
|||
foreach (array_unique($m[0], \SORT_STRING) as $o) { |
|||
$c = UTF8::encode(hexdec(substr($o, 1))); |
|||
$name = str_replace($o, $c, $name); |
|||
} |
|||
return $name; |
|||
} |
|||
} |
@ -1,31 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// Node in the DOM spec is dirty. Many nodes which inherit from it inherit |
|||
// methods it cannot use which all check for this and throw exceptions. This is |
|||
// for nodes which DO NOT have child nodes. |
|||
trait LeafNode { |
|||
use Node; |
|||
|
|||
|
|||
public function appendChild($node) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
public function insertBefore($node, $child = null) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
public function removeChild($child) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
|
|||
public function replaceChild($node, $child) { |
|||
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR); |
|||
} |
|||
} |
@ -1,64 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
/** |
|||
* Getters and setters in PHP sucks. Instead of having getter and setter |
|||
* function types for classes we instead have the __get and __set magic methods |
|||
* to handle all properties. Not only are they unwieldy to use when you have |
|||
* many properties they also become difficult to handle when inheriting where |
|||
* traits are involved. This trait attempts to create hackish getter and setter |
|||
* functions that can be extended by simple inheritance. |
|||
*/ |
|||
trait MagicProperties { |
|||
public function __get(string $name) { |
|||
// If a getter method exists return it. Otherwise, trigger a property does not |
|||
// exist fatal error. |
|||
$methodName = $this->getMagicPropertyMethodName($name); |
|||
if (!method_exists($this, $methodName)) { |
|||
trigger_error("Property \"$name\" does not exist", \E_USER_ERROR); |
|||
} |
|||
return call_user_func([ $this, $methodName ]); |
|||
} |
|||
|
|||
public function __isset(string $name): bool { |
|||
return (method_exists($this, $this->getMagicPropertyMethodName($name))); |
|||
} |
|||
|
|||
public function __set(string $name, $value) { |
|||
// If a setter method exists return that. |
|||
$methodName = $this->getMagicPropertyMethodName($name, false); |
|||
if (method_exists($this, $methodName)) { |
|||
call_user_func([ $this, $methodName ], $value); |
|||
return; |
|||
} |
|||
|
|||
// Otherwise, if a getter exists then trigger a readonly property fatal error. |
|||
// Finally, if a getter doesn't exist trigger a property does not exist fatal |
|||
// error. |
|||
if (method_exists($this, $this->getMagicPropertyMethodName($name))) { |
|||
trigger_error("Cannot write readonly property \"$name\"", \E_USER_ERROR); |
|||
} else { |
|||
trigger_error("Property \"$name\" does not exist", \E_USER_ERROR); |
|||
} |
|||
} |
|||
|
|||
public function __unset(string $name) { |
|||
$methodName = $this->getMagicPropertyMethodName($name, false); |
|||
if (!method_exists($this, $methodName)) { |
|||
trigger_error("Cannot write readonly property \"$name\"", \E_USER_ERROR); |
|||
} |
|||
|
|||
call_user_func([ $this, $methodName ], null); |
|||
} |
|||
|
|||
|
|||
private function getMagicPropertyMethodName(string $name, bool $get = true): string { |
|||
return "__" . (($get) ? 'get' : 'set') . "_{$name}"; |
|||
} |
|||
} |
@ -1,40 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
trait Moonwalk { |
|||
/** Generator which walks up the DOM. Nonstandard. */ |
|||
public function moonwalk(?\Closure $filter = null): \Generator { |
|||
return $this->moonwalkGenerator($this, $filter); |
|||
} |
|||
|
|||
private function moonwalkGenerator(\DOMNode $node, ?\Closure $filter = null) { |
|||
do { |
|||
while (true) { |
|||
if ($filter === null || $filter($node)) { |
|||
yield $node; |
|||
} |
|||
|
|||
// If node is an instance of DocumentFragment then it might be the content |
|||
// fragment of a template element, so iterate through all template elements |
|||
// stored in the element map and see if node is the fragment of one of the |
|||
// templates; if it is change node to the template element and reprocess. Magic! |
|||
// Can walk backwards THROUGH templates! |
|||
if ($node instanceof DocumentFragment) { |
|||
foreach (ElementMap::getIterator() as $element) { |
|||
if ($element->ownerDocument->isSameNode($node->ownerDocument) && $element instanceof TemplateElement && $element->content->isSameNode($node)) { |
|||
$node = $element; |
|||
continue; |
|||
} |
|||
} |
|||
} |
|||
|
|||
break; |
|||
} |
|||
} while ($node = $node->parentNode); |
|||
} |
|||
} |
@ -1,27 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
trait MoonwalkShallow { |
|||
/** |
|||
* Generator which just walks through a node's child nodes in reverse. |
|||
* Nonstandard. |
|||
* |
|||
* @param ?\Closure $filter - An optional closure to use to filter |
|||
*/ |
|||
public function moonwalkShallow(?\Closure $filter = null): \Generator { |
|||
$node = (!$this instanceof TemplateElement) ? $this : $this->content; |
|||
|
|||
$childNodesLength = $node->childNodes->length; |
|||
for ($childNodesLength = $node->childNodes->length, $i = $childNodesLength - 1; $i >= 0; $i--) { |
|||
$child = $node->childNodes[$i]; |
|||
if ($filter === null || $filter($child)) { |
|||
yield $child; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,21 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
// Extensions to PHP's DOM cannot inherit from an extended Node parent, so a |
|||
// trait is the next best thing... |
|||
trait Node { |
|||
// Disable C14N |
|||
public function C14N($exclusive = null, $with_comments = null, ?array $xpath = null, ?array $ns_prefixes = null): bool { |
|||
return false; |
|||
} |
|||
|
|||
// Disable C14NFile |
|||
public function C14NFile($uri, $exclusive = null, $with_comments = null, ?array $xpath = null, ?array $ns_prefixes = null): bool { |
|||
return false; |
|||
} |
|||
} |
@ -1,243 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
if (version_compare(\PHP_VERSION, '8.0', '>=')) { |
|||
# 4.2.6. Mixin ParentNode |
|||
trait ParentNode { |
|||
public function __get_children(): \DOMNodeList { |
|||
# The children getter steps are to return an HTMLCollection collection rooted at |
|||
# this matching only element children. |
|||
// DEVIATION: HTMLCollection doesn't exist in PHP's DOM, and \DOMNodeList is |
|||
// almost identical; so, using that. PHP's DOM doesn't provide the end user any |
|||
// way to create a \DOMNodeList from scratch, so going to cheat and use XPath to |
|||
// make one for us. |
|||
|
|||
$isDocument = ($this instanceof Document); |
|||
$document = ($isDocument) ? $this : $this->ownerDocument; |
|||
return $document->xpath->query('//*', (!$isDocument) ? $this : null); |
|||
} |
|||
|
|||
public function replaceChildren(...$nodes) { |
|||
# The replaceChildren(nodes) method steps are: |
|||
# 1. Let node be the result of converting nodes into a node given nodes and |
|||
# this’s node document. |
|||
$node = $this->convertNodesToNode($nodes); |
|||
# 2. Ensure pre-insertion validity of node into this before null. |
|||
$this->preInsertionValidity($node); |
|||
# 3. Replace all with node within this. |
|||
# |
|||
# To replace all with a node within a parent, run these steps: |
|||
# 1. Let removedNodes be parent’s children. |
|||
$removedNodes = $this->childNodes; |
|||
# 2. Let addedNodes be the empty set. |
|||
$addedNodes = []; |
|||
# 3. If node is a DocumentFragment node, then set addedNodes to node’s children. |
|||
if ($node instanceof DocumentFragment) { |
|||
$addedNodes = $node->childNodes; |
|||
} |
|||
# 4. Otherwise, if node is non-null, set addedNodes to « node ». |
|||
elseif ($node !== null) { |
|||
$addedNodes = node; |
|||
} |
|||
# 5. Remove all parent’s children, in tree order, with the suppress observers |
|||
# flag set. |
|||
// DEVIATION: There is no scripting in this implementation, so cannnot set |
|||
// suppress observers flag. |
|||
while ($this->hasChildNodes()) { |
|||
$this->removeChild($this->firstChild); |
|||
} |
|||
# 6. If node is non-null, then insert node into parent before null with the |
|||
# suppress observers flag set. |
|||
// DEVIATION: There is no scripting in this implementation, so cannnot set |
|||
// suppress observers flag. |
|||
if ($node !== null) { |
|||
$this->appendChild($node); |
|||
} |
|||
# 7. If either addedNodes or removedNodes is not empty, then queue a tree |
|||
# mutation record for parent with addedNodes, removedNodes, null, and null. |
|||
// DEVIATION: There is no scripting in this implementation |
|||
} |
|||
|
|||
private function convertNodesToNode(array $nodes): \DOMNode { |
|||
# To convert nodes into a node, given nodes and document, run these steps: |
|||
# 1. Let node be null. |
|||
# 2. Replace each string in nodes with a new Text node whose data is the string |
|||
# and node document is document. |
|||
# 3. If nodes contains one node, then set node to nodes[0]. |
|||
# 4. Otherwise, set node to a new DocumentFragment node whose node document is |
|||
# document, and then append each node in nodes, if any, to it. |
|||
// The spec would have us iterate through the provided nodes and then iterate |
|||
// through them again to append. Let's optimize this a wee bit, shall we? |
|||
$document = ($this instanceof Document) ? $this : $this->ownerDocument; |
|||
$node = ($node->length > 1) ? $document->createDocumentFragment() : null; |
|||
foreach ($nodes as &$n) { |
|||
// Can't do union types until PHP 8... OTL |
|||
if (!$n instanceof \DOMNode && !is_string($n)) { |
|||
trigger_error(sprintf("Uncaught TypeError: %s::%s(): Argument #1 (\$%s) must be of type \DOMNode|string, %s given", __CLASS__, __METHOD__, 'nodes', gettype($n))); |
|||
} |
|||
|
|||
if (is_string($n)) { |
|||
$n = $this->ownerDocument->createTextNode($n); |
|||
} |
|||
|
|||
if ($node !== null) { |
|||
$node->appendChild($n); |
|||
} else { |
|||
$node = $n; |
|||
} |
|||
} |
|||
|
|||
return $node; |
|||
} |
|||
} |
|||
} else { |
|||
trait ParentNode { |
|||
public function __get_childElementCount(): int { |
|||
# The childElementCount getter steps are to return the number of children of |
|||
# this that are elements. |
|||
$count = 0; |
|||
foreach ($this->childNodes as $child) { |
|||
if ($child instanceof Element) { |
|||
$count++; |
|||
} |
|||
} |
|||
|
|||
return $count; |
|||
} |
|||
|
|||
public function __get_children(): \DOMNodeList { |
|||
# The children getter steps are to return an HTMLCollection collection rooted at |
|||
# this matching only element children. |
|||
// DEVIATION: HTMLCollection doesn't exist in PHP's DOM, and \DOMNodeList is |
|||
// almost identical; so, using that. PHP's DOM doesn't provide the end user any |
|||
// way to create a \DOMNodeList from scratch, so going to cheat and use XPath to |
|||
// make one for us. |
|||
|
|||
$isDocument = ($this instanceof Document); |
|||
$document = ($isDocument) ? $this : $this->ownerDocument; |
|||
return $document->xpath->query('//*', (!$isDocument) ? $this : null); |
|||
} |
|||
|
|||
public function __get_firstElementChild(): Element { |
|||
# The firstElementChild getter steps are to return the first child that is an |
|||
# element; otherwise null. |
|||
foreach ($this->childNodes as $child) { |
|||
if ($child instanceof Element) { |
|||
return $child; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public function __get_lastElementChild(): Element { |
|||
# The lastElementChild getter steps are to return the last child that is an |
|||
# element; otherwise null. |
|||
for ($i = $this->childNodes->length - 1; $i >= 0; $i--) { |
|||
$child = $this->childNodes->item($i); |
|||
if ($child instanceof Element) { |
|||
return $child; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
public function append(...$nodes): void { |
|||
# The append(nodes) method steps are: |
|||
# 1. Let node be the result of converting nodes into a node given nodes and |
|||
# this’s node document. |
|||
$node = $this->convertNodesToNode($nodes); |
|||
# 2. Append node to this. |
|||
$this->appendChild($node); |
|||
} |
|||
|
|||
public function prepend(...$nodes): void { |
|||
# The prepend(nodes) method steps are: |
|||
# |
|||
# 1. Let node be the result of converting nodes into a node given nodes and |
|||
# this’s node document. |
|||
$node = $this->convertNodesToNode($nodes); |
|||
# 2. Pre-insert node into this before this’s first child. |
|||
$this->insertBefore($node, $this->firstChild); |
|||
} |
|||
|
|||
public function replaceChildren(...$nodes) { |
|||
# The replaceChildren(nodes) method steps are: |
|||
# 1. Let node be the result of converting nodes into a node given nodes and |
|||
# this’s node document. |
|||
$node = $this->convertNodesToNode($nodes); |
|||
# 2. Ensure pre-insertion validity of node into this before null. |
|||
$this->preInsertionValidity($node); |
|||
# 3. Replace all with node within this. |
|||
# |
|||
# To replace all with a node within a parent, run these steps: |
|||
# 1. Let removedNodes be parent’s children. |
|||
$removedNodes = $this->childNodes; |
|||
# 2. Let addedNodes be the empty set. |
|||
$addedNodes = []; |
|||
# 3. If node is a DocumentFragment node, then set addedNodes to node’s children. |
|||
if ($node instanceof DocumentFragment) { |
|||
$addedNodes = $node->childNodes; |
|||
} |
|||
# 4. Otherwise, if node is non-null, set addedNodes to « node ». |
|||
elseif ($node !== null) { |
|||
$addedNodes = node; |
|||
} |
|||
# 5. Remove all parent’s children, in tree order, with the suppress observers |
|||
# flag set. |
|||
// DEVIATION: There is no scripting in this implementation, so cannnot set |
|||
// suppress observers flag. |
|||
while ($this->hasChildNodes()) { |
|||
$this->removeChild($this->firstChild); |
|||
} |
|||
# 6. If node is non-null, then insert node into parent before null with the |
|||
# suppress observers flag set. |
|||
// DEVIATION: There is no scripting in this implementation, so cannnot set |
|||
// suppress observers flag. |
|||
if ($node !== null) { |
|||
$this->appendChild($node); |
|||
} |
|||
# 7. If either addedNodes or removedNodes is not empty, then queue a tree |
|||
# mutation record for parent with addedNodes, removedNodes, null, and null. |
|||
// DEVIATION: There is no scripting in this implementation |
|||
} |
|||
|
|||
private function convertNodesToNode(array $nodes): \DOMNode { |
|||
# To convert nodes into a node, given nodes and document, run these steps: |
|||
# 1. Let node be null. |
|||
# 2. Replace each string in nodes with a new Text node whose data is the string |
|||
# and node document is document. |
|||
# 3. If nodes contains one node, then set node to nodes[0]. |
|||
# 4. Otherwise, set node to a new DocumentFragment node whose node document is |
|||
# document, and then append each node in nodes, if any, to it. |
|||
// The spec would have us iterate through the provided nodes and then iterate |
|||
// through them again to append. Let's optimize this a wee bit, shall we? |
|||
$document = ($this instanceof Document) ? $this : $this->ownerDocument; |
|||
$node = ($node->length > 1) ? $document->createDocumentFragment() : null; |
|||
foreach ($nodes as &$n) { |
|||
// Can't do union types until PHP 8... OTL |
|||
if (!$n instanceof \DOMNode && !is_string($n)) { |
|||
trigger_error(sprintf("Uncaught TypeError: %s::%s(): Argument #1 (\$%s) must be of type \DOMNode|string, %s given", __CLASS__, __METHOD__, 'nodes', gettype($n))); |
|||
} |
|||
|
|||
if (is_string($n)) { |
|||
$n = $this->ownerDocument->createTextNode($n); |
|||
} |
|||
|
|||
if ($node !== null) { |
|||
$node->appendChild($n); |
|||
} else { |
|||
$node = $n; |
|||
} |
|||
} |
|||
|
|||
return $node; |
|||
} |
|||
} |
|||
} |
@ -1,15 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
trait ToString { |
|||
public function __toString(): string { |
|||
$frag = $this->ownerDocument->createDocumentFragment(); |
|||
$frag->appendChild($this->cloneNode(true)); |
|||
return $this->ownerDocument->serialize($frag); |
|||
} |
|||
} |
@ -1,31 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
trait Walk { |
|||
/** Generator which walks down the DOM. Nonstandard. */ |
|||
public function walk(?\Closure $filter = null): \Generator { |
|||
return $this->walkGenerator($this, $filter); |
|||
} |
|||
|
|||
private function walkGenerator(\DOMNode $node, ?\Closure $filter = null) { |
|||
if ($filter === null || $filter($node)) { |
|||
yield $node; |
|||
} |
|||
|
|||
if ($node instanceof TemplateElement) { |
|||
$node = $node->content; |
|||
} |
|||
|
|||
if ($node->hasChildNodes()) { |
|||
$children = $node->childNodes; |
|||
foreach ($children as $c) { |
|||
yield from $this->walkGenerator($c, $filter); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,24 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML; |
|||
|
|||
trait WalkShallow { |
|||
/** |
|||
* Generator which just walks through a node's child nodes. Nonstandard. |
|||
* |
|||
* @param ?\Closure $filter - An optional closure to use to filter |
|||
*/ |
|||
public function walkShallow(?\Closure $filter = null): \Generator { |
|||
$node = (!$this instanceof TemplateElement) ? $this : $this->content; |
|||
|
|||
foreach ($node->childNodes as $child) { |
|||
if ($filter === null || $filter($child)) { |
|||
yield $child; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,17 +0,0 @@ |
|||
{ |
|||
"devDependencies": { |
|||
"autoprefixer": "^9.6.1", |
|||
"postcss": "^7.0.0", |
|||
"postcss-cli": "^7.1.1", |
|||
"postcss-color-function": "^4.1.0", |
|||
"postcss-csso": "^4.0.0", |
|||
"postcss-custom-media": "^7.0.8", |
|||
"postcss-custom-properties": "^9.0.2", |
|||
"postcss-discard-comments": "^4.0.2", |
|||
"postcss-import": "^12.0.1", |
|||
"postcss-media-minmax": "^4.0.0", |
|||
"postcss-nested": "^4.1.2", |
|||
"postcss-sassy-mixins": "^2.1.0", |
|||
"postcss-scss": "^2.0.0" |
|||
} |
|||
} |
@ -1,17 +0,0 @@ |
|||
module.exports = ctx => ({ |
|||
//map: ctx.options.map,
|
|||
parser: 'postcss-scss', |
|||
//syntax: 'postcss-scss',
|
|||
plugins: { |
|||
'postcss-import': { root: ctx.file.dirname }, |
|||
'postcss-discard-comments': {}, |
|||
'postcss-sassy-mixins': {}, |
|||
'postcss-custom-media': {preserve: false}, |
|||
'postcss-media-minmax': {}, |
|||
'postcss-custom-properties': {preserve: false}, |
|||
'postcss-color-function': {}, |
|||
'postcss-nested': {}, |
|||
'autoprefixer': {}, |
|||
'postcss-csso': {}, |
|||
} |
|||
}) |
@ -1,318 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML\TestCase; |
|||
|
|||
use MensBeam\HTML\Document; |
|||
use MensBeam\HTML\Parser; |
|||
use MensBeam\HTML\TemplateElement; |
|||
|
|||
class TestDOM extends \PHPUnit\Framework\TestCase { |
|||
/** |
|||
* @dataProvider provideNamespacedElements |
|||
* @covers \MensBeam\HTML\Document::createElementNS |
|||
*/ |
|||
public function testCreateNamespacedElements(?string $nsIn, string $nameIn, ?string $nsOut, string $local, string $prefix): void { |
|||
$d = new Document; |
|||
$e = $d->createElementNS($nsIn, $nameIn); |
|||
$this->assertSame($nsOut, $e->namespaceURI); |
|||
$this->assertSame($local, $e->localName); |
|||
$this->assertSame($prefix, $e->prefix); |
|||
} |
|||
|
|||
public function provideNamespacedElements(): iterable { |
|||
return [ |
|||
[null, "test", null, "test", ""], |
|||
[null, "test:test", null, "testU00003Atest", ""], |
|||
["http://www.w3.org/2000/svg", "svg", "http://www.w3.org/2000/svg", "svg", ""], |
|||
["http://www.w3.org/2000/svg", "svg:svg", "http://www.w3.org/2000/svg", "svg", "svg"], |
|||
["fake_ns", "test:test", "fake_ns", "test", "test"], |
|||
["fake_ns", "test:test:test", "fake_ns", "testU00003Atest", "test"], |
|||
["fake_ns", "te st:test", "fake_ns", "test", "teU000020st"], |
|||
[null, "9", null, "U000039", ""], |
|||
["http://www.w3.org/1999/xhtml", "test", null, "test", ""], |
|||
["http://www.w3.org/1999/xhtml", "TEST", null, "test", ""], |
|||
[null, "TEST", null, "test", ""], |
|||
["fake_ns", "TEST", "fake_ns", "TEST", ""], |
|||
["http://www.w3.org/2000/svg", "TEST", "http://www.w3.org/2000/svg", "TEST", ""], |
|||
["http://www.w3.org/1998/Math/MathML", "TEST", "http://www.w3.org/1998/Math/MathML", "TEST", ""], |
|||
]; |
|||
} |
|||
/** |
|||
* @dataProvider provideBareElements |
|||
* @covers \MensBeam\HTML\Document::createElement |
|||
*/ |
|||
public function testCreateBareElements(string $nameIn, $nameOut): void { |
|||
$d = new Document; |
|||
$e = $d->createElement($nameIn); |
|||
$this->assertNull($e->namespaceURI); |
|||
$this->assertSame("", $e->prefix); |
|||
$this->assertSame($nameOut, $e->localName); |
|||
} |
|||
|
|||
public function provideBareElements(): iterable { |
|||
return [ |
|||
["test", "test"], |
|||
["test:test", "testU00003Atest"], |
|||
["9", "U000039"], |
|||
["TEST", "test"], |
|||
]; |
|||
} |
|||
|
|||
/** @covers \MensBeam\HTML\Document::createElementNS */ |
|||
public function testCreateTemplateElements(): void { |
|||
$d = new Document; |
|||
$t = $d->createElement("template"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
$t = $d->createElement("TEMPLATE"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
$t = $d->createElementNS(null, "template"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
$t = $d->createElementNS(null, "TEMPLATE"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
$t = $d->createElementNS("http://www.w3.org/1999/xhtml", "template"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
$t = $d->createElementNS("http://www.w3.org/1999/xhtml", "TEMPLATE"); |
|||
$this->assertInstanceOf(TemplateElement::class, $t); |
|||
$this->assertNotNull($t->ownerDocument); |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider provideNamespacedAttributeCreations |
|||
* @covers \MensBeam\HTML\Document::createAttributeNS |
|||
*/ |
|||
public function testCreateNamespacedAttributes(?string $nsIn, string $nameIn, string $local, string $prefix): void { |
|||
$d = new Document; |
|||
$d->appendChild($d->createElement("html")); |
|||
$a = $d->createAttributeNS($nsIn, $nameIn); |
|||
$this->assertSame($local, $a->localName); |
|||
$this->assertSame($nsIn, $a->namespaceURI); |
|||
$this->assertSame($prefix, $a->prefix); |
|||
} |
|||
|
|||
public function provideNamespacedAttributeCreations(): iterable { |
|||
return [ |
|||
[null, "test", "test", ""], |
|||
[null, "test:test", "testU00003Atest", ""], |
|||
[null, "test", "test", ""], |
|||
[null, "TEST:TEST", "TESTU00003ATEST", ""], |
|||
["fake_ns", "test", "test", ""], |
|||
["fake_ns", "test:test", "test", "test"], |
|||
["fake_ns", "TEST:TEST", "TEST", "TEST"], |
|||
["fake_ns", "test:test:test", "testU00003Atest", "test"], |
|||
["fake_ns", "TEST:TEST:TEST", "TESTU00003ATEST", "TEST"], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider provideBareAttributeCreations |
|||
* @covers \MensBeam\HTML\Document::createAttribute |
|||
*/ |
|||
public function testCreateBareAttributes(string $nameIn, string $nameOut): void { |
|||
$d = new Document; |
|||
$d->appendChild($d->createElement("html")); |
|||
$a = $d->createAttribute($nameIn); |
|||
$this->assertSame($nameOut, $a->name); |
|||
$this->assertNull($a->namespaceURI); |
|||
} |
|||
|
|||
public function provideBareAttributeCreations(): iterable { |
|||
return [ |
|||
["test", "test"], |
|||
["test:test", "testU00003Atest"], |
|||
["TEST", "TEST"], |
|||
["TEST:TEST", "TESTU00003ATEST"], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider provideNamespacedAttributeSettings |
|||
* @covers \MensBeam\HTML\Element::setAttributeNS |
|||
*/ |
|||
public function testSetNamespoacedAttributes(?string $elementNS, ?string $attrNS, string $nameIn, string $nameOut): void { |
|||
$d = new Document; |
|||
$e = $d->createElementNS($elementNS, "test"); |
|||
$this->assertSame(0, $e->attributes->length); |
|||
$e->setAttributeNS($attrNS, $nameIn, "test"); |
|||
$this->assertSame(1, $e->attributes->length); |
|||
$a = $e->attributes[0]; |
|||
$this->assertSame($nameOut, $a->nodeName); |
|||
$this->assertSame($attrNS, $a->namespaceURI); |
|||
} |
|||
|
|||
public function provideNamespacedAttributeSettings(): iterable { |
|||
return [ |
|||
[null, null, "test", "test"], |
|||
[null, null, "TEST", "test"], |
|||
["http://www.w3.org/1999/xhtml", null, "test", "test"], |
|||
["http://www.w3.org/1999/xhtml", null, "TEST", "test"], |
|||
[null, null, "test:test", "testU00003Atest"], |
|||
[null, null, "TEST:TEST", "testU00003Atest"], |
|||
["http://www.w3.org/1999/xhtml", null, "test:test", "testU00003Atest"], |
|||
["http://www.w3.org/1999/xhtml", null, "TEST:TEST", "testU00003Atest"], |
|||
[null, "http://www.w3.org/1999/xhtml", "test:test", "test:test"], |
|||
[null, "http://www.w3.org/1999/xhtml", "TEST:TEST", "TEST:TEST"], |
|||
["http://www.w3.org/1998/Math/MathML", null, "test", "test"], |
|||
["http://www.w3.org/1998/Math/MathML", null, "TEST", "TEST"], |
|||
[null, "http://www.w3.org/2000/xmlns/", "xmlns:xlink", "xmlns:xlink"], |
|||
[null, "http://www.w3.org/2000/xmlns/", "xmlns:XLINK", "xmlns:XLINK"], |
|||
[null, "fake_ns", "test:test:test", "test:testU00003Atest"], |
|||
[null, "fake_ns", "TEST:TEST:TEST", "TEST:TESTU00003ATEST"], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider provideBareAttributeSettings |
|||
* @covers \MensBeam\HTML\Element::setAttribute |
|||
*/ |
|||
public function testSetBareAttributes(?string $elementNS, string $nameIn, string $nameOut): void { |
|||
$d = new Document; |
|||
$e = $d->createElementNS($elementNS, "test"); |
|||
$this->assertSame(0, $e->attributes->length); |
|||
$e->setAttribute($nameIn, "test"); |
|||
$this->assertSame(1, $e->attributes->length); |
|||
$a = $e->attributes[0]; |
|||
$this->assertSame($nameOut, $a->nodeName); |
|||
$this->assertNull($a->namespaceURI); |
|||
} |
|||
|
|||
public function provideBareAttributeSettings(): iterable { |
|||
return [ |
|||
[null, "test", "test"], |
|||
[null, "TEST", "test"], |
|||
["http://www.w3.org/1999/xhtml", "test", "test"], |
|||
["http://www.w3.org/1999/xhtml", "TEST", "test"], |
|||
[null, "test:test", "testU00003Atest"], |
|||
[null, "TEST:TEST", "testU00003Atest"], |
|||
["http://www.w3.org/1999/xhtml", "test:test", "testU00003Atest"], |
|||
["http://www.w3.org/1999/xhtml", "TEST:TEST", "testU00003Atest"], |
|||
["http://www.w3.org/1998/Math/MathML", "test", "test"], |
|||
["http://www.w3.org/1998/Math/MathML", "TEST", "TEST"], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider provideAttributeNodeSettings |
|||
* @covers \MensBeam\HTML\Element::setAttributeNode |
|||
* @covers \MensBeam\HTML\Element::setAttributeNodeNS |
|||
*/ |
|||
public function testSetAttributeNodes(bool $ns, ?string $elementNS, ?string $attrNS, string $name): void { |
|||
$d = new Document; |
|||
$e = $d->createElementNS($elementNS, "test"); |
|||
$d->appendChild($e); |
|||
$this->assertSame(0, $e->attributes->length); |
|||
$a = $d->createAttributeNS($attrNS, $name); |
|||
if ($ns) { |
|||
$e->setAttributeNodeNS($a); |
|||
} else { |
|||
$e->setAttributeNode($a); |
|||
} |
|||
$this->assertSame(1, $e->attributes->length); |
|||
$a = $e->attributes[0]; |
|||
$this->assertSame($name, $a->nodeName); |
|||
$this->assertSame($attrNS, $a->namespaceURI); |
|||
} |
|||
|
|||
public function provideAttributeNodeSettings(): iterable { |
|||
return [ |
|||
[true, null, null, "test"], |
|||
[true, null, null, "TEST"], |
|||
[true, "http://www.w3.org/1999/xhtml", null, "test"], |
|||
[true, "http://www.w3.org/1999/xhtml", null, "TEST"], |
|||
[true, null, null, "testU00003Atest"], |
|||
[true, null, null, "TESTU00003ATEST"], |
|||
[true, "http://www.w3.org/1999/xhtml", null, "testU00003Atest"], |
|||
[true, "http://www.w3.org/1999/xhtml", null, "TESTU00003ATEST"], |
|||
[true, null, "http://www.w3.org/1999/xhtml", "test:test"], |
|||
[true, null, "http://www.w3.org/1999/xhtml", "TEST:TEST"], |
|||
[true, "http://www.w3.org/1998/Math/MathML", null, "test"], |
|||
[true, "http://www.w3.org/1998/Math/MathML", null, "TEST"], |
|||
[true, null, "http://www.w3.org/2000/xmlns/", "xmlns:xlink"], |
|||
[true, null, "http://www.w3.org/2000/xmlns/", "xmlns:XLINK"], |
|||
[true, null, "fake_ns", "test:testU00003Atest"], |
|||
[true, null, "fake_ns", "TEST:TESTU00003ATEST"], |
|||
[false, null, null, "test"], |
|||
[false, null, null, "TEST"], |
|||
[false, "http://www.w3.org/1999/xhtml", null, "test"], |
|||
[false, "http://www.w3.org/1999/xhtml", null, "TEST"], |
|||
[false, null, null, "testU00003Atest"], |
|||
[false, null, null, "TESTU00003ATEST"], |
|||
[false, "http://www.w3.org/1999/xhtml", null, "testU00003Atest"], |
|||
[false, "http://www.w3.org/1999/xhtml", null, "TESTU00003ATEST"], |
|||
[false, null, "http://www.w3.org/1999/xhtml", "test:test"], |
|||
[false, null, "http://www.w3.org/1999/xhtml", "TEST:TEST"], |
|||
[false, "http://www.w3.org/1998/Math/MathML", null, "test"], |
|||
[false, "http://www.w3.org/1998/Math/MathML", null, "TEST"], |
|||
[false, null, "http://www.w3.org/2000/xmlns/", "xmlns:xlink"], |
|||
[false, null, "http://www.w3.org/2000/xmlns/", "xmlns:XLINK"], |
|||
[false, null, "fake_ns", "test:testU00003Atest"], |
|||
[false, null, "fake_ns", "TEST:TESTU00003ATEST"], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @covers \MensBeam\HTML\Element::hasAttribute |
|||
* @covers \MensBeam\HTML\Element::getAttribute |
|||
* @covers \MensBeam\HTML\Element::getAttributeNS |
|||
*/ |
|||
public function testCheckForAttribute(): void { |
|||
$d = new Document; |
|||
$d->appendChild($d->createElement("html")); |
|||
$e = $d->documentElement; |
|||
$e->setAttribute("ook", "eek"); |
|||
$e->setAttributeNS(Parser::XML_NAMESPACE, "xml:base", "http://example.com/"); |
|||
$e->setAttributeNS(Parser::XMLNS_NAMESPACE, "xmlns:xlink", Parser::XLINK_NAMESPACE); |
|||
$e->setAttributeNS("fake_ns", "ook:eek", "ack"); |
|||
// perform boolean tests |
|||
$this->assertFalse($e->hasAttribute("blah")); |
|||
$this->assertFalse($e->hasAttribute("OOK"));; |
|||
$this->assertFalse($e->hasAttribute("eek")); |
|||
$this->assertFalse($e->hasAttribute("ack")); |
|||
$this->assertTrue($e->hasAttribute("ook")); |
|||
$this->assertTrue($e->hasAttribute("xml:base")); |
|||
$this->assertTrue($e->hasAttribute("xmlns:xlink")); |
|||
$this->assertTrue($e->hasAttribute("ook:eek")); |
|||
$this->assertFalse($e->hasAttributeNS(null, "blah")); |
|||
$this->assertFalse($e->hasAttributeNS(null, "OOK")); |
|||
$this->assertFalse($e->hasAttributeNS(null, "eek")); |
|||
$this->assertTrue($e->hasAttributeNS(null, "ook")); |
|||
$this->assertTrue($e->hasAttributeNS(Parser::XML_NAMESPACE, "base")); |
|||
$this->assertTrue($e->hasAttributeNS(Parser::XMLNS_NAMESPACE, "xlink")); |
|||
$this->assertTrue($e->hasAttributeNS("fake_ns", "eek")); |
|||
// perform retrival tests |
|||
$this->assertNull($e->getAttribute("blah")); |
|||
$this->assertNull($e->getAttribute("OOK")); |
|||
$this->assertNull($e->getAttribute("eek")); |
|||
$this->assertNull($e->getAttribute("ack")); |
|||
$this->assertSame("eek", $e->getAttribute("ook")); |
|||
$this->assertSame("http://example.com/", $e->getAttribute("xml:base")); |
|||
$this->assertSame(Parser::XLINK_NAMESPACE, $e->getAttribute("xmlns:xlink")); |
|||
$this->assertSame("ack", $e->getAttribute("ook:eek")); |
|||
$this->assertNull($e->getAttributeNS(null, "blah")); |
|||
$this->assertNull($e->getAttributeNS(null, "OOK")); |
|||
$this->assertNull($e->getAttributeNS(null, "ack")); |
|||
$this->assertSame("eek", $e->getAttributeNS(null, "ook")); |
|||
$this->assertSame("http://example.com/", $e->getAttributeNS(Parser::XML_NAMESPACE, "base")); |
|||
$this->assertSame(Parser::XLINK_NAMESPACE, $e->getAttributeNS(Parser::XMLNS_NAMESPACE, "xlink")); |
|||
$this->assertSame("ack", $e->getAttributeNS("fake_ns", "eek")); |
|||
} |
|||
|
|||
/** @covers \MensBeam\HTML\Element::__get */ |
|||
public function testGetInnerAndOuterHtml(): void { |
|||
$d = new Document; |
|||
$d->appendChild($d->createElement("html")); |
|||
$d->documentElement->appendChild($d->createTextNode("OOK")); |
|||
$this->assertSame("OOK", $d->documentElement->innerHTML); |
|||
$this->assertSame("<html>OOK</html>", $d->documentElement->outerHTML); |
|||
$this->assertNull($d->documentElement->innerHtml); |
|||
$this->assertNull($d->documentElement->outerHtml); |
|||
} |
|||
} |
@ -1,138 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 , Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML\TestCase; |
|||
|
|||
use MensBeam\HTML\Document; |
|||
use MensBeam\HTML\Parser; |
|||
|
|||
/** |
|||
* @covers \MensBeam\HTML\Document |
|||
* @covers \MensBeam\HTML\DocumentFragment |
|||
* @covers \MensBeam\HTML\Element |
|||
* @covers \MensBeam\HTML\TemplateElement |
|||
* @covers \MensBeam\HTML\Comment |
|||
* @covers \MensBeam\HTML\Text |
|||
* @covers \MensBeam\HTML\ProcessingInstruction |
|||
*/ |
|||
class TestSerializer extends \PHPUnit\Framework\TestCase { |
|||
/** @dataProvider provideStandardSerializerTests */ |
|||
public function testStandardTreeTests(array $data, bool $fragment, string $exp): void { |
|||
$node = $this->buildTree($data, $fragment); |
|||
$this->assertSame($exp, (string) $node); |
|||
} |
|||
|
|||
public function provideStandardSerializerTests(): iterable { |
|||
$blacklist = []; |
|||
$files = new \AppendIterator(); |
|||
$files->append(new \GlobIterator(\MensBeam\HTML\BASE."tests/cases/serializer/*.dat", \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)); |
|||
foreach ($files as $file) { |
|||
$index = 0; |
|||
$l = 0; |
|||
if (!in_array(basename($file), $blacklist)) { |
|||
$lines = array_map(function($v) { |
|||
return rtrim($v, "\n"); |
|||
}, file($file)); |
|||
while ($l < sizeof($lines)) { |
|||
$pos = $l + 1; |
|||
assert(in_array($lines[$l], ["#document", "#fragment"]), new \Exception("Test $file #$index does not start with #doocument or #fragment tag at line ".($l + 1))); |
|||
$fragment = $lines[$l] === "#fragment"; |
|||
// collect the test input |
|||
$data = []; |
|||
for (++$l; $l < sizeof($lines); $l++) { |
|||
if (preg_match('/^#(script-(on|off)|output)$/', $lines[$l])) { |
|||
break; |
|||
} |
|||
$data[] = $lines[$l]; |
|||
} |
|||
// set the script mode, if present |
|||
assert(preg_match('/^#(script-(on|off)|output)$/', $lines[$l]) === 1, new \Exception("Test $file #$index follows data with something other than script flag or output at line ".($l + 1))); |
|||
$script = null; |
|||
if ($lines[$l] === "#script-off") { |
|||
$script = false; |
|||
$l++; |
|||
} elseif ($lines[$l] === "#script-on") { |
|||
$script = true; |
|||
$l++; |
|||
} |
|||
// collect the output string |
|||
$exp = []; |
|||
assert($lines[$l] === "#output", new \Exception("Test $file #$index follows input with something other than output at line ".($l + 1))); |
|||
for (++$l; $l < sizeof($lines); $l++) { |
|||
if ($lines[$l] === "" && in_array(($lines[$l + 1] ?? ""), ["#document", "#fragment"])) { |
|||
break; |
|||
} |
|||
assert(preg_match('/^[^#]/', $lines[$l]) === 1, new \Exception("Test $file #$index contains unrecognized data after output at line ".($l + 1))); |
|||
$exp[] = $lines[$l]; |
|||
} |
|||
$exp = implode("\n", $exp); |
|||
if (!$script) { |
|||
yield basename($file)." #$index (line $pos)" => [$data, $fragment, $exp]; |
|||
} |
|||
$l++; |
|||
$index++; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected function buildTree(array $data, bool $fragment): \DOMNode { |
|||
$document = new Document; |
|||
if ($fragment) { |
|||
$document->appendChild($document->createElement("html")); |
|||
$out = $document->createDocumentFragment(); |
|||
} else { |
|||
$out = $document; |
|||
} |
|||
$cur = $out; |
|||
$pad = 2; |
|||
// process each line in turn |
|||
for ($l = 0; $l < sizeof($data); $l++) { |
|||
preg_match('/^(\|\s+)(.+)/', $data[$l], $m); |
|||
// pop any parents as long as the padding of the line is less than the expected padding |
|||
$p = strlen((string) $m[1]); |
|||
assert($p >= 2 && $p <= $pad && !($p % 2), new \Exception("Input data is invalid on line ".($l + 1))); |
|||
while ($p < $pad) { |
|||
$pad -= 2; |
|||
$cur = $cur->parentNode; |
|||
} |
|||
// act based upon what the rest of the line looks like |
|||
$d = $m[2]; |
|||
if (preg_match('/^<!-- (.*?) -->$/', $d, $m)) { |
|||
// comment |
|||
$cur->appendChild($document->createComment($m[1])); |
|||
} elseif (preg_match('/^<!DOCTYPE(?: ([^ >]*)(?: "([^"]*)" "([^"]*)")?)?>$/', $d, $m)) { |
|||
// doctype |
|||
$name = strlen((string) ($m[1] ?? "")) ? $m[1] : " "; |
|||
$public = strlen((string) ($m[2] ?? "")) ? $m[2] : ""; |
|||
$system = strlen((string) ($m[3] ?? "")) ? $m[3] : ""; |
|||
$cur->appendChild($document->implementation->createDocumentType($name, $public, $system)); |
|||
} elseif (preg_match('/^<\?([^ ]+) ([^>]*)>$/', $d, $m)) { |
|||
$cur->appendChild($document->createProcessingInstruction($m[1], $m[2])); |
|||
} elseif (preg_match('/^<(?:([^ ]+) )?([^>]+)>$/', $d, $m)) { |
|||
// element |
|||
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? $m[1]) : null; |
|||
$cur = $cur->appendChild($document->createElementNS($ns, $m[2])); |
|||
$pad += 2; |
|||
} elseif (preg_match('/^(?:([^" ]+) )?([^"=]+)="((?:[^"]|"(?!$))*)"$/', $d, $m)) { |
|||
// attribute |
|||
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? $m[1]) : ""; |
|||
$cur->setAttributeNS($ns, $m[2], $m[3]); |
|||
} elseif (preg_match('/^"((?:[^"]|"(?!$))*)("?)$/', $d, $m)) { |
|||
// text |
|||
$t = $m[1]; |
|||
while (!strlen((string) $m[2])) { |
|||
preg_match('/^((?:[^"]|"(?!$))*)("?)$/', $data[++$l], $m); |
|||
$t .= "\n".$m[1]; |
|||
} |
|||
$cur->appendChild($document->createTextNode($t)); |
|||
} else { |
|||
throw new \Exception("Input data is invalid on line ".($l + 1)); |
|||
} |
|||
} |
|||
return $out; |
|||
} |
|||
} |
@ -1,32 +0,0 @@ |
|||
#fragment |
|||
| <fake_ns test:test> |
|||
#output |
|||
<test:test></test:test> |
|||
|
|||
#fragment |
|||
| <fake_ns test:te<st> |
|||
#output |
|||
<test:te<st></test:te<st> |
|||
|
|||
#fragment |
|||
| <test<test> |
|||
#output |
|||
<test<test></test<test> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| test<test="test" |
|||
#output |
|||
<span test<test="test"></span> |
|||
|
|||
#fragment |
|||
| <wbr> |
|||
| "You should not see this text." |
|||
#output |
|||
<wbr> |
|||
|
|||
#fragment |
|||
| <wbr> |
|||
| class="test" |
|||
#output |
|||
<wbr class="test"> |
@ -1,34 +0,0 @@ |
|||
#document |
|||
| <html> |
|||
#output |
|||
<html></html> |
|||
|
|||
#document |
|||
| <!DOCTYPE html> |
|||
| <html> |
|||
#output |
|||
<!DOCTYPE html><html></html> |
|||
|
|||
#document |
|||
| <!DOCTYPE html "public" "system"> |
|||
| <html> |
|||
#output |
|||
<!DOCTYPE html><html></html> |
|||
|
|||
#document |
|||
| <!DOCTYPE test> |
|||
| <html> |
|||
#output |
|||
<!DOCTYPE test><html></html> |
|||
|
|||
#document |
|||
| <!DOCTYPE> |
|||
| <html> |
|||
#output |
|||
<!DOCTYPE ><html></html> |
|||
|
|||
#document |
|||
| <html> |
|||
| <?php echo "Hello world!"; ?> |
|||
#output |
|||
<html><?php echo "Hello world!"; ?></html> |
@ -1,913 +0,0 @@ |
|||
#fragment |
|||
| <span> |
|||
#output |
|||
<span></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
#output |
|||
<span><a></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b="c" |
|||
#output |
|||
<span><a b="c"></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b="&" |
|||
#output |
|||
<span><a b="&"></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b=" " |
|||
#output |
|||
<span><a b=" "></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b=""" |
|||
#output |
|||
<span><a b="""></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b="<" |
|||
#output |
|||
<span><a b="<"></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| b=">" |
|||
#output |
|||
<span><a b=">"></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| href="javascript:"<>"" |
|||
#output |
|||
<span><a href="javascript:"<>""></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xlink xlink:href="a" |
|||
#output |
|||
<span><svg xlink:href="a"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xmlns xmlns:svg="test" |
|||
#output |
|||
<span><svg xmlns:svg="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| "a" |
|||
#output |
|||
<span>a</span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| "&" |
|||
#output |
|||
<span>&</span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| " " |
|||
#output |
|||
<span> </span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| "<" |
|||
#output |
|||
<span><</span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| ">" |
|||
#output |
|||
<span>></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| """ |
|||
#output |
|||
<span>"</span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <style> |
|||
| "<&>" |
|||
#output |
|||
<span><style><&></style></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <script> |
|||
| type="test" |
|||
| "<&>" |
|||
#output |
|||
<span><script type="test"><&></script></span> |
|||
|
|||
#fragment |
|||
| <script> |
|||
| type="test" |
|||
| "<&>" |
|||
#output |
|||
<script type="test"><&></script> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <xmp> |
|||
| "<&>" |
|||
#output |
|||
<span><xmp><&></xmp></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <iframe> |
|||
| "<&>" |
|||
#output |
|||
<span><iframe><&></iframe></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <noembed> |
|||
| "<&>" |
|||
#output |
|||
<span><noembed><&></noembed></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <noframes> |
|||
| "<&>" |
|||
#output |
|||
<span><noframes><&></noframes></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <noscript> |
|||
| "<&>" |
|||
#script-off |
|||
#output |
|||
<span><noscript><&></noscript></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <noscript> |
|||
| "<&>" |
|||
#script-on |
|||
#output |
|||
<span><noscript><&></noscript></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <!-- data --> |
|||
#output |
|||
<span><!--data--></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| <b> |
|||
| <c> |
|||
| <d> |
|||
| "e" |
|||
| <f> |
|||
| <g> |
|||
| "h" |
|||
#output |
|||
<span><a><b><c></c></b><d>e</d><f><g>h</g></f></a></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| b="c" |
|||
#output |
|||
<span b="c"></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xml xml:foo="test" |
|||
#output |
|||
<span><svg xml:foo="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xml abc:foo="test" |
|||
#output |
|||
<span><svg xml:foo="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xmlns xmlns:foo="test" |
|||
#output |
|||
<span><svg xmlns:foo="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| xmlns xmlns="test" |
|||
#output |
|||
<span><svg xmlns="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <svg svg> |
|||
| fake_ns abc:def="test" |
|||
#output |
|||
<span><svg abc:def="test"></svg></span> |
|||
|
|||
#fragment |
|||
| <pre> |
|||
| " |
|||
" |
|||
#output |
|||
<pre> |
|||
</pre> |
|||
|
|||
#fragment |
|||
| <pre> |
|||
| "a |
|||
" |
|||
#output |
|||
<pre>a |
|||
</pre> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <pre> |
|||
| " |
|||
" |
|||
#output |
|||
<span><pre> |
|||
</pre></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <pre> |
|||
| "a |
|||
" |
|||
#output |
|||
<span><pre>a |
|||
</pre></span> |
|||
|
|||
#fragment |
|||
| <textarea> |
|||
| " |
|||
" |
|||
#output |
|||
<textarea> |
|||
</textarea> |
|||
|
|||
#fragment |
|||
| <textarea> |
|||
| "a |
|||
" |
|||
#output |
|||
<textarea>a |
|||
</textarea> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <textarea> |
|||
| " |
|||
" |
|||
#output |
|||
<span><textarea> |
|||
</textarea></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <textarea> |
|||
| "a |
|||
" |
|||
#output |
|||
<span><textarea>a |
|||
</textarea></span> |
|||
|
|||
#fragment |
|||
| <listing> |
|||
| " |
|||
" |
|||
#output |
|||
<listing> |
|||
</listing> |
|||
|
|||
#fragment |
|||
| <listing> |
|||
| "a |
|||
" |
|||
#output |
|||
<listing>a |
|||
</listing> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <listing> |
|||
| " |
|||
" |
|||
#output |
|||
<span><listing> |
|||
</listing></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <listing> |
|||
| "a |
|||
" |
|||
#output |
|||
<span><listing>a |
|||
</listing></span> |
|||
|
|||
#fragment |
|||
| <area> |
|||
#output |
|||
<area> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <area> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><area><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <area> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><area><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <area> |
|||
#output |
|||
<span><a>test</a><b></b><area></span> |
|||
|
|||
#fragment |
|||
| <base> |
|||
#output |
|||
<base> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <base> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><base><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <base> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><base><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <base> |
|||
#output |
|||
<span><a>test</a><b></b><base></span> |
|||
|
|||
#fragment |
|||
| <basefont> |
|||
#output |
|||
<basefont> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <basefont> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><basefont><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <basefont> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><basefont><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <basefont> |
|||
#output |
|||
<span><a>test</a><b></b><basefont></span> |
|||
|
|||
#fragment |
|||
| <bgsound> |
|||
#output |
|||
<bgsound> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <bgsound> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><bgsound><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <bgsound> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><bgsound><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <bgsound> |
|||
#output |
|||
<span><a>test</a><b></b><bgsound></span> |
|||
|
|||
#fragment |
|||
| <br> |
|||
#output |
|||
<br> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <br> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><br><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <br> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><br><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <br> |
|||
#output |
|||
<span><a>test</a><b></b><br></span> |
|||
|
|||
#fragment |
|||
| <col> |
|||
#output |
|||
<col> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <col> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><col><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <col> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><col><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <col> |
|||
#output |
|||
<span><a>test</a><b></b><col></span> |
|||
|
|||
#fragment |
|||
| <embed> |
|||
#output |
|||
<embed> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <embed> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><embed><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <embed> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><embed><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <embed> |
|||
#output |
|||
<span><a>test</a><b></b><embed></span> |
|||
|
|||
#fragment |
|||
| <frame> |
|||
#output |
|||
<frame> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <frame> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><frame><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <frame> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><frame><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <frame> |
|||
#output |
|||
<span><a>test</a><b></b><frame></span> |
|||
|
|||
#fragment |
|||
| <hr> |
|||
#output |
|||
<hr> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <hr> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><hr><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <hr> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><hr><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <hr> |
|||
#output |
|||
<span><a>test</a><b></b><hr></span> |
|||
|
|||
#fragment |
|||
| <img> |
|||
#output |
|||
<img> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <img> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><img><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <img> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><img><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <img> |
|||
#output |
|||
<span><a>test</a><b></b><img></span> |
|||
|
|||
#fragment |
|||
| <input> |
|||
#output |
|||
<input> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <input> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><input><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <input> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><input><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <input> |
|||
#output |
|||
<span><a>test</a><b></b><input></span> |
|||
|
|||
#fragment |
|||
| <keygen> |
|||
#output |
|||
<keygen> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <keygen> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><keygen><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <keygen> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><keygen><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <keygen> |
|||
#output |
|||
<span><a>test</a><b></b><keygen></span> |
|||
|
|||
#fragment |
|||
| <link> |
|||
#output |
|||
<link> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <link> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><link><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <link> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><link><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <link> |
|||
#output |
|||
<span><a>test</a><b></b><link></span> |
|||
|
|||
#fragment |
|||
| <meta> |
|||
#output |
|||
<meta> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <meta> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><meta><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <meta> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><meta><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <meta> |
|||
#output |
|||
<span><a>test</a><b></b><meta></span> |
|||
|
|||
#fragment |
|||
| <param> |
|||
#output |
|||
<param> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <param> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><param><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <param> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><param><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <param> |
|||
#output |
|||
<span><a>test</a><b></b><param></span> |
|||
|
|||
#fragment |
|||
| <source> |
|||
#output |
|||
<source> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <source> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><source><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <source> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><source><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <source> |
|||
#output |
|||
<span><a>test</a><b></b><source></span> |
|||
|
|||
#fragment |
|||
| <track> |
|||
#output |
|||
<track> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <track> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><track><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <track> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><track><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <track> |
|||
#output |
|||
<span><a>test</a><b></b><track></span> |
|||
|
|||
#fragment |
|||
| <wbr> |
|||
#output |
|||
<wbr> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <wbr> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
#output |
|||
<span><wbr><a>test</a><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <wbr> |
|||
| <b> |
|||
#output |
|||
<span><a>test</a><wbr><b></b></span> |
|||
|
|||
#fragment |
|||
| <span> |
|||
| <a> |
|||
| "test" |
|||
| <b> |
|||
| <wbr> |
|||
#output |
|||
<span><a>test</a><b></b><wbr></span> |
File diff suppressed because it is too large
Loading…
Reference in new issue