diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:38:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:38:04 +0000 |
commit | 1ff5c35de5dbd70a782875a91dd2232fd01b002b (patch) | |
tree | 77d9ce5e1bf78b3e6ef79f8f6e7861e2ced3c09b /vendor/ipl/html/src/BaseHtmlElement.php | |
parent | Initial commit. (diff) | |
download | icinga-php-library-1ff5c35de5dbd70a782875a91dd2232fd01b002b.tar.xz icinga-php-library-1ff5c35de5dbd70a782875a91dd2232fd01b002b.zip |
Adding upstream version 0.10.1.upstream/0.10.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ipl/html/src/BaseHtmlElement.php')
-rw-r--r-- | vendor/ipl/html/src/BaseHtmlElement.php | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/vendor/ipl/html/src/BaseHtmlElement.php b/vendor/ipl/html/src/BaseHtmlElement.php new file mode 100644 index 0000000..da8348d --- /dev/null +++ b/vendor/ipl/html/src/BaseHtmlElement.php @@ -0,0 +1,355 @@ +<?php + +namespace ipl\Html; + +use RuntimeException; + +/** + * Base class for HTML elements + * + * Extend this class in order to provide concrete HTML elements or series of HTML elements, e.g. widgets. + * When extending this class you should provide the element's tag with {@link $tag}. Setting default attributes is + * possible via {@link $defaultAttributes}. And the content of the element is provided in {@link assemble()}. + * + * # Example Usage + * ``` + * namespace Acme\Widgets; + * + * use ipl\Html\BaseHtmlElement; + * + * class Dashboard extends BaseHtmlElement + * { + * protected $defaultAttributes = ['class' => 'acme-dashboard']; + * + * protected $tag = 'div'; + * + * protected function assemble() + * { + * // ... + * $this->add($content); + * } + * } + * ``` + */ +abstract class BaseHtmlElement extends HtmlDocument +{ + /** + * List of void elements which must not contain end tags or content + * + * If {@link $isVoid} is null, this property should be used to decide whether the content and end tag has to be + * rendered. + * + * @var array + * + * @see https://www.w3.org/TR/html5/syntax.html#void-elements + */ + protected static $voidElements = [ + 'area' => 1, + 'base' => 1, + 'br' => 1, + 'col' => 1, + 'embed' => 1, + 'hr' => 1, + 'img' => 1, + 'input' => 1, + 'link' => 1, + 'meta' => 1, + 'param' => 1, + 'source' => 1, + 'track' => 1, + 'wbr' => 1 + ]; + + /** @var Attributes */ + protected $attributes; + + /** @var bool Whether possible attribute callbacks have been registered */ + protected $attributeCallbacksRegistered = false; + + /** @var bool|null Whether the element is void. If null, void check should use {@link $voidElements} */ + protected $isVoid; + + /** @var array You may want to set default attributes when extending this class */ + protected $defaultAttributes; + + /** @var string Tag of element. Set this property in order to provide the element's tag when extending this class */ + protected $tag; + + /** + * Get the attributes of the element + * + * @return Attributes + */ + public function getAttributes() + { + if ($this->attributes === null) { + $default = $this->getDefaultAttributes(); + if (empty($default)) { + $this->attributes = new Attributes(); + } else { + $this->attributes = Attributes::wantAttributes($default); + } + + $this->ensureAttributeCallbacksRegistered(); + } + + return $this->attributes; + } + + /** + * Set the attributes of the element + * + * @param Attributes|array|null $attributes + * + * @return $this + */ + public function setAttributes($attributes) + { + $this->attributes = Attributes::wantAttributes($attributes); + + $this->attributeCallbacksRegistered = false; + $this->ensureAttributeCallbacksRegistered(); + + return $this; + } + + /** + * Set the attribute with the given name and value + * + * If the attribute with the given name already exists, it gets overridden. + * + * @param string $name The name of the attribute + * @param string|bool|array $value The value of the attribute + * + * @return $this + */ + public function setAttribute($name, $value) + { + $this->getAttributes()->set($name, $value); + + return $this; + } + + /** + * Add the given attributes + * + * @param Attributes|array $attributes + * + * @return $this + */ + public function addAttributes($attributes) + { + $this->getAttributes()->add($attributes); + + return $this; + } + + /** + * Get the default attributes of the element + * + * @return array + */ + public function getDefaultAttributes() + { + return $this->defaultAttributes; + } + + /** + * Get the tag of the element + * + * Since HTML Elements must have a tag, this method throws an exception if the element does not have a tag. + * + * @return string + * + * @throws RuntimeException If the element does not have a tag + */ + final public function getTag() + { + $tag = $this->tag(); + + if (! $tag) { + throw new RuntimeException('Element must have a tag'); + } + + return $tag; + } + + /** + * Set the tag of the element + * + * @param string $tag + * + * @return $this + */ + public function setTag($tag) + { + $this->tag = $tag; + + return $this; + } + + /** + * Get whether the element is void + * + * The default void detection which checks whether the element's tag is in the list of void elements according to + * https://www.w3.org/TR/html5/syntax.html#void-elements. + * + * If you want to override this behavior, use {@link setVoid()}. + * + * @return bool + */ + public function isVoid() + { + if ($this->isVoid !== null) { + return $this->isVoid; + } + + $tag = $this->getTag(); + + return isset(self::$voidElements[$tag]); + } + + /** + * Set whether the element is void + * + * You may use this method to override the default void detection which checks whether the element's tag is in the + * list of void elements according to https://www.w3.org/TR/html5/syntax.html#void-elements. + * + * If you specify null, void detection is reset to its default behavior. + * + * @param bool|null $void + * + * @return $this + */ + public function setVoid($void = true) + { + $this->isVoid = $void === null ?: (bool) $void; + + return $this; + } + + /** + * Ensure that possible attribute callbacks have been registered + * + * Note that this method is automatically called in {@link getAttributes()} and {@link setAttributes()}. + * + * @return $this + */ + public function ensureAttributeCallbacksRegistered() + { + if (! $this->attributeCallbacksRegistered) { + $this->attributeCallbacksRegistered = true; + $this->registerAttributeCallbacks($this->attributes); + } + + return $this; + } + + /** + * Render the content of the element to HTML + * + * @return string + */ + public function renderContent() + { + return parent::renderUnwrapped(); + } + + /** + * Get whether the closing tag should be rendered + * + * @return bool True for void elements, false otherwise + */ + public function wantsClosingTag() + { + // TODO: There is more. SVG and MathML namespaces + return ! $this->isVoid(); + } + + /** + * Use this element to wrap the given document + * + * @param HtmlDocument $document + * + * @return $this + */ + public function wrap(HtmlDocument $document) + { + $document->addWrapper($this); + + return $this; + } + + /** + * Internal method for accessing the tag + * + * You may override this method in order to provide the tag dynamically + * + * @return string + */ + protected function tag() + { + return $this->tag; + } + + /** + * Register attribute callbacks + * + * Override this method in order to register attribute callbacks in concrete classes. + */ + protected function registerAttributeCallbacks(Attributes $attributes) + { + } + + public function addHtml(ValidHtml ...$content) + { + $this->ensureAssembled(); + + parent::addHtml(...$content); + + return $this; + } + + /** + * @inheritdoc + * + * @throws RuntimeException If the element does not have a tag or is void but has content + */ + public function renderUnwrapped() + { + $this->ensureAssembled(); + + $tag = $this->getTag(); + $content = $this->renderContent(); + $attributes = $this->getAttributes()->render(); + + if (strlen($this->contentSeparator)) { + $length = strlen($content); + if ($length > 0) { + if ($content[0] === '<') { + $content = $this->contentSeparator . $content; + $length++; + } + if ($content[$length - 1] === '>') { + $content .= $this->contentSeparator; + } + } + } + + if (! $this->wantsClosingTag()) { + if (strlen($content)) { + throw new RuntimeException('Void elements must not have content'); + } + + return sprintf('<%s%s />', $tag, $attributes); + } + + return sprintf( + '<%s%s>%s</%s>', + $tag, + $attributes, + $content, + $tag + ); + } +} |