more comments, improved boolean attributes
This commit is contained in:
parent
074b41167e
commit
51de2d6f64
31 changed files with 944 additions and 266 deletions
|
@ -5,6 +5,7 @@ namespace ByJoby\HTML;
|
|||
use ByJoby\HTML\Containers\Fragment;
|
||||
use ByJoby\HTML\Containers\FragmentInterface;
|
||||
use ByJoby\HTML\Containers\HtmlDocumentInterface;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use ByJoby\HTML\Nodes\CData;
|
||||
use ByJoby\HTML\Nodes\CDataInterface;
|
||||
use ByJoby\HTML\Nodes\Comment;
|
||||
|
@ -66,33 +67,34 @@ abstract class AbstractParser
|
|||
|
||||
public function parseFragment(string $html): FragmentInterface
|
||||
{
|
||||
$fragment = new ($this->fragment_class);
|
||||
$fragment = new($this->fragment_class);
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML(
|
||||
'<div>' . $html . '</div>', // wrap in DIV otherwise it will wrap root-level text in P tags
|
||||
LIBXML_BIGLINES
|
||||
| LIBXML_COMPACT
|
||||
| LIBXML_HTML_NOIMPLIED
|
||||
| LIBXML_HTML_NODEFDTD
|
||||
| LIBXML_PARSEHUGE
|
||||
| LIBXML_NOERROR
|
||||
| LIBXML_COMPACT
|
||||
| LIBXML_HTML_NOIMPLIED
|
||||
| LIBXML_HTML_NODEFDTD
|
||||
| LIBXML_PARSEHUGE
|
||||
| LIBXML_NOERROR
|
||||
);
|
||||
$this->walkDom($dom->childNodes[0], $fragment);
|
||||
// @phpstan-ignore-next-line we actually do know there's an item zero
|
||||
$this->walkDom($dom->childNodes->item(0), $fragment);
|
||||
return $fragment;
|
||||
}
|
||||
|
||||
public function parseDocument(string $html): HtmlDocumentInterface
|
||||
{
|
||||
/** @var HtmlDocumentInterface */
|
||||
$document = new ($this->document_class);
|
||||
$document = new($this->document_class);
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML(
|
||||
$html,
|
||||
LIBXML_BIGLINES
|
||||
| LIBXML_COMPACT
|
||||
| LIBXML_HTML_NODEFDTD
|
||||
| LIBXML_PARSEHUGE
|
||||
| LIBXML_NOERROR
|
||||
| LIBXML_COMPACT
|
||||
| LIBXML_HTML_NODEFDTD
|
||||
| LIBXML_PARSEHUGE
|
||||
| LIBXML_NOERROR
|
||||
);
|
||||
$this->walkDom($dom, $document);
|
||||
return $document;
|
||||
|
@ -117,11 +119,11 @@ abstract class AbstractParser
|
|||
if ($node instanceof DOMElement) {
|
||||
return $this->convertNodeToTag($node);
|
||||
} elseif ($node instanceof DOMComment) {
|
||||
return new ($this->comment_class)($node->textContent);
|
||||
return new($this->comment_class)($node->textContent);
|
||||
} elseif ($node instanceof DOMText) {
|
||||
$content = trim($node->textContent);
|
||||
if ($content) {
|
||||
return new ($this->text_class)($content);
|
||||
return new($this->text_class)($content);
|
||||
}
|
||||
}
|
||||
// It's philosophically consistent to simply ignore unknown node types
|
||||
|
@ -149,18 +151,17 @@ abstract class AbstractParser
|
|||
|
||||
protected function processAttributes(DOMElement $node, TagInterface $tag): void
|
||||
{
|
||||
/** @var array<string,string|bool> */
|
||||
$attributes = [];
|
||||
// absorb attributes
|
||||
// absorb attributes from DOMNode
|
||||
/** @var DOMNode $attribute */
|
||||
foreach ($node->attributes ?? [] as $attribute) {
|
||||
if ($attribute->nodeValue) {
|
||||
$attributes[$attribute->nodeName] = $attribute->nodeValue;
|
||||
} else {
|
||||
$attributes[$attribute->nodeName] = true;
|
||||
$attributes[$attribute->nodeName] = BooleanAttribute::true;
|
||||
}
|
||||
}
|
||||
// set attributes
|
||||
// set attributes internally
|
||||
foreach ($attributes as $k => $v) {
|
||||
if ($k == 'id' && is_string($v)) {
|
||||
$tag->setID($v);
|
||||
|
@ -205,4 +206,4 @@ abstract class AbstractParser
|
|||
// return null if nothing found
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace ByJoby\HTML\Helpers;
|
|||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use BackedEnum;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use Exception;
|
||||
use IteratorAggregate;
|
||||
use Stringable;
|
||||
|
@ -13,12 +14,12 @@ use Traversable;
|
|||
/**
|
||||
* Holds and validates a set of HTML attribute name/value pairs for use in tags.
|
||||
*
|
||||
* @implements ArrayAccess<string,bool|string|number|Stringable>
|
||||
* @implements IteratorAggregate<string,bool|string|number|Stringable>
|
||||
* @implements ArrayAccess<string,string|number|Stringable|BooleanAttribute>
|
||||
* @implements IteratorAggregate<string,string|number|Stringable|BooleanAttribute>
|
||||
*/
|
||||
class Attributes implements IteratorAggregate, ArrayAccess
|
||||
{
|
||||
/** @var array<string,bool|string|number|Stringable> */
|
||||
/** @var array<string,string|number|Stringable|BooleanAttribute> */
|
||||
protected $array = [];
|
||||
/** @var bool */
|
||||
protected $sorted = true;
|
||||
|
@ -26,7 +27,7 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
protected $disallowed = [];
|
||||
|
||||
/**
|
||||
* @param null|array<string,bool|string|number|Stringable> $array
|
||||
* @param null|array<string,string|number|Stringable|BooleanAttribute|BooleanAttribute> $array
|
||||
* @param array<mixed,string> $disallowed
|
||||
* @return void
|
||||
*/
|
||||
|
@ -69,16 +70,18 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
}
|
||||
|
||||
/**
|
||||
* Set a value as a stringable enum array, automatically converting from a single enum or normal array of enums.
|
||||
* Set a value as an array of enums, which will be internally saved as a
|
||||
* string separated by $separator. An array of Enum values can also be
|
||||
* retrieved using asEnumArray().
|
||||
*
|
||||
* @template T of BackedEnum
|
||||
* @param string $offset
|
||||
* @param null|BackedEnum|StringableEnumArray<T>|array<string|int,T> $value
|
||||
* @param null|BackedEnum|array<string|int,T> $value
|
||||
* @param class-string<T> $enum_class
|
||||
* @param string $separator
|
||||
* @return static
|
||||
*/
|
||||
public function setEnumArray(string $offset, null|BackedEnum|StringableEnumArray|array $value, string $enum_class, string $separator): static
|
||||
public function setEnumArray(string $offset, null|BackedEnum|array $value, string $enum_class, string $separator): static
|
||||
{
|
||||
if (is_null($value)) {
|
||||
$value = [];
|
||||
|
@ -94,7 +97,9 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a given offset's value as an array of enums.
|
||||
* Returns a given offset's value as an array of enums. Note that this
|
||||
* method always returns an array, it will simply be empty for empty
|
||||
* attributes, unset attributes, or attributes with no valid values in them.
|
||||
*
|
||||
* @template T of BackedEnum
|
||||
* @param string $offset
|
||||
|
@ -104,12 +109,31 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
*/
|
||||
public function asEnumArray(string $offset, string $enum_class, string $separator): array
|
||||
{
|
||||
$value = strval($this->offsetGet($offset));
|
||||
$value = $this->offsetGet($offset);
|
||||
// short circuit if value is a boolean attribute
|
||||
if ($value instanceof BooleanAttribute) {
|
||||
return [];
|
||||
}
|
||||
// process as string
|
||||
$value = strval($value);
|
||||
$value = explode($separator, $value);
|
||||
$value = array_map(
|
||||
$enum_class::tryFrom(...),
|
||||
$value
|
||||
);
|
||||
if (!$enum_class::cases()) {
|
||||
// short-circuit if there are no cases in the enum
|
||||
return [];
|
||||
} elseif (is_string($enum_class::cases()[0]->value)) {
|
||||
// look at string values only
|
||||
$value = array_map(
|
||||
fn(string|int $e) => $enum_class::tryFrom(strval($e)),
|
||||
$value
|
||||
);
|
||||
} else {
|
||||
// look at int values only
|
||||
$value = array_map(
|
||||
fn(string|int $e) => $enum_class::tryFrom(intval($e)),
|
||||
$value
|
||||
);
|
||||
}
|
||||
// filter and return
|
||||
$value = array_filter(
|
||||
$value,
|
||||
fn($e) => !empty($e)
|
||||
|
@ -126,6 +150,9 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
public function asString(string $offset): null|string|Stringable
|
||||
{
|
||||
$value = $this->offsetGet($offset);
|
||||
if (is_numeric($value)) {
|
||||
$value = strval($value);
|
||||
}
|
||||
if ($value instanceof Stringable || is_string($value)) {
|
||||
return $value;
|
||||
} else {
|
||||
|
@ -142,8 +169,8 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
public function asInt(string $offset): null|int
|
||||
{
|
||||
$value = $this->asNumber($offset);
|
||||
if (is_int($value)) {
|
||||
return $value;
|
||||
if (is_numeric($value)) {
|
||||
return intval($value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -216,7 +243,7 @@ class Attributes implements IteratorAggregate, ArrayAccess
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array<string,bool|string|number|Stringable>
|
||||
* @return array<string,string|number|Stringable|BooleanAttribute>
|
||||
*/
|
||||
public function getArray(): array
|
||||
{
|
||||
|
|
16
src/Html5/Enums/BooleanAttribute.php
Normal file
16
src/Html5/Enums/BooleanAttribute.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace ByJoby\HTML\Html5\Enums;
|
||||
|
||||
/**
|
||||
* This special enum is used to specify that an attribute is an HTML5 boolean
|
||||
* value. Any attribute set to BooleanAttribute::true will render as a lone tag,
|
||||
* with no value like <tag attribute>. Any attribute set to
|
||||
* BooleanAttribute::false will not render.
|
||||
*/
|
||||
enum BooleanAttribute {
|
||||
/** Render an attribute with no value */
|
||||
case true;
|
||||
/** Do not render this attribute */
|
||||
case false;
|
||||
}
|
53
src/Html5/Enums/ReferrerPolicy_script.php
Normal file
53
src/Html5/Enums/ReferrerPolicy_script.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace ByJoby\HTML\Html5\Enums;
|
||||
|
||||
/**
|
||||
* A string indicating which referrer to use when fetching the resource. These
|
||||
* values are valid in <script> elements.
|
||||
*
|
||||
* Description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
|
||||
*/
|
||||
enum ReferrerPolicy_script: string
|
||||
{
|
||||
/**
|
||||
* (default): Send a full URL when performing a same-origin request, only
|
||||
* send the origin when the protocol security level stays the same
|
||||
* (HTTPS→HTTPS), and send no header to a less secure destination
|
||||
* (HTTPS→HTTP).
|
||||
*/
|
||||
case strictOriginWhenCrossOrigin = "strict-origin-when-cross-origin";
|
||||
/**
|
||||
* means that the Referer header will not be sent.
|
||||
*/
|
||||
case noReferrer = "no-referrer";
|
||||
/**
|
||||
* The sent referrer will be limited to the origin of the referring page:
|
||||
* its scheme, host, and port.
|
||||
*/
|
||||
case origin = "origin";
|
||||
/**
|
||||
* The referrer sent to other origins will be limited to the scheme, the
|
||||
* host, and the port. Navigations on the same origin will still include the
|
||||
* path.
|
||||
*/
|
||||
case originWhenCrossOrigin = "origin-when-cross-origin";
|
||||
/**
|
||||
* A referrer will be sent for same origin, but cross-origin requests will
|
||||
* contain no referrer information.
|
||||
*/
|
||||
case sameOrigin = "same-origin";
|
||||
/**
|
||||
* Only send the origin of the document as the referrer when the protocol
|
||||
* security level stays the same (HTTPS→HTTPS), but don't send it to a less
|
||||
* secure destination (HTTPS→HTTP).
|
||||
*/
|
||||
case strictOrigin = "strict-origin";
|
||||
/**
|
||||
* The referrer will include the origin and the path (but not the fragment,
|
||||
* password, or username). This value is unsafe, because it leaks origins
|
||||
* and paths from TLS-protected resources to insecure origins.
|
||||
*/
|
||||
case unsafeUrl = "unsafe-url";
|
||||
}
|
38
src/Html5/Enums/Type_script.php
Normal file
38
src/Html5/Enums/Type_script.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace ByJoby\HTML\Html5\Enums;
|
||||
|
||||
/**
|
||||
* The type attribute of the <script> element indicates the type of script
|
||||
* represented by the element: a classic script, a JavaScript module, an import
|
||||
* map, or a data block.
|
||||
*
|
||||
* Descriptions by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type
|
||||
*/
|
||||
enum Type_script: string
|
||||
{
|
||||
/**
|
||||
* Indicates that the script is a "classic script", containing JavaScript
|
||||
* code. Authors are encouraged to omit the attribute if the script refers
|
||||
* to JavaScript code rather than specify a MIME type. JavaScript MIME types
|
||||
* are listed in the IANA media types specification.
|
||||
*
|
||||
* Equivalent to the attribute being unset.
|
||||
*/
|
||||
case default = "text/javascript";
|
||||
/**
|
||||
* This value causes the code to be treated as a JavaScript module. The
|
||||
* processing of the script contents is deferred. The charset and defer
|
||||
* attributes have no effect. For information on using module, see our
|
||||
* JavaScript modules guide. Unlike classic scripts, module scripts require
|
||||
* the use of the CORS protocol for cross-origin fetching.
|
||||
*/
|
||||
case module = "module";
|
||||
/**
|
||||
* This value indicates that the body of the element contains an import map.
|
||||
* The import map is a JSON object that developers can use to control how
|
||||
* the browser resolves module specifiers when importing JavaScript modules
|
||||
*/
|
||||
case importMap = "importmap";
|
||||
}
|
|
@ -26,9 +26,9 @@ class BaseTag extends AbstractTag implements MetadataContent
|
|||
* Absolute and relative URLs are allowed. data: and javascript: URLs are
|
||||
* not allowed.
|
||||
*
|
||||
* @return null|string
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function href(): null|string
|
||||
public function href(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('href');
|
||||
}
|
||||
|
@ -38,16 +38,13 @@ class BaseTag extends AbstractTag implements MetadataContent
|
|||
* Absolute and relative URLs are allowed. data: and javascript: URLs are
|
||||
* not allowed.
|
||||
*
|
||||
* @param null|string $href
|
||||
* @param null|string|Stringable $href
|
||||
* @return static
|
||||
*/
|
||||
public function setHref(null|string $href): static
|
||||
public function setHref(null|string|Stringable $href): static
|
||||
{
|
||||
if (!$href) {
|
||||
$this->attributes()['href'] = false;
|
||||
} else {
|
||||
$this->attributes()['href'] = $href;
|
||||
}
|
||||
if ($href) $this->attributes()['href'] = $href;
|
||||
else $this->unsetHref();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -88,7 +85,7 @@ class BaseTag extends AbstractTag implements MetadataContent
|
|||
public function setTarget(null|string|Stringable|BrowsingContext $target): static
|
||||
{
|
||||
if (!$target) {
|
||||
$this->attributes()['target'] = false;
|
||||
$this->unsetTarget();
|
||||
} elseif ($target instanceof BrowsingContext) {
|
||||
$this->attributes()['target'] = $target->value;
|
||||
} else {
|
||||
|
|
|
@ -47,17 +47,17 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*
|
||||
* if $as is As_link::fetch then $crossorigin must be specified
|
||||
*
|
||||
* @param null|Rel_link|StringableEnumArray<Rel_link>|array<int|string,Rel_link> $rel
|
||||
* @param null|Rel_link|array<int|string,Rel_link> $rel
|
||||
* @param null|As_link|null $as
|
||||
* @param null|CrossOrigin|null $crossorigin
|
||||
* @return static
|
||||
*/
|
||||
public function setRel(null|Rel_link|StringableEnumArray|array $rel, null|As_link $as = null, null|CrossOrigin $crossorigin = null): static
|
||||
public function setRel(null|Rel_link|array $rel, null|As_link $as = null, null|CrossOrigin $crossorigin = null): static
|
||||
{
|
||||
if (!$rel) {
|
||||
$this->attributes()['rel'] = false;
|
||||
$this->unsetRel();
|
||||
} else {
|
||||
$this->attributes()->setEnumArray('rel',$rel,Rel_link::class,' ');
|
||||
$this->attributes()->setEnumArray('rel', $rel, Rel_link::class, ' ');
|
||||
// check if new value includes Rel_link::preload and require $as if so
|
||||
$rel = $this->rel();
|
||||
if (in_array(Rel_link::preload, $rel)) {
|
||||
|
@ -116,7 +116,7 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
public function setAs(null|As_link $as, null|CrossOrigin $crossorigin = null): static
|
||||
{
|
||||
if (!$as) {
|
||||
$this->attributes()['as'] = false;
|
||||
$this->unsetAs();
|
||||
} else {
|
||||
$this->attributes()['as'] = $as->value;
|
||||
// check if we just set as to As_link::fetch and require $crossorigin if so
|
||||
|
@ -171,7 +171,7 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
public function setCrossorigin(null|CrossOrigin $crossorigin): static
|
||||
{
|
||||
if (!$crossorigin) {
|
||||
$this->attributes()['crossorigin'] = false;
|
||||
$this->unsetCrossorigin();
|
||||
} else {
|
||||
$this->attributes()['crossorigin'] = $crossorigin->value;
|
||||
}
|
||||
|
@ -211,11 +211,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setHref(null|string|Stringable $href): static
|
||||
{
|
||||
if (!$href) {
|
||||
$this->attributes()['href'] = false;
|
||||
} else {
|
||||
$this->attributes()['href'] = $href;
|
||||
}
|
||||
if ($href) $this->attributes()['href'] = $href;
|
||||
else $this->unsetHref();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -258,11 +255,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setHreflang(null|string|Stringable $hreflang): static
|
||||
{
|
||||
if (!$hreflang) {
|
||||
$this->attributes()['hreflang'] = false;
|
||||
} else {
|
||||
$this->attributes()['hreflang'] = $hreflang;
|
||||
}
|
||||
if ($hreflang) $this->attributes()['hreflang'] = $hreflang;
|
||||
else $this->unsetHreflang();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -304,11 +298,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setImagesizes(null|string|Stringable $imagesizes): static
|
||||
{
|
||||
if (!$imagesizes) {
|
||||
$this->attributes()['imagesizes'] = false;
|
||||
} else {
|
||||
$this->attributes()['imagesizes'] = $imagesizes;
|
||||
}
|
||||
if ($imagesizes) $this->attributes()['imagesizes'] = $imagesizes;
|
||||
else $this->unsetImagesizes();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -350,11 +341,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setImagesrcset(null|string|Stringable $imagesrcset): static
|
||||
{
|
||||
if (!$imagesrcset) {
|
||||
$this->attributes()['imagesrcset'] = false;
|
||||
} else {
|
||||
$this->attributes()['imagesrcset'] = $imagesrcset;
|
||||
}
|
||||
if ($imagesrcset) $this->attributes()['imagesrcset'] = $imagesrcset;
|
||||
else $this->unsetImagesrcset();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -396,11 +384,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setIntegrity(null|string|Stringable $integrity): static
|
||||
{
|
||||
if (!$integrity) {
|
||||
$this->attributes()['integrity'] = false;
|
||||
} else {
|
||||
$this->attributes()['integrity'] = $integrity;
|
||||
}
|
||||
if ($integrity) $this->attributes()['integrity'] = $integrity;
|
||||
else $this->unsetIntegrity();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -442,11 +427,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setMedia(null|string|Stringable $media): static
|
||||
{
|
||||
if (!$media) {
|
||||
$this->attributes()['media'] = false;
|
||||
} else {
|
||||
$this->attributes()['media'] = $media;
|
||||
}
|
||||
if ($media) $this->attributes()['media'] = $media;
|
||||
else $this->unsetMedia();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -482,11 +464,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setReferrerpolicy(null|ReferrerPolicy_link $referrerpolicy): static
|
||||
{
|
||||
if (!$referrerpolicy) {
|
||||
$this->attributes()['referrerpolicy'] = false;
|
||||
} else {
|
||||
$this->attributes()['referrerpolicy'] = $referrerpolicy->value;
|
||||
}
|
||||
if ($referrerpolicy) $this->attributes()['referrerpolicy'] = $referrerpolicy->value;
|
||||
else $this->unsetReferrerpolicy();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -533,11 +512,8 @@ class LinkTag extends AbstractTag implements MetadataContent
|
|||
*/
|
||||
public function setType(null|string|Stringable $type): static
|
||||
{
|
||||
if (!$type) {
|
||||
$this->attributes()['type'] = false;
|
||||
} else {
|
||||
$this->attributes()['type'] = $type;
|
||||
}
|
||||
if ($type) $this->attributes()['type'] = $type;
|
||||
else $this->unsetType();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@ use ByJoby\HTML\DisplayTypes\DisplayContents;
|
|||
use ByJoby\HTML\Tags\AbstractContentTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <noscript> HTML element defines a section of HTML to be inserted if a
|
||||
* script type on the page is unsupported or if scripting is currently turned
|
||||
* off in the browser.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript
|
||||
*/
|
||||
class NoscriptTag extends AbstractContentTag implements MetadataContent, PhrasingContent, DisplayContents
|
||||
{
|
||||
|
|
|
@ -5,174 +5,379 @@ namespace ByJoby\HTML\Html5\Tags;
|
|||
use ByJoby\HTML\ContentCategories\MetadataContent;
|
||||
use ByJoby\HTML\ContentCategories\PhrasingContent;
|
||||
use ByJoby\HTML\DisplayTypes\DisplayNone;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use ByJoby\HTML\Html5\Enums\CrossOrigin;
|
||||
use ByJoby\HTML\Html5\Enums\ReferrerPolicy_script;
|
||||
use ByJoby\HTML\Html5\Enums\Type_script;
|
||||
use ByJoby\HTML\Tags\AbstractContentTag;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <script> HTML element is used to embed executable code or data; this is
|
||||
* typically used to embed or refer to JavaScript code. The <script> element can
|
||||
* also be used with other languages, such as WebGL's GLSL shader programming
|
||||
* language and JSON.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
|
||||
*/
|
||||
class ScriptTag extends AbstractContentTag implements MetadataContent, PhrasingContent, DisplayNone
|
||||
{
|
||||
const TAG = 'script';
|
||||
|
||||
/**
|
||||
* For classic scripts, if the async attribute is present, then the classic
|
||||
* script will be fetched in parallel to parsing and evaluated as soon as it
|
||||
* is available.
|
||||
*
|
||||
* For module scripts, if the async attribute is present then the scripts
|
||||
* and all their dependencies will be executed in the defer queue, therefore
|
||||
* they will get fetched in parallel to parsing and evaluated as soon as
|
||||
* they are available.
|
||||
*
|
||||
* This attribute allows the elimination of parser-blocking JavaScript where
|
||||
* the browser would have to load and evaluate scripts before continuing to
|
||||
* parse. defer has a similar effect in this case.
|
||||
*
|
||||
* @param boolean $async
|
||||
* @return static
|
||||
*/
|
||||
public function setAsync(bool $async): static
|
||||
{
|
||||
$this->attributes()['async'] = $async;
|
||||
if ($async) $this->attributes()['async'] = BooleanAttribute::true;
|
||||
else unset($this->attributes()['async']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For classic scripts, if the async attribute is present, then the classic
|
||||
* script will be fetched in parallel to parsing and evaluated as soon as it
|
||||
* is available.
|
||||
*
|
||||
* For module scripts, if the async attribute is present then the scripts
|
||||
* and all their dependencies will be executed in the defer queue, therefore
|
||||
* they will get fetched in parallel to parsing and evaluated as soon as
|
||||
* they are available.
|
||||
*
|
||||
* This attribute allows the elimination of parser-blocking JavaScript where
|
||||
* the browser would have to load and evaluate scripts before continuing to
|
||||
* parse. defer has a similar effect in this case.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function async(): bool
|
||||
{
|
||||
return !!$this->attributes()['async'];
|
||||
return $this->attributes()['async'] === BooleanAttribute::true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Boolean attribute is set to indicate to a browser that the script is
|
||||
* meant to be executed after the document has been parsed, but before
|
||||
* firing DOMContentLoaded.
|
||||
*
|
||||
* Scripts with the defer attribute will prevent the DOMContentLoaded event
|
||||
* from firing until the script has loaded and finished evaluating.
|
||||
*
|
||||
* @param boolean $defer
|
||||
* @return static
|
||||
*/
|
||||
public function setDefer(bool $defer): static
|
||||
{
|
||||
$this->attributes()['defer'] = $defer;
|
||||
if ($defer) $this->attributes()['defer'] = BooleanAttribute::true;
|
||||
else unset($this->attributes()['defer']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Boolean attribute is set to indicate to a browser that the script is
|
||||
* meant to be executed after the document has been parsed, but before
|
||||
* firing DOMContentLoaded.
|
||||
*
|
||||
* Scripts with the defer attribute will prevent the DOMContentLoaded event
|
||||
* from firing until the script has loaded and finished evaluating.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function defer(): bool
|
||||
{
|
||||
return !!$this->attributes()['defer'];
|
||||
return $this->attributes()['defer'] === BooleanAttribute::true;
|
||||
}
|
||||
|
||||
public function crossorigin(): null|string
|
||||
/**
|
||||
* Normal script elements pass minimal information to the window.onerror for
|
||||
* scripts which do not pass the standard CORS checks. To allow error
|
||||
* logging for sites which use a separate domain for static media, use this
|
||||
* attribute. See CORS settings attributes for a more descriptive
|
||||
* explanation of its valid arguments.
|
||||
*
|
||||
* @return null|CrossOrigin
|
||||
*/
|
||||
public function crossorigin(): null|CrossOrigin
|
||||
{
|
||||
return $this->attributes()->asString('crossorigin');
|
||||
return $this->attributes()->asEnum('crossorigin', CrossOrigin::class);
|
||||
}
|
||||
|
||||
public function setCrossorigin(null|string $crossorigin): static
|
||||
/**
|
||||
* Normal script elements pass minimal information to the window.onerror for
|
||||
* scripts which do not pass the standard CORS checks. To allow error
|
||||
* logging for sites which use a separate domain for static media, use this
|
||||
* attribute. See CORS settings attributes for a more descriptive
|
||||
* explanation of its valid arguments.
|
||||
*
|
||||
* @param null|CrossOrigin $crossorigin
|
||||
* @return static
|
||||
*/
|
||||
public function setCrossorigin(null|CrossOrigin $crossorigin): static
|
||||
{
|
||||
if (!$crossorigin) {
|
||||
$this->attributes()['crossorigin'] = false;
|
||||
} else {
|
||||
$this->attributes()['crossorigin'] = $crossorigin;
|
||||
}
|
||||
if ($crossorigin) $this->attributes()['crossorigin'] = $crossorigin->value;
|
||||
else unset($this->attributes()['crossorigin']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal script elements pass minimal information to the window.onerror for
|
||||
* scripts which do not pass the standard CORS checks. To allow error
|
||||
* logging for sites which use a separate domain for static media, use this
|
||||
* attribute. See CORS settings attributes for a more descriptive
|
||||
* explanation of its valid arguments.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetCrossorigin(): static
|
||||
{
|
||||
unset($this->attributes()['crossorigin']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function integrity(): null|string
|
||||
/**
|
||||
* This attribute contains inline metadata that a user agent can use to
|
||||
* verify that a fetched resource has been delivered free of unexpected
|
||||
* manipulation. See Subresource Integrity.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
||||
*
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function integrity(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('integrity');
|
||||
}
|
||||
|
||||
public function setIntegrity(null|string $integrity): static
|
||||
/**
|
||||
* This attribute contains inline metadata that a user agent can use to
|
||||
* verify that a fetched resource has been delivered free of unexpected
|
||||
* manipulation. See Subresource Integrity.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
||||
*
|
||||
* @param null|string|Stringable $integrity
|
||||
* @return static
|
||||
*/
|
||||
public function setIntegrity(null|string|Stringable $integrity): static
|
||||
{
|
||||
if (!$integrity) {
|
||||
$this->attributes()['integrity'] = false;
|
||||
} else {
|
||||
$this->attributes()['integrity'] = $integrity;
|
||||
}
|
||||
if ($integrity) $this->attributes()['integrity'] = $integrity;
|
||||
else $this->unsetIntegrity();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This attribute contains inline metadata that a user agent can use to
|
||||
* verify that a fetched resource has been delivered free of unexpected
|
||||
* manipulation. See Subresource Integrity.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetIntegrity(): static
|
||||
{
|
||||
unset($this->attributes()['integrity']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Boolean attribute is set to indicate that the script should not be
|
||||
* executed in browsers that support ES modules — in effect, this can be
|
||||
* used to serve fallback scripts to older browsers that do not support
|
||||
* modular JavaScript code.
|
||||
*
|
||||
* @param boolean $nomodule
|
||||
* @return static
|
||||
*/
|
||||
public function setNomodule(bool $nomodule): static
|
||||
{
|
||||
$this->attributes()['nomodule'] = $nomodule;
|
||||
if ($nomodule) $this->attributes()['nomodule'] = BooleanAttribute::true;
|
||||
else unset($this->attributes()['nomodule']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Boolean attribute is set to indicate that the script should not be
|
||||
* executed in browsers that support ES modules — in effect, this can be
|
||||
* used to serve fallback scripts to older browsers that do not support
|
||||
* modular JavaScript code.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function nomodule(): bool
|
||||
{
|
||||
return !!$this->attributes()['nomodule'];
|
||||
return $this->attributes()['nomodule'] === BooleanAttribute::true;
|
||||
}
|
||||
|
||||
public function nonce(): null|string
|
||||
/**
|
||||
* A cryptographic nonce (number used once) to allow scripts in a script-src
|
||||
* Content-Security-Policy. The server must generate a unique nonce value
|
||||
* each time it transmits a policy. It is critical to provide a nonce that
|
||||
* cannot be guessed as bypassing a resource's policy is otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function nonce(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('nonce');
|
||||
}
|
||||
|
||||
public function setNonce(null|string $nonce): static
|
||||
/**
|
||||
* A cryptographic nonce (number used once) to allow scripts in a script-src
|
||||
* Content-Security-Policy. The server must generate a unique nonce value
|
||||
* each time it transmits a policy. It is critical to provide a nonce that
|
||||
* cannot be guessed as bypassing a resource's policy is otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
|
||||
*
|
||||
* @param null|string|Stringable $nonce
|
||||
* @return static
|
||||
*/
|
||||
public function setNonce(null|string|Stringable $nonce): static
|
||||
{
|
||||
if (!$nonce) {
|
||||
$this->attributes()['nonce'] = false;
|
||||
} else {
|
||||
$this->attributes()['nonce'] = $nonce;
|
||||
}
|
||||
if ($nonce) $this->attributes()['nonce'] = $nonce;
|
||||
else $this->unsetNonce();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic nonce (number used once) to allow scripts in a script-src
|
||||
* Content-Security-Policy. The server must generate a unique nonce value
|
||||
* each time it transmits a policy. It is critical to provide a nonce that
|
||||
* cannot be guessed as bypassing a resource's policy is otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetNonce(): static
|
||||
{
|
||||
unset($this->attributes()['nonce']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function referrerpolicy(): null|string
|
||||
/**
|
||||
* Indicates which referrer to send when fetching the script, or resources
|
||||
* fetched by the script.
|
||||
*
|
||||
* @return null|ReferrerPolicy_script
|
||||
*/
|
||||
public function referrerpolicy(): null|ReferrerPolicy_script
|
||||
{
|
||||
return $this->attributes()->asString('referrerpolicy');
|
||||
return $this->attributes()->asEnum('referrerpolicy', ReferrerPolicy_script::class);
|
||||
}
|
||||
|
||||
public function setReferrerpolicy(null|string $referrerpolicy): static
|
||||
/**
|
||||
* Indicates which referrer to send when fetching the script, or resources
|
||||
* fetched by the script.
|
||||
*
|
||||
* @param null|ReferrerPolicy_script $referrerpolicy
|
||||
* @return static
|
||||
*/
|
||||
public function setReferrerpolicy(null|ReferrerPolicy_script $referrerpolicy): static
|
||||
{
|
||||
if (!$referrerpolicy) {
|
||||
$this->attributes()['referrerpolicy'] = false;
|
||||
} else {
|
||||
$this->attributes()['referrerpolicy'] = $referrerpolicy;
|
||||
}
|
||||
if ($referrerpolicy) $this->attributes()['referrerpolicy'] = $referrerpolicy->value;
|
||||
else $this->unsetReferrerpolicy();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates which referrer to send when fetching the script, or resources
|
||||
* fetched by the script.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetReferrerpolicy(): static
|
||||
{
|
||||
unset($this->attributes()['referrerpolicy']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function src(): null|string
|
||||
/**
|
||||
* This attribute specifies the URI of an external script; this can be used
|
||||
* as an alternative to embedding a script directly within a document.
|
||||
*
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function src(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('src');
|
||||
}
|
||||
|
||||
public function setSrc(null|string $src): static
|
||||
/**
|
||||
* This attribute specifies the URI of an external script; this can be used
|
||||
* as an alternative to embedding a script directly within a document.
|
||||
*
|
||||
* @param null|string|Stringable $src
|
||||
* @return static
|
||||
*/
|
||||
public function setSrc(null|string|Stringable $src): static
|
||||
{
|
||||
if (!$src) {
|
||||
$this->attributes()['src'] = false;
|
||||
} else {
|
||||
$this->attributes()['src'] = $src;
|
||||
}
|
||||
if ($src) $this->attributes()['src'] = $src;
|
||||
else $this->unsetSrc();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This attribute specifies the URI of an external script; this can be used
|
||||
* as an alternative to embedding a script directly within a document.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetSrc(): static
|
||||
{
|
||||
unset($this->attributes()['src']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function type(): null|string
|
||||
/**
|
||||
* This attribute indicates the type of script represented.
|
||||
*
|
||||
* @return null|Type_script
|
||||
*/
|
||||
public function type(): null|Type_script
|
||||
{
|
||||
return $this->attributes()->asString('type');
|
||||
return $this->attributes()->asEnum('type', Type_script::class);
|
||||
}
|
||||
|
||||
public function setType(null|string $type): static
|
||||
/**
|
||||
* This attribute indicates the type of script represented.
|
||||
*
|
||||
* @param null|Type_script $type
|
||||
* @return static
|
||||
*/
|
||||
public function setType(null|Type_script $type): static
|
||||
{
|
||||
if (!$type) {
|
||||
$this->attributes()['type'] = false;
|
||||
} else {
|
||||
$this->attributes()['type'] = $type;
|
||||
}
|
||||
if ($type) $this->attributes()['type'] = $type->value;
|
||||
else $this->unsetType();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This attribute indicates the type of script represented.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetType(): static
|
||||
{
|
||||
unset($this->attributes()['type']);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,56 +4,110 @@ namespace ByJoby\HTML\Html5\Tags;
|
|||
|
||||
use ByJoby\HTML\ContentCategories\MetadataContent;
|
||||
use ByJoby\HTML\Tags\AbstractContentTag;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <style> HTML element contains style information for a document, or part
|
||||
* of a document. It contains CSS, which is applied to the contents of the
|
||||
* document containing the <style> element.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style
|
||||
*/
|
||||
class StyleTag extends AbstractContentTag implements MetadataContent
|
||||
{
|
||||
const TAG = 'style';
|
||||
|
||||
public function media(): null|string
|
||||
/**
|
||||
* This attribute defines which media the style should be applied to. Its
|
||||
* value is a media query, which defaults to all if the attribute is
|
||||
* missing.
|
||||
*
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function media(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('media');
|
||||
}
|
||||
|
||||
public function setMedia(null|string $media): static
|
||||
/**
|
||||
* This attribute defines which media the style should be applied to. Its
|
||||
* value is a media query, which defaults to all if the attribute is
|
||||
* missing.
|
||||
*
|
||||
* @param null|string|Stringable $media
|
||||
* @return static
|
||||
*/
|
||||
public function setMedia(null|string|Stringable $media): static
|
||||
{
|
||||
if (!$media) {
|
||||
$this->attributes()['media'] = false;
|
||||
} else {
|
||||
$this->attributes()['media'] = $media;
|
||||
}
|
||||
if ($media) $this->attributes()['media'] = $media;
|
||||
else $this->unsetMedia();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This attribute defines which media the style should be applied to. Its
|
||||
* value is a media query, which defaults to all if the attribute is
|
||||
* missing.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetMedia(): static
|
||||
{
|
||||
unset($this->attributes()['media']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function nonce(): null|string
|
||||
/**
|
||||
* A cryptographic nonce (number used once) used to allow inline styles in a
|
||||
* style-src Content-Security-Policy. The server must generate a unique
|
||||
* nonce value each time it transmits a policy. It is critical to provide a
|
||||
* nonce that cannot be guessed as bypassing a resource's policy is
|
||||
* otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
|
||||
*
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function nonce(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('nonce');
|
||||
}
|
||||
|
||||
public function setNonce(null|string $nonce): static
|
||||
/**
|
||||
* A cryptographic nonce (number used once) used to allow inline styles in a
|
||||
* style-src Content-Security-Policy. The server must generate a unique
|
||||
* nonce value each time it transmits a policy. It is critical to provide a
|
||||
* nonce that cannot be guessed as bypassing a resource's policy is
|
||||
* otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
|
||||
*
|
||||
* @param null|string|Stringable $nonce
|
||||
* @return static
|
||||
*/
|
||||
public function setNonce(null|string|Stringable $nonce): static
|
||||
{
|
||||
if (!$nonce) {
|
||||
$this->attributes()['nonce'] = false;
|
||||
} else {
|
||||
$this->attributes()['nonce'] = $nonce;
|
||||
}
|
||||
if ($nonce) $this->attributes()['nonce'] = $nonce;
|
||||
else $this->unsetNonce();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* A cryptographic nonce (number used once) used to allow inline styles in a
|
||||
* style-src Content-Security-Policy. The server must generate a unique
|
||||
* nonce value each time it transmits a policy. It is critical to provide a
|
||||
* nonce that cannot be guessed as bypassing a resource's policy is
|
||||
* otherwise trivial.
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetNonce(): static
|
||||
{
|
||||
unset($this->attributes()['nonce']);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,35 +6,59 @@ use ByJoby\HTML\ContentCategories\FlowContent;
|
|||
use ByJoby\HTML\ContentCategories\SectioningRoot;
|
||||
use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
||||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <blockquote> HTML element indicates that the enclosed text is an extended
|
||||
* quotation. Usually, this is rendered visually by indentation (see Notes for
|
||||
* how to change it). A URL for the source of the quotation may be given using
|
||||
* the cite attribute, while a text representation of the source can be given
|
||||
* using the <cite> element.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote
|
||||
*/
|
||||
class BlockquoteTag extends AbstractContainerTag implements FlowContent, SectioningRoot, DisplayBlock
|
||||
{
|
||||
const TAG = 'blockquote';
|
||||
|
||||
public function cite(): null|string
|
||||
/**
|
||||
* A URL that designates a source document or message for the information
|
||||
* quoted. This attribute is intended to point to information explaining the
|
||||
* context or the reference for the quote.
|
||||
*
|
||||
* @return null|string|Stringable
|
||||
*/
|
||||
public function cite(): null|string|Stringable
|
||||
{
|
||||
return $this->attributes()->asString('cite');
|
||||
}
|
||||
|
||||
public function setCite(null|string $cite): static
|
||||
/**
|
||||
* A URL that designates a source document or message for the information
|
||||
* quoted. This attribute is intended to point to information explaining the
|
||||
* context or the reference for the quote.
|
||||
*
|
||||
* @param null|string|Stringable $cite
|
||||
* @return static
|
||||
*/
|
||||
public function setCite(null|string|Stringable $cite): static
|
||||
{
|
||||
if (!$cite) {
|
||||
$this->attributes()['cite'] = false;
|
||||
} else {
|
||||
$this->attributes()['cite'] = $cite;
|
||||
}
|
||||
if ($cite) $this->attributes()['cite'] = $cite;
|
||||
else $this->unsetCite();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A URL that designates a source document or message for the information
|
||||
* quoted. This attribute is intended to point to information explaining the
|
||||
* context or the reference for the quote.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function unsetCite(): static
|
||||
{
|
||||
unset($this->attributes()['cite']);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,11 @@ namespace ByJoby\HTML\Html5\TextContentTags;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <dd> HTML element provides the description, definition, or value for the
|
||||
* preceding term (<dt>) in a description list (<dl>).
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd
|
||||
*/
|
||||
class DdTag extends AbstractContainerTag
|
||||
{
|
||||
|
|
|
@ -7,10 +7,13 @@ use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <div> HTML element is the generic container for flow content. It has no
|
||||
* effect on the content or layout until styled in some way using CSS (e.g.
|
||||
* styling is directly applied to it, or some kind of layout model like Flexbox
|
||||
* is applied to its parent element).
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
|
||||
*/
|
||||
class DivTag extends AbstractContainerTag implements DisplayBlock, SectioningContent
|
||||
{
|
||||
|
|
|
@ -7,10 +7,13 @@ use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <dl> HTML element represents a description list. The element encloses a
|
||||
* list of groups of terms (specified using the <dt> element) and descriptions
|
||||
* (provided by <dd> elements). Common uses for this element are to implement a
|
||||
* glossary or to display metadata (a list of key-value pairs).
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl
|
||||
*/
|
||||
class DlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
|
|
@ -5,10 +5,16 @@ namespace ByJoby\HTML\Html5\TextContentTags;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <dt> HTML element specifies a term in a description or definition list,
|
||||
* and as such must be used inside a <dl> element. It is usually followed by a
|
||||
* <dd> element; however, multiple <dt> elements in a row indicate several terms
|
||||
* that are all defined by the immediate next <dd> element.
|
||||
*
|
||||
* The subsequent <dd> (Description Details) element provides the definition or
|
||||
* other related text associated with the term specified using <dt>.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt
|
||||
*/
|
||||
class DtTag extends AbstractContainerTag
|
||||
{
|
||||
|
|
|
@ -7,10 +7,11 @@ use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <figcaption> HTML element represents a caption or legend describing the
|
||||
* rest of the contents of its parent <figure> element.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption
|
||||
*/
|
||||
class FigcaptionTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
|
|
@ -10,10 +10,12 @@ use ByJoby\HTML\Tags\AbstractGroupedTag;
|
|||
use ByJoby\HTML\Tags\TagInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <figure> HTML element represents self-contained content, potentially with
|
||||
* an optional caption, which is specified using the <figcaption> element. The
|
||||
* figure, its caption, and its contents are referenced as a single unit.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure
|
||||
*/
|
||||
class FigureTag extends AbstractGroupedTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
@ -34,7 +36,13 @@ class FigureTag extends AbstractGroupedTag implements FlowContent, DisplayBlock
|
|||
$this->addGroup(ContainerGroup::ofTag('figcaption', 1));
|
||||
}
|
||||
|
||||
public function reverseCaptionOrder(): static
|
||||
/**
|
||||
* Flip the caption and content order from its current state. The default
|
||||
* state is to have the content first, then the caption.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function flipCaptionOrder(): static
|
||||
{
|
||||
$this->children = array_reverse($this->children);
|
||||
return $this;
|
||||
|
|
|
@ -7,10 +7,12 @@ use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
|||
use ByJoby\HTML\Tags\AbstractTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <hr> HTML element represents a thematic break between paragraph-level
|
||||
* elements: for example, a change of scene in a story, or a shift of topic
|
||||
* within a section.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr
|
||||
*/
|
||||
class HrTag extends AbstractTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
|
|
@ -8,10 +8,14 @@ use ByJoby\HTML\Html5\Enums\Type_list;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <li> HTML element is used to represent an item in a list. It must be
|
||||
* contained in a parent element: an ordered list (<ol>), an unordered list
|
||||
* (<ul>), or a menu (<menu>). In menus and unordered lists, list items are
|
||||
* usually displayed using bullet points. In ordered lists, they are usually
|
||||
* displayed with an ascending counter on the left, such as a number or letter.
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li
|
||||
*/
|
||||
class LiTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
@ -35,11 +39,8 @@ class LiTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function setType(null|Type_list $type): static
|
||||
{
|
||||
if (!$type) {
|
||||
$this->attributes()['type'] = false;
|
||||
} else {
|
||||
$this->attributes()['type'] = $type->value;
|
||||
}
|
||||
if ($type) $this->attributes()['type'] = $type->value;
|
||||
else $this->unsetType();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,13 @@ use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
|||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* The <menu> HTML element is described in the HTML specification as a semantic
|
||||
* alternative to <ul>, but treated by browsers (and exposed through the
|
||||
* accessibility tree) as no different than <ul>. It represents an unordered
|
||||
* list of items (which are represented by <li> elements).
|
||||
*
|
||||
* Tag description by Mozilla Contributors licensed under CC-BY-SA 2.5
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu
|
||||
*/
|
||||
class MenuTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace ByJoby\HTML\Html5\TextContentTags;
|
|||
|
||||
use ByJoby\HTML\ContentCategories\FlowContent;
|
||||
use ByJoby\HTML\DisplayTypes\DisplayBlock;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use ByJoby\HTML\Html5\Enums\Type_list;
|
||||
use ByJoby\HTML\Tags\AbstractContainerTag;
|
||||
|
||||
|
@ -27,7 +28,8 @@ class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function setReversed(bool $reversed): static
|
||||
{
|
||||
$this->attributes()['reversed'] = $reversed;
|
||||
if ($reversed) $this->attributes()['reversed'] = BooleanAttribute::true;
|
||||
else unset($this->attributes()['reversed']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -39,7 +41,7 @@ class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function reversed(): bool
|
||||
{
|
||||
return !!$this->attributes()['reversed'];
|
||||
return $this->attributes()['reversed'] === BooleanAttribute::true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,11 +54,7 @@ class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function start(): null|int
|
||||
{
|
||||
if ($this->attributes()['start']) {
|
||||
return intval($this->attributes()->asString('start'));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return $this->attributes()->asInt('start');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,11 +68,8 @@ class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function setStart(null|int $start): static
|
||||
{
|
||||
if (!$start) {
|
||||
$this->attributes()['start'] = false;
|
||||
} else {
|
||||
$this->attributes()['start'] = strval($start);
|
||||
}
|
||||
if (is_null($start)) $this->unsetStart();
|
||||
else $this->attributes()['start'] = $start;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -116,11 +111,8 @@ class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
|
|||
*/
|
||||
public function setType(null|Type_list $type): static
|
||||
{
|
||||
if (!$type) {
|
||||
$this->attributes()['type'] = false;
|
||||
} else {
|
||||
$this->attributes()['type'] = $type->value;
|
||||
}
|
||||
if ($type) $this->attributes()['type'] = $type->value;
|
||||
else $this->unsetType();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace ByJoby\HTML\Traits;
|
|||
use ByJoby\HTML\Helpers\Attributes;
|
||||
use ByJoby\HTML\Helpers\Classes;
|
||||
use ByJoby\HTML\Helpers\Styles;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use Exception;
|
||||
use Stringable;
|
||||
|
||||
|
@ -88,10 +89,14 @@ trait TagTrait
|
|||
$strings[] = sprintf('style="%s"', $this->styles());
|
||||
}
|
||||
foreach ($this->attributes() as $name => $value) {
|
||||
if (is_string($value)) {
|
||||
$strings[] = sprintf('%s="%s"', $name, static::sanitizeAttribute($value));
|
||||
} elseif ($value) {
|
||||
if ($value == BooleanAttribute::false) {
|
||||
// skip over false boolean attributes
|
||||
continue;
|
||||
}elseif ($value == BooleanAttribute::true) {
|
||||
// true boolean attributes render as null
|
||||
$strings[] = $name;
|
||||
}elseif (is_string($value) || is_numeric($value) || $value instanceof Stringable) {
|
||||
$strings[] = sprintf('%s="%s"', $name, static::sanitizeAttribute(strval($value)));
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
|
|
|
@ -9,7 +9,14 @@ class FragmentTest extends TestCase
|
|||
{
|
||||
public function tag(string $name): AbstractContainerTag
|
||||
{
|
||||
$tag = $this->getMockForAbstractClass(AbstractContainerTag::class, [], '', true, true, true, ['tag']);
|
||||
$tag = $this->getMockForAbstractClass(
|
||||
AbstractContainerTag::class,
|
||||
[], 'Mock_Tag_' . $name,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
['tag']
|
||||
);
|
||||
$tag->method('tag')->willReturn($name);
|
||||
return $tag;
|
||||
}
|
||||
|
@ -62,4 +69,4 @@ class FragmentTest extends TestCase
|
|||
$div2->addChildAfter('c', 'a');
|
||||
$this->assertEquals($fragment, $div2->children()[2]->parentDocument());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,6 @@ namespace ByJoby\HTML\Helpers;
|
|||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
// TODO test setEnumArray
|
||||
// TODO test asEnumArray
|
||||
// TODO test asNumber
|
||||
// TODO test asInt
|
||||
// TODO test asFloat
|
||||
|
||||
class AttributesTest extends TestCase
|
||||
{
|
||||
public function testConstruction(): Attributes
|
||||
|
@ -79,4 +73,165 @@ class AttributesTest extends TestCase
|
|||
$this->expectExceptionMessage('Invalid character in attribute name');
|
||||
$attributes['>'] = 'b';
|
||||
}
|
||||
|
||||
public function testAsString(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$this->assertNull($a->asString('non-existent'));
|
||||
$a['empty-string'] = '';
|
||||
$this->assertEquals('', $a->asString('empty-string'));
|
||||
$a['string'] = 's';
|
||||
$this->assertEquals('s', $a->asString('string'));
|
||||
$a['int'] = 1;
|
||||
$this->assertEquals('1', $a->asString('int'));
|
||||
$a['int_string'] = '1';
|
||||
$this->assertEquals('1', $a->asString('int_string'));
|
||||
$a['float'] = 1.5;
|
||||
$this->assertEquals('1.5', $a->asString('float'));
|
||||
$a['float_string'] = '1.5';
|
||||
$this->assertEquals('1.5', $a->asString('float_string'));
|
||||
$a['zero'] = 0;
|
||||
$this->assertEquals('0', $a->asString('zero'));
|
||||
$a['zero_string'] = '0';
|
||||
$this->assertEquals('0', $a->asString('zero_string'));
|
||||
}
|
||||
|
||||
public function testAsNumber(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$this->assertNull($a->asNumber('non-existent'));
|
||||
$a['empty-string'] = '';
|
||||
$this->assertNull($a->asNumber('empty-string'));
|
||||
$a['string'] = 's';
|
||||
$this->assertNull($a->asNumber('string'));
|
||||
$a['int'] = 1;
|
||||
$this->assertEquals(1, $a->asNumber('int'));
|
||||
$a['int_string'] = '1';
|
||||
$this->assertEquals(1, $a->asNumber('int_string'));
|
||||
$a['float'] = 1.5;
|
||||
$this->assertEquals(1.5, $a->asNumber('float'));
|
||||
$a['float_string'] = '1.5';
|
||||
$this->assertEquals(1.5, $a->asNumber('float_string'));
|
||||
$a['zero'] = 0;
|
||||
$this->assertEquals(0, $a->asNumber('zero'));
|
||||
$a['zero_string'] = '0';
|
||||
$this->assertEquals(0, $a->asNumber('zero_string'));
|
||||
}
|
||||
|
||||
public function testAsFloat(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$this->assertNull($a->asFloat('non-existent'));
|
||||
$a['empty-string'] = '';
|
||||
$this->assertNull($a->asFloat('empty-string'));
|
||||
$a['string'] = 's';
|
||||
$this->assertNull($a->asFloat('string'));
|
||||
$a['int'] = 1;
|
||||
$this->assertEquals(1, $a->asFloat('int'));
|
||||
$a['int_string'] = '1';
|
||||
$this->assertEquals(1, $a->asFloat('int_string'));
|
||||
$a['float'] = 1.5;
|
||||
$this->assertEquals(1.5, $a->asFloat('float'));
|
||||
$a['float_string'] = '1.5';
|
||||
$this->assertEquals(1.5, $a->asFloat('float_string'));
|
||||
$a['zero'] = 0;
|
||||
$this->assertEquals(0, $a->asFloat('zero'));
|
||||
$a['zero_string'] = '0';
|
||||
$this->assertEquals(0, $a->asFloat('zero_string'));
|
||||
}
|
||||
|
||||
public function testAsInt(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$this->assertNull($a->asInt('non-existent'));
|
||||
$a['empty-string'] = '';
|
||||
$this->assertNull($a->asInt('empty-string'));
|
||||
$a['string'] = 's';
|
||||
$this->assertNull($a->asInt('string'));
|
||||
$a['int'] = 1;
|
||||
$this->assertEquals(1, $a->asInt('int'));
|
||||
$a['int_string'] = '1';
|
||||
$this->assertEquals(1, $a->asInt('int_string'));
|
||||
$a['float'] = 1.5;
|
||||
$this->assertEquals(1, $a->asInt('float'));
|
||||
$a['float_string'] = '1.5';
|
||||
$this->assertEquals(1., $a->asInt('float_string'));
|
||||
$a['zero'] = 0;
|
||||
$this->assertEquals(0, $a->asInt('zero'));
|
||||
$a['zero_string'] = '0';
|
||||
$this->assertEquals(0, $a->asInt('zero_string'));
|
||||
}
|
||||
|
||||
public function testAsEnum(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$a['string-a'] = TestStringEnum::a->value;
|
||||
$this->assertEquals(TestStringEnum::a, $a->asEnum('string-a', TestStringEnum::class));
|
||||
$a['string-b'] = TestStringEnum::b->value;
|
||||
$this->assertEquals(TestStringEnum::b, $a->asEnum('string-b', TestStringEnum::class));
|
||||
$a['int-one'] = TestIntEnum::one->value;
|
||||
$this->assertEquals(TestIntEnum::one, $a->asEnum('int-one', TestIntEnum::class));
|
||||
$a['int-two'] = TestIntEnum::two->value;
|
||||
$this->assertEquals(TestIntEnum::two, $a->asEnum('int-two', TestIntEnum::class));
|
||||
}
|
||||
|
||||
public function testAsEnumInvalidCases(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$a['string-c'] = 'c';
|
||||
$this->assertNull($a->asEnum('string-a', TestStringEnum::class));
|
||||
$this->assertNull($a->asEnum('string-a', TestIntEnum::class));
|
||||
$a['int-three'] = 'three';
|
||||
$this->assertNull($a->asEnum('int-two', TestIntEnum::class));
|
||||
$this->assertNull($a->asEnum('int-two', TestStringEnum::class));
|
||||
}
|
||||
|
||||
public function testEnumArraySingleValue(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$a->setEnumArray('v', TestStringEnum::a, TestStringEnum::class, ' ');
|
||||
$this->assertEquals('a', $a['v']);
|
||||
$this->assertEquals(
|
||||
[TestStringEnum::a],
|
||||
$a->asEnumArray('v', TestStringEnum::class, ' ')
|
||||
);
|
||||
// should return an empty array for a different enum class
|
||||
$this->assertEquals(
|
||||
[],
|
||||
$a->asEnumArray('v', TestIntEnum::class, ' ')
|
||||
);
|
||||
}
|
||||
|
||||
public function testEnumArrayValue(): void
|
||||
{
|
||||
$a = new Attributes();
|
||||
$a->setEnumArray('v', [TestStringEnum::a, TestStringEnum::b], TestStringEnum::class, ' ');
|
||||
$this->assertEquals('a b', $a['v']);
|
||||
$this->assertEquals(
|
||||
[TestStringEnum::a, TestStringEnum::b],
|
||||
$a->asEnumArray('v', TestStringEnum::class, ' ')
|
||||
);
|
||||
// should return an empty array for a different enum class
|
||||
$this->assertEquals(
|
||||
[],
|
||||
$a->asEnumArray('v', TestIntEnum::class, ' ')
|
||||
);
|
||||
// should return an empty array for a different separator
|
||||
$this->assertEquals(
|
||||
[],
|
||||
$a->asEnumArray('v', TestStringEnum::class, ', ')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum TestStringEnum: string
|
||||
{
|
||||
case a = 'a';
|
||||
case b = 'b';
|
||||
}
|
||||
|
||||
enum TestIntEnum: int
|
||||
{
|
||||
case one = 1;
|
||||
case two = 2;
|
||||
}
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
namespace ByJoby\HTML\Html5\Tags;
|
||||
|
||||
use ByJoby\HTML\Html5\Enums\As_link;
|
||||
use ByJoby\HTML\Html5\Enums\CrossOrigin;
|
||||
use ByJoby\HTML\Html5\Enums\ReferrerPolicy_link;
|
||||
use ByJoby\HTML\Html5\Enums\Rel_link;
|
||||
use ByJoby\HTML\Html5\Exceptions\InvalidArgumentsException;
|
||||
|
||||
class LinkTagTest extends TagTestCase
|
||||
{
|
||||
public function testAttributeHelpers(): void
|
||||
{
|
||||
// TODO update tests that now use enums, add tests for their exeption cases
|
||||
// $this->assertAttributeHelperMethods('rel', LinkTag::class, Rel_link::class, 'class');
|
||||
// $this->assertAttributeHelperMethods('as', LinkTag::class);
|
||||
// $this->assertAttributeHelperMethods('referrerpolicy', LinkTag::class);
|
||||
$this->assertAttributeHelperMethods('referrerpolicy', LinkTag::class, ReferrerPolicy_link::origin, 'origin');
|
||||
$this->assertAttributeHelperMethods('crossorigin', LinkTag::class, CrossOrigin::anonymous, 'anonymous');
|
||||
$this->assertAttributeHelperMethods('crossorigin', LinkTag::class, CrossOrigin::useCredentials, 'use-credentials');
|
||||
$this->assertAttributeHelperMethods('href', LinkTag::class);
|
||||
|
@ -23,4 +23,46 @@ class LinkTagTest extends TagTestCase
|
|||
$this->assertAttributeHelperMethods('media', LinkTag::class);
|
||||
$this->assertAttributeHelperMethods('type', LinkTag::class);
|
||||
}
|
||||
|
||||
public function testAsBasic(): void
|
||||
{
|
||||
$tag = new LinkTag();
|
||||
// set as to something that can be set alone
|
||||
$tag->setAs(As_link::document);
|
||||
$this->assertEquals('document', $tag->attributes()->asString('as'));
|
||||
// set as to fetch so crossorigin is required
|
||||
$tag->setAs(As_link::fetch, CrossOrigin::anonymous);
|
||||
$this->assertEquals('fetch', $tag->attributes()->asString('as'));
|
||||
$this->assertEquals('anonymous', $tag->attributes()->asString('crossorigin'));
|
||||
}
|
||||
|
||||
public function testRelBasic(): void
|
||||
{
|
||||
$tag = new LinkTag();
|
||||
// set rel as a single attribute
|
||||
$tag->setRel(Rel_link::prefetch);
|
||||
$this->assertEquals('prefetch', $tag->attributes()->asString('rel'));
|
||||
// set rel as an array of attributes
|
||||
$tag->setRel([Rel_link::prefetch, Rel_link::next]);
|
||||
$this->assertEquals('prefetch next', $tag->attributes()->asString('rel'));
|
||||
// set deeper values
|
||||
$tag->setRel(Rel_link::preload, As_link::fetch, CrossOrigin::anonymous);
|
||||
$this->assertEquals('preload', $tag->attributes()->asString('rel'));
|
||||
$this->assertEquals('fetch', $tag->attributes()->asString('as'));
|
||||
$this->assertEquals('anonymous', $tag->attributes()->asString('crossorigin'));
|
||||
}
|
||||
|
||||
public function testRelMIssingAs(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentsException::class);
|
||||
$tag = new LinkTag();
|
||||
$tag->setRel(Rel_link::preload);
|
||||
}
|
||||
|
||||
public function testRelMIssingCrossorigin(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentsException::class);
|
||||
$tag = new LinkTag();
|
||||
$tag->setRel(Rel_link::preload, As_link::fetch);
|
||||
}
|
||||
}
|
|
@ -2,14 +2,64 @@
|
|||
|
||||
namespace ByJoby\HTML\Html5\Tags;
|
||||
|
||||
use ByJoby\HTML\Html5\Enums\HttpEquiv_meta;
|
||||
use ByJoby\HTML\Html5\Enums\Name_meta;
|
||||
|
||||
class MetaTagTest extends TagTestCase
|
||||
{
|
||||
public function testAttributeHelpers(): void
|
||||
public function testCharset(): void
|
||||
{
|
||||
// TODO test all of these with their new format
|
||||
// $this->assertAttributeHelperMethods('name', MetaTag::class);
|
||||
// $this->assertAttributeHelperMethods('content', MetaTag::class);
|
||||
// $this->assertAttributeHelperMethods('http-equiv', MetaTag::class);
|
||||
// $this->assertAttributeHelperMethods('charset', MetaTag::class);
|
||||
$tag = new MetaTag();
|
||||
$tag->setCharset(true);
|
||||
$this->assertEquals("utf-8", $tag->attributes()['charset']);
|
||||
$tag->setCharset(false);
|
||||
$this->assertNull($tag->attributes()['charset']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testName(): void
|
||||
{
|
||||
$tag = new MetaTag();
|
||||
$tag->setNameAndContent(Name_meta::application, 'test');
|
||||
$this->assertEquals(Name_meta::application->value, $tag->attributes()['name']);
|
||||
$this->assertEquals('test', $tag->attributes()['content']);
|
||||
}
|
||||
|
||||
public function testHttpEquiv(): void
|
||||
{
|
||||
$tag = new MetaTag();
|
||||
$tag->setHttpEquivAndContent(HttpEquiv_meta::mime, 'text/plain');
|
||||
$this->assertEquals(HttpEquiv_meta::mime->value, $tag->attributes()['http-equiv']);
|
||||
$this->assertEquals('text/plain', $tag->attributes()['content']);
|
||||
}
|
||||
|
||||
public function testNameOverrides(): void
|
||||
{
|
||||
$tag = new MetaTag();
|
||||
$tag->setCharset(true);
|
||||
$tag->setHttpEquivAndContent(HttpEquiv_meta::mime, 'text/plain');
|
||||
$tag->setNameAndContent(Name_meta::application, 'test');
|
||||
$this->assertNull($tag->attributes()['charset']);
|
||||
$this->assertNull($tag->attributes()['http-equiv']);
|
||||
}
|
||||
|
||||
public function testHttpEquivOverrides(): void
|
||||
{
|
||||
$tag = new MetaTag();
|
||||
$tag->setCharset(true);
|
||||
$tag->setNameAndContent(Name_meta::application, 'test');
|
||||
$tag->setHttpEquivAndContent(HttpEquiv_meta::mime, 'text/plain');
|
||||
$this->assertNull($tag->attributes()['charset']);
|
||||
$this->assertNull($tag->attributes()['name']);
|
||||
}
|
||||
|
||||
public function testCharsetOverrides(): void
|
||||
{
|
||||
$tag = new MetaTag();
|
||||
$tag->setHttpEquivAndContent(HttpEquiv_meta::mime, 'text/plain');
|
||||
$tag->setNameAndContent(Name_meta::application, 'test');
|
||||
$tag->setCharset(true);
|
||||
$this->assertNull($tag->attributes()['name']);
|
||||
$this->assertNull($tag->attributes()['http-equiv']);
|
||||
$this->assertNull($tag->attributes()['content']);
|
||||
}
|
||||
}
|
|
@ -2,19 +2,23 @@
|
|||
|
||||
namespace ByJoby\HTML\Html5\Tags;
|
||||
|
||||
use ByJoby\HTML\Html5\Enums\CrossOrigin;
|
||||
use ByJoby\HTML\Html5\Enums\ReferrerPolicy_script;
|
||||
use ByJoby\HTML\Html5\Enums\Type_script;
|
||||
|
||||
class ScriptTagTest extends TagTestCase
|
||||
{
|
||||
public function testAttributeHelpers(): void
|
||||
{
|
||||
$this->assertAttributeHelperMethods('crossorigin', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('crossorigin', ScriptTag::class, CrossOrigin::useCredentials, CrossOrigin::useCredentials->value);
|
||||
$this->assertAttributeHelperMethods('integrity', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('integrity', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('nonce', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('referrerpolicy', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('referrerpolicy', ScriptTag::class, ReferrerPolicy_script::noReferrer, ReferrerPolicy_script::noReferrer->value);
|
||||
$this->assertAttributeHelperMethods('src', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('type', ScriptTag::class);
|
||||
$this->assertAttributeHelperMethods('type', ScriptTag::class, Type_script::module, Type_script::module->value);
|
||||
$this->assertBooleanAttributeHelperMethods('async', ScriptTag::class);
|
||||
$this->assertBooleanAttributeHelperMethods('defer', ScriptTag::class);
|
||||
$this->assertBooleanAttributeHelperMethods('nomodule', ScriptTag::class);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,14 +8,14 @@ use ByJoby\HTML\Nodes\TextInterface;
|
|||
|
||||
class FigureTagTest extends BaseTagTest
|
||||
{
|
||||
public function testCaptionOrder()
|
||||
public function testCaptionOrder(): void
|
||||
{
|
||||
$figure = new FigureTag();
|
||||
$figure->addChild(new FigcaptionTag);
|
||||
$figure->addChild('Some content');
|
||||
$this->assertInstanceOf(TextInterface::class, $figure->children()[0]);
|
||||
$this->assertInstanceOf(FigcaptionTag::class, $figure->children()[1]);
|
||||
$figure->reverseCaptionOrder();
|
||||
$figure->flipCaptionOrder();
|
||||
$this->assertInstanceOf(TextInterface::class, $figure->children()[1]);
|
||||
$this->assertInstanceOf(FigcaptionTag::class, $figure->children()[0]);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class OlTagTest extends BaseTagTest
|
|||
{
|
||||
$this->assertBooleanAttributeHelperMethods('reversed', OlTag::class);
|
||||
$this->assertAttributeHelperMethods('start', OlTag::class, 1, '1');
|
||||
$this->assertAttributeHelperMethods('start', OlTag::class, 0, null);
|
||||
$this->assertAttributeHelperMethods('start', OlTag::class, 0, '0');
|
||||
$this->assertAttributeHelperMethods('type', OlTag::class, Type_list::letterLower, 'a');
|
||||
$this->assertAttributeHelperMethods('type', OlTag::class, Type_list::letterUpper, 'A');
|
||||
$this->assertAttributeHelperMethods('type', OlTag::class, Type_list::romanLower, 'i');
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace ByJoby\HTML\Tags;
|
||||
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use ByJoby\HTML\Nodes\Text;
|
||||
use ByJoby\HTML\Nodes\UnsanitizedText;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -47,10 +48,10 @@ class AbstractContainerTagTest extends TestCase
|
|||
public function testBooleanAttributes(): void
|
||||
{
|
||||
$tag = $this->tag('div');
|
||||
$tag->attributes()['a'] = true;
|
||||
$tag->attributes()['b'] = false;
|
||||
$tag->attributes()['c'] = null;
|
||||
$this->assertEquals('<div a></div>', $tag->__toString());
|
||||
$tag->attributes()['a'] = BooleanAttribute::true;
|
||||
$tag->attributes()['b'] = BooleanAttribute::false;
|
||||
$tag->attributes()['c'] = "";
|
||||
$this->assertEquals('<div a c=""></div>', $tag->__toString());
|
||||
}
|
||||
|
||||
/** @depends clone testDIV */
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace ByJoby\HTML\Tags;
|
|||
|
||||
use ByJoby\HTML\Helpers\Attributes;
|
||||
use ByJoby\HTML\Helpers\Classes;
|
||||
use ByJoby\HTML\Html5\Enums\BooleanAttribute;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AbstractTagTest extends TestCase
|
||||
|
@ -67,10 +68,10 @@ class AbstractTagTest extends TestCase
|
|||
public function testBooleanAttributes(): void
|
||||
{
|
||||
$tag = $this->tag('br');
|
||||
$tag->attributes()['a'] = true;
|
||||
$tag->attributes()['b'] = false;
|
||||
$tag->attributes()['c'] = null;
|
||||
$this->assertEquals('<br a>', $tag->__toString());
|
||||
$tag->attributes()['a'] = BooleanAttribute::true;
|
||||
$tag->attributes()['b'] = BooleanAttribute::false;
|
||||
$tag->attributes()['c'] = "";
|
||||
$this->assertEquals('<br a c="">', $tag->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,4 +100,4 @@ class AbstractTagTest extends TestCase
|
|||
$this->expectExceptionMessage('Setting attribute is disallowed');
|
||||
$tag->attributes()['style'] = 'foo';
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue