From 1920ad571e13e381615386255c935a25332ac280 Mon Sep 17 00:00:00 2001 From: Joby Elliott Date: Thu, 1 Dec 2022 16:35:47 -0700 Subject: [PATCH] finished root and document metadata tags --- src/Html5/Tags/LinkTag.php | 187 ++++++++++++++++++++++++++ src/Html5/Tags/MetaTag.php | 68 ++++++++++ src/Html5/Tags/StyleTag.php | 39 +++++- src/Tags/AbstractContainerTag.php | 20 ++- src/Tags/AbstractContentTag.php | 38 ++++++ src/Tags/ContainerTagInterface.php | 9 +- src/Tags/ContentTagInterface.php | 18 +++ src/Tags/TagInterface.php | 6 + src/Traits/ContainerMutableTrait.php | 1 - src/Traits/ContainerTagTrait.php | 23 ---- src/Traits/TagTrait.php | 3 - tests/Html5/Tags/LinkTagTest.php | 21 +++ tests/Html5/Tags/MetaTagTest.php | 14 ++ tests/Html5/Tags/StyleTagTest.php | 12 ++ tests/Html5/Tags/TagTestCase.php | 7 +- tests/Tags/AbstractContentTagTest.php | 26 ++++ 16 files changed, 451 insertions(+), 41 deletions(-) create mode 100644 src/Tags/AbstractContentTag.php create mode 100644 src/Tags/ContentTagInterface.php delete mode 100644 src/Traits/ContainerTagTrait.php create mode 100644 tests/Html5/Tags/LinkTagTest.php create mode 100644 tests/Html5/Tags/MetaTagTest.php create mode 100644 tests/Html5/Tags/StyleTagTest.php create mode 100644 tests/Tags/AbstractContentTagTest.php diff --git a/src/Html5/Tags/LinkTag.php b/src/Html5/Tags/LinkTag.php index 8107a69..a14ee59 100644 --- a/src/Html5/Tags/LinkTag.php +++ b/src/Html5/Tags/LinkTag.php @@ -7,4 +7,191 @@ use ByJoby\HTML\Tags\AbstractTag; class LinkTag extends AbstractTag { const TAG = 'link'; + + public function rel(): null|string + { + return $this->attributes()['rel']; + } + + public function setRel(null|string $rel): static + { + $this->attributes()['rel'] = $rel; + return $this; + } + + public function unsetRel(): static + { + unset($this->attributes()['rel']); + return $this; + } + + public function as(): null|string + { + return $this->attributes()['as']; + } + + public function setAs(null|string $as): static + { + $this->attributes()['as'] = $as; + return $this; + } + + public function unsetAs(): static + { + unset($this->attributes()['as']); + return $this; + } + + public function crossorigin(): null|string + { + return $this->attributes()['crossorigin']; + } + + public function setCrossorigin(null|string $crossorigin): static + { + $this->attributes()['crossorigin'] = $crossorigin; + return $this; + } + + public function unsetCrossorigin(): static + { + unset($this->attributes()['crossorigin']); + return $this; + } + + public function href(): null|string + { + return $this->attributes()['href']; + } + + public function setHref(null|string $href): static + { + $this->attributes()['href'] = $href; + return $this; + } + + public function unsetHref(): static + { + unset($this->attributes()['href']); + return $this; + } + + public function hreflang(): null|string + { + return $this->attributes()['hreflang']; + } + + public function setHreflang(null|string $hreflang): static + { + $this->attributes()['hreflang'] = $hreflang; + return $this; + } + + public function unsetHreflang(): static + { + unset($this->attributes()['hreflang']); + return $this; + } + + public function imagesizes(): null|string + { + return $this->attributes()['imagesizes']; + } + + public function setImagesizes(null|string $imagesizes): static + { + $this->attributes()['imagesizes'] = $imagesizes; + return $this; + } + + public function unsetImagesizes(): static + { + unset($this->attributes()['imagesizes']); + return $this; + } + + public function imagesrcset(): null|string + { + return $this->attributes()['imagesrcset']; + } + + public function setImagesrcset(null|string $imagesrcset): static + { + $this->attributes()['imagesrcset'] = $imagesrcset; + return $this; + } + + public function unsetImagesrcset(): static + { + unset($this->attributes()['imagesrcset']); + return $this; + } + + public function integrity(): null|string + { + return $this->attributes()['integrity']; + } + + public function setIntegrity(null|string $integrity): static + { + $this->attributes()['integrity'] = $integrity; + return $this; + } + + public function unsetIntegrity(): static + { + unset($this->attributes()['integrity']); + return $this; + } + + public function media(): null|string + { + return $this->attributes()['media']; + } + + public function setMedia(null|string $media): static + { + $this->attributes()['media'] = $media; + return $this; + } + + public function unsetMedia(): static + { + unset($this->attributes()['media']); + return $this; + } + + public function referrerpolicy(): null|string + { + return $this->attributes()['referrerpolicy']; + } + + public function setReferrerpolicy(null|string $referrerpolicy): static + { + $this->attributes()['referrerpolicy'] = $referrerpolicy; + return $this; + } + + public function unsetReferrerpolicy(): static + { + unset($this->attributes()['referrerpolicy']); + return $this; + } + + public function type(): null|string + { + return $this->attributes()['type']; + } + + public function setType(null|string $type): static + { + $this->attributes()['type'] = $type; + return $this; + } + + public function unsetType(): static + { + unset($this->attributes()['type']); + return $this; + } } diff --git a/src/Html5/Tags/MetaTag.php b/src/Html5/Tags/MetaTag.php index 6378a19..fb7e438 100644 --- a/src/Html5/Tags/MetaTag.php +++ b/src/Html5/Tags/MetaTag.php @@ -7,4 +7,72 @@ use ByJoby\HTML\Tags\AbstractTag; class MetaTag extends AbstractTag { const TAG = 'meta'; + + public function name(): null|string + { + return $this->attributes()['name']; + } + + public function setName(null|string $name): static + { + $this->attributes()['name'] = $name; + return $this; + } + + public function unsetName(): static + { + unset($this->attributes()['name']); + return $this; + } + + public function content(): null|string + { + return $this->attributes()['content']; + } + + public function setContent(null|string $content): static + { + $this->attributes()['content'] = $content; + return $this; + } + + public function unsetContent(): static + { + unset($this->attributes()['content']); + return $this; + } + + public function httpEquiv(): null|string + { + return $this->attributes()['http-equiv']; + } + + public function setHttpEquiv(null|string $http_equiv): static + { + $this->attributes()['http-equiv'] = $http_equiv; + return $this; + } + + public function unsetHttpEquiv(): static + { + unset($this->attributes()['http-equiv']); + return $this; + } + + public function charset(): null|string + { + return $this->attributes()['charset']; + } + + public function setCharset(null|string $charset): static + { + $this->attributes()['charset'] = $charset; + return $this; + } + + public function unsetCharset(): static + { + unset($this->attributes()['charset']); + return $this; + } } diff --git a/src/Html5/Tags/StyleTag.php b/src/Html5/Tags/StyleTag.php index 285a521..c79f801 100644 --- a/src/Html5/Tags/StyleTag.php +++ b/src/Html5/Tags/StyleTag.php @@ -2,10 +2,43 @@ namespace ByJoby\HTML\Html5\Tags; -use ByJoby\HTML\Tags\AbstractTag; +use ByJoby\HTML\Tags\AbstractContentTag; -// TODO: implement some sort of AbstractContentTag to hold non-HTML content like styles (maybe also make the TitleTag use this) -class StyleTag extends AbstractTag +class StyleTag extends AbstractContentTag { const TAG = 'style'; + + public function media(): null|string + { + return $this->attributes()['media']; + } + + public function setMedia(null|string $media): static + { + $this->attributes()['media'] = $media; + return $this; + } + + public function unsetMedia(): static + { + unset($this->attributes()['media']); + return $this; + } + + public function nonce(): null|string + { + return $this->attributes()['nonce']; + } + + public function setNonce(null|string $nonce): static + { + $this->attributes()['nonce'] = $nonce; + return $this; + } + + public function unsetNonce(): static + { + unset($this->attributes()['nonce']); + return $this; + } } diff --git a/src/Tags/AbstractContainerTag.php b/src/Tags/AbstractContainerTag.php index f3a5ab2..baf60f1 100644 --- a/src/Tags/AbstractContainerTag.php +++ b/src/Tags/AbstractContainerTag.php @@ -3,21 +3,27 @@ namespace ByJoby\HTML\Tags; use ByJoby\HTML\Traits\ContainerMutableTrait; -use ByJoby\HTML\Traits\ContainerTagTrait; use ByJoby\HTML\Traits\ContainerTrait; use ByJoby\HTML\Traits\TagTrait; use ByJoby\HTML\Traits\NodeTrait; -abstract class AbstractContainerTag implements ContainerTagInterface +abstract class AbstractContainerTag extends AbstractTag implements ContainerTagInterface { use NodeTrait, TagTrait; use ContainerTrait, ContainerMutableTrait; - use ContainerTagTrait { - ContainerTagTrait::__toString insteadof TagTrait; - } - public function tag(): string + public function __toString(): string { - return static::TAG; //@phpstan-ignore-line + $openingTag = sprintf('<%s>', implode(' ', $this->openingTagStrings())); + $closingTag = sprintf('', $this->tag()); + if (!$this->children()) return $openingTag . $closingTag; + else return implode( + PHP_EOL, + [ + $openingTag, + implode(PHP_EOL, $this->children()), + $closingTag + ] + ); } } diff --git a/src/Tags/AbstractContentTag.php b/src/Tags/AbstractContentTag.php new file mode 100644 index 0000000..93d33c5 --- /dev/null +++ b/src/Tags/AbstractContentTag.php @@ -0,0 +1,38 @@ +content, "\t\n\r\0x0B"); + } + + public function setContent(string|Stringable $content): static + { + $this->content = $content; + return $this; + } + + public function __toString(): string + { + $openingTag = sprintf('<%s>', implode(' ', $this->openingTagStrings())); + $closingTag = sprintf('', $this->tag()); + $content = $this->content(); + if (!$content) return $openingTag . $closingTag; + else return implode( + PHP_EOL, + [ + $openingTag, + $content, + $closingTag + ] + ); + } +} diff --git a/src/Tags/ContainerTagInterface.php b/src/Tags/ContainerTagInterface.php index 401567a..163998c 100644 --- a/src/Tags/ContainerTagInterface.php +++ b/src/Tags/ContainerTagInterface.php @@ -3,8 +3,15 @@ namespace ByJoby\HTML\Tags; use ByJoby\HTML\ContainerMutableInterface; -use ByJoby\HTML\NodeCollectionInterface; +/** + * Container Tags are HTML tags that are capable of holding a collection of + * child tags. They can all have tags added and removed from them as well. + * Container Tags always render as a full opening and closing tag, even when + * they are empty. + * + * @package ByJoby\HTML\Tags + */ interface ContainerTagInterface extends TagInterface, ContainerMutableInterface { } diff --git a/src/Tags/ContentTagInterface.php b/src/Tags/ContentTagInterface.php new file mode 100644 index 0000000..9347f3a --- /dev/null +++ b/src/Tags/ContentTagInterface.php @@ -0,0 +1,18 @@ +', implode(' ', $this->openingTagStrings())); - $closingTag = sprintf('', $this->tag()); - if (!$this->children()) return $openingTag . $closingTag; - else return implode( - PHP_EOL, - [ - $openingTag, - implode(PHP_EOL, $this->children()), - $closingTag - ] - ); - } -} diff --git a/src/Traits/TagTrait.php b/src/Traits/TagTrait.php index 0feca72..5ba8e3e 100644 --- a/src/Traits/TagTrait.php +++ b/src/Traits/TagTrait.php @@ -2,12 +2,9 @@ namespace ByJoby\HTML\Traits; -use ArrayIterator; -use ByJoby\HTML\ContainerInterface; use ByJoby\HTML\Helpers\Attributes; use ByJoby\HTML\Helpers\Classes; use ByJoby\HTML\Helpers\Styles; -use ByJoby\HTML\NodeInterface; use Exception; use Stringable; diff --git a/tests/Html5/Tags/LinkTagTest.php b/tests/Html5/Tags/LinkTagTest.php new file mode 100644 index 0000000..899517d --- /dev/null +++ b/tests/Html5/Tags/LinkTagTest.php @@ -0,0 +1,21 @@ +assertAttributeHelperMethods('rel', LinkTag::class); + $this->assertAttributeHelperMethods('as', LinkTag::class); + $this->assertAttributeHelperMethods('crossorigin', LinkTag::class); + $this->assertAttributeHelperMethods('href', LinkTag::class); + $this->assertAttributeHelperMethods('hreflang', LinkTag::class); + $this->assertAttributeHelperMethods('imagesizes', LinkTag::class); + $this->assertAttributeHelperMethods('imagesrcset', LinkTag::class); + $this->assertAttributeHelperMethods('integrity', LinkTag::class); + $this->assertAttributeHelperMethods('media', LinkTag::class); + $this->assertAttributeHelperMethods('referrerpolicy', LinkTag::class); + $this->assertAttributeHelperMethods('type', LinkTag::class); + } +} diff --git a/tests/Html5/Tags/MetaTagTest.php b/tests/Html5/Tags/MetaTagTest.php new file mode 100644 index 0000000..88871cf --- /dev/null +++ b/tests/Html5/Tags/MetaTagTest.php @@ -0,0 +1,14 @@ +assertAttributeHelperMethods('name', MetaTag::class); + $this->assertAttributeHelperMethods('content', MetaTag::class); + $this->assertAttributeHelperMethods('http-equiv', MetaTag::class); + $this->assertAttributeHelperMethods('charset', MetaTag::class); + } +} diff --git a/tests/Html5/Tags/StyleTagTest.php b/tests/Html5/Tags/StyleTagTest.php new file mode 100644 index 0000000..00785ff --- /dev/null +++ b/tests/Html5/Tags/StyleTagTest.php @@ -0,0 +1,12 @@ +assertAttributeHelperMethods('media', StyleTag::class); + $this->assertAttributeHelperMethods('nonce', StyleTag::class); + } +} diff --git a/tests/Html5/Tags/TagTestCase.php b/tests/Html5/Tags/TagTestCase.php index 0a4424c..8365d6e 100644 --- a/tests/Html5/Tags/TagTestCase.php +++ b/tests/Html5/Tags/TagTestCase.php @@ -3,6 +3,7 @@ namespace ByJoby\HTML\Html5\Tags; use ByJoby\HTML\ContainerInterface; +use ByJoby\HTML\Tags\ContentTagInterface; use ByJoby\HTML\Tags\TagInterface; use PHPUnit\Framework\TestCase; @@ -23,13 +24,13 @@ abstract class TagTestCase extends TestCase $this->assertEquals($render_value, call_user_func([$tag, $getFn])); $this->assertEquals($render_value, $tag->attributes()[$attribute]); // test unsetting via unset - call_user_func([$tag,$unsetFn]); - $this->assertNull(call_user_func([$tag,$getFn])); + call_user_func([$tag, $unsetFn]); + $this->assertNull(call_user_func([$tag, $getFn])); } protected function assertTagRendersAttribute(TagInterface $tag, string $attribute, string $value) { - if ($tag instanceof ContainerInterface) { + if ($tag instanceof ContainerInterface || $tag instanceof ContentTagInterface) { $this->assertEquals( sprintf('<%s %s="%s">', $tag->tag(), $attribute, $value, $tag->tag()), $tag->__toString(), diff --git a/tests/Tags/AbstractContentTagTest.php b/tests/Tags/AbstractContentTagTest.php new file mode 100644 index 0000000..80518a0 --- /dev/null +++ b/tests/Tags/AbstractContentTagTest.php @@ -0,0 +1,26 @@ +getMockForAbstractClass(AbstractContentTag::class, [], '', true, true, true, ['tag']); + $tag->method('tag')->willReturn($name); + return $tag; + } + + public function testContent(): void + { + $content = 'this content goes in the tag'; + $tag = $this->tag('div'); + $this->assertEquals('', $tag->content()); + $this->assertEquals('
', $tag->__toString()); + $tag->setContent($content); + $this->assertEquals($content, $tag->content()); + $this->assertEquals('
' . PHP_EOL . $content . PHP_EOL . '
', $tag->__toString()); + } +}