finished text content tags

This commit is contained in:
Joby 2022-12-19 09:50:48 -07:00
parent 67763ada8f
commit abea8a6f68
24 changed files with 335 additions and 8 deletions

View file

@ -2,8 +2,10 @@
namespace ByJoby\HTML\Containers\DocumentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\ContentCategories\SectioningRoot;
use ByJoby\HTML\Tags\ContainerTagInterface;
interface BodyTagInterface extends ContainerTagInterface
interface BodyTagInterface extends ContainerTagInterface, SectioningRoot, FlowContent
{
}

View file

@ -2,8 +2,9 @@
namespace ByJoby\HTML\Containers\DocumentTags;
use ByJoby\HTML\ContentCategories\MetadataContent;
use ByJoby\HTML\Tags\ContentTagInterface;
interface TitleTagInterface extends ContentTagInterface
interface TitleTagInterface extends ContentTagInterface, MetadataContent
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace ByJoby\HTML\ContentCategories;
interface SectioningRoot
{
}

View file

@ -10,6 +10,7 @@ class Html5Parser extends AbstractParser
/** @var array<int,string> */
protected $tag_namespaces = [
'\\ByJoby\\HTML\\Html5\\Tags\\',
'\\ByJoby\\HTML\\Html5\\TextContentTags\\',
'\\ByJoby\\HTML\\Html5\\ContentSectioningTags\\',
'\\ByJoby\\HTML\\Html5\\DocumentTags\\',
];

View file

@ -0,0 +1,31 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\ContentCategories\SectioningRoot;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class BlockquoteTag extends AbstractContainerTag implements FlowContent, SectioningRoot, DisplayBlock
{
const TAG = 'blockquote';
public function cite(): null|string
{
return $this->attributes()->string('cite');
}
public function setCite(null|string $cite): static
{
if (!$cite) $this->attributes()['cite'] = false;
else $this->attributes()['cite'] = $cite;
return $this;
}
public function unsetCite(): static
{
unset($this->attributes()['cite']);
return $this;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Tags\AbstractContainerTag;
class DdTag extends AbstractContainerTag
{
const TAG = 'dd';
}

View file

@ -1,6 +1,6 @@
<?php
namespace ByJoby\HTML\Html5\Tags;
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\SectioningContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;

View file

@ -0,0 +1,12 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class DlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
{
const TAG = 'dl';
}

View file

@ -0,0 +1,10 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Tags\AbstractContainerTag;
class DtTag extends AbstractContainerTag
{
const TAG = 'dt';
}

View file

@ -0,0 +1,12 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class FigcaptionTag extends AbstractContainerTag implements FlowContent, DisplayBlock
{
const TAG = 'figcaption';
}

View file

@ -0,0 +1,36 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Containers\ContainerGroup;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\NodeInterface;
use ByJoby\HTML\Tags\AbstractGroupedTag;
use ByJoby\HTML\Tags\TagInterface;
class FigureTag extends AbstractGroupedTag implements FlowContent, DisplayBlock
{
const TAG = 'figure';
public function __construct()
{
parent::__construct();
// group that accepts anything but a figcaption tag
$this->addGroup(new ContainerGroup(function (NodeInterface $node): bool {
if ($node instanceof TagInterface) {
return $node->tag() != 'figcaption';
} else {
return true;
}
}));
// figcaption tag group
$this->addGroup(ContainerGroup::ofTag('figcaption', 1));
}
public function reverseCaptionOrder(): static
{
$this->children = array_reverse($this->children);
return $this;
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractTag;
class HrTag extends AbstractTag implements FlowContent, DisplayBlock
{
const TAG = 'hr';
}

View file

@ -0,0 +1,12 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class LiTag extends AbstractContainerTag implements FlowContent, DisplayBlock
{
const TAG = 'li';
}

View file

@ -0,0 +1,12 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class MenuTag extends AbstractContainerTag implements FlowContent, DisplayBlock
{
const TAG = 'menu';
}

View file

@ -0,0 +1,74 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\FlowContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class OlTag extends AbstractContainerTag implements FlowContent, DisplayBlock
{
const TAG = 'ol';
const TYPE_LETTER_LOWER = 'a';
const TYPE_LETTER_UPPER = 'A';
const TYPE_ROMAN_LOWER = 'i';
const TYPE_ROMAN_UPPER = 'I';
const TYPE_NUMBER = '1';
public function setReversed(bool $reversed): static
{
$this->attributes()['reversed'] = $reversed;
return $this;
}
public function reversed(): bool
{
return !!$this->attributes()['reversed'];
}
public function start(): null|int
{
if (isset($this->attributes['start'])) {
return intval($this->attributes()->string('start'));
} else {
return null;
}
}
public function setStart(null|int $start): static
{
if (!$start) $this->attributes()['start'] = false;
else $this->attributes()['start'] = strval($start);
return $this;
}
public function unsetStart(): static
{
unset($this->attributes()['start']);
return $this;
}
public function type(): null|string
{
return $this->attributes()->string('type');
}
public function setType(null|string $type): static
{
if (!in_array($type, ['a', 'A', 'i', 'I', '1'])) {
$type = null;
}
if (!$type) {
$this->attributes()['type'] = false;
} else {
$this->attributes()['type'] = $type;
}
return $this;
}
public function unsetType(): static
{
unset($this->attributes()['type']);
return $this;
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace ByJoby\HTML\Html5\Tags;
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\ContentCategories\SectioningContent;
use ByJoby\HTML\DisplayTypes\DisplayBlock;

View file

@ -0,0 +1,11 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class PreTag extends AbstractContainerTag implements DisplayBlock
{
const TAG = 'pre';
}

View file

@ -0,0 +1,11 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\DisplayTypes\DisplayBlock;
use ByJoby\HTML\Tags\AbstractContainerTag;
class UlTag extends AbstractContainerTag implements DisplayBlock
{
const TAG = 'ul';
}

View file

@ -103,11 +103,11 @@ trait ContainerTrait
protected function indexOfChild(NodeInterface|Stringable|string $child): null|int
{
if ($child instanceof NodeInterface) {
foreach ($this->children() as $i => $v) {
foreach ($this->children as $i => $v) {
if ($v === $child) return $i;
}
} else {
foreach ($this->children() as $i => $v) {
foreach ($this->children as $i => $v) {
if ($v == $child) return $i;
}
}

View file

@ -26,7 +26,7 @@ trait GroupedContainerTrait
public function groups(): array
{
return array_filter(
$this->children(),
$this->children,
function (NodeInterface $node) {
return $node instanceof ContainerGroup;
}
@ -102,4 +102,16 @@ trait GroupedContainerTrait
}
return $this;
}
public function children(): array
{
/** @var array<int,NodeInterface> */
$children = [];
foreach ($this->groups() as $group) {
foreach ($group->children() as $child) {
$children[] = $child;
}
}
return $children;
}
}

View file

@ -2,7 +2,7 @@
namespace ByJoby\HTML\Html5;
use ByJoby\HTML\Html5\Tags\DivTag;
use ByJoby\HTML\Html5\TextContentTags\DivTag;
use ByJoby\HTML\Nodes\TextInterface;
use PHPUnit\Framework\TestCase;

View file

@ -0,0 +1,13 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Html5\Tags\BaseTagTest;
class BlockquoteTagTest extends BaseTagTest
{
public function testAttributeHelpers(): void
{
$this->assertAttributeHelperMethods('cite', BlockquoteTag::class);
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Html5\Tags\BaseTagTest;
use ByJoby\HTML\Html5\TextContentTags\FigureTag;
use ByJoby\HTML\Nodes\TextInterface;
class FigureTagTest extends BaseTagTest
{
public function testCaptionOrder()
{
$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();
$this->assertInstanceOf(TextInterface::class, $figure->children()[1]);
$this->assertInstanceOf(FigcaptionTag::class, $figure->children()[0]);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace ByJoby\HTML\Html5\TextContentTags;
use ByJoby\HTML\Html5\Tags\BaseTagTest;
class OlTagTest extends BaseTagTest
{
public function testAttributeHelpers(): void
{
$this->assertBooleanAttributeHelperMethods('reversed', OlTag::class);
$this->assertAttributeHelperMethods('start', OlTag::class, 1, 1);
$this->assertAttributeHelperMethods('type', OlTag::class, 'a', 'a');
$this->assertAttributeHelperMethods('type', OlTag::class, 'A', 'A');
$this->assertAttributeHelperMethods('type', OlTag::class, 'i', 'i');
$this->assertAttributeHelperMethods('type', OlTag::class, 'I', 'I');
$this->assertAttributeHelperMethods('type', OlTag::class, '1', '1');
}
public function testInvalidType(): void
{
$ol = new OlTag;
$ol->setType('X');
$this->assertNull($ol->type());
}
}