Make an HTML tag with a specific tag name (div, p, section etc)

@param string $tag
@param mixed $props
@param mixed $content

@throws \InvalidArgumentException
@return Tag
425802
public function make($tag, $props = null, $content = null)
    {
        if (! isset($this->tagFactories[$tag])) {
            return Tag::create($tag, $props, $content, $this);
        }

        $constructor = $this->tagFactories[$tag];

        if (is_callable($constructor)) {
            /* @var $tag Tag */
            $tag = call_user_func($constructor, $props, $content, $this);
        } elseif (is_string($constructor) && class_exists($constructor)) {
            /* @var $tag Tag */
            $tag = new $constructor($props, $content, $this);
        }

        if (! $tag || ! $tag instanceof Tag) {
            throw  new \InvalidArgumentException(sprintf(
                'The constructor for the `%s` tag did not generate a Tag object',
                $tag
            ));
        }

        return $tag;

    }
186039
function compileSelfClosingTag(tag, props) {
    const compiledProps = compileProps(props);

    return contains(tag, ['br', 'hr', 'img'])
        ? `<${tag}${compiledProps} />`
        : `<${tag}${compiledProps}></${tag}>`;
}
629218
protected function _renderTag($attribs = array(), $content = null, TemplateInterface $template)
    {
        $result = '';
        $link   = isset($attribs['src']) ? $attribs['src'] : false;

        if($link)
        {
            $url        = $this->getObject('lib:http.url', array('url' => $link));
            $identifier = $this->getIdentifier($url->toString(HttpUrl::BASE));

            //Include the component
            $result = $this->getObject('com:'.$identifier->package.'.dispatcher.fragment')
                ->include($url);

            if($this->getObject('template.engine.factory')->isDebug())
            {
                $format  = PHP_EOL.'<!--BEGIN ktml:include '.$url.' -->'.PHP_EOL;
                $format .= '%s';
                $format .= PHP_EOL.'<!--END ktml:include '.$url.' -->'.PHP_EOL;

                $result = sprintf($format, trim($result));
            }
        }

        return $result;
    }
972816
public static function th(
        string $content = null, 
        array $attributes = []
    ) : string 
    {
        return self::tag("th", $content, $attributes);
    }
987677
public static function create(string $tag, string $content = null, array $attributes = null,
        bool $selfClosing = false, bool $v5 = true): string
    {
        if ($attributes != null) {
            $tmp = [];
            foreach ($attributes as $name => $value) {
                if ($value === null) { // eg: ['a' => 1, 'b' => null, ...]
                    $tmp[] = $name;
                } elseif (is_int($name)) { // eg: ['a' => 1, 'b', ...]
                    $tmp[] = $value;
                } else { // eg: ['a' => 1, 'b' => 2, ...]
                    $tmp[] = sprintf('%s="%s"', $name, strtr((string) $value, ['"' => '&quot;']));
                }
            }
            $attributes = ' '. join(' ', $tmp);
        }

        return $selfClosing || in_array($tag, self::$selfClosingTags)
            ? sprintf('<%s%s%s>', $tag, $attributes, $v5 ? '' : ' /')
            : sprintf('<%s%s>%s</%s>', $tag, $attributes, $content, $tag);
    }
86354
public function content($content)
    {
        if ($content instanceof Renderable) {
            $this->content = $content->render();
        } else {
            $this->content = (string) $content;
        }

        return $this;
    }
174482
public function process($content, array $options = [])
    {
        $tagNames = array_keys($this->tags);
        $tagNames[] = 'component';
        if (is_string($content)) {
            $found = false;
            foreach ($tagNames as $tagName) {
                if (strpos($content, '<' . $tagName) !== false) {
                    $found = true;
                    break;
                }
            }
            if (!$found) {
                return $content;
            }
        } elseif (!($content instanceof \IvoPetkov\HTMLServerComponent)) {
            throw new \InvalidArgumentException('');
        }

        $getComponentFileContent = static function($file, $component, $variables) {
            if (is_file($file)) {
                $__componentFile = $file;
                unset($file);
                if (!empty($variables)) {
                    extract($variables, EXTR_SKIP);
                }
                unset($variables);
                ob_start();
                include $__componentFile;
                $content = ob_get_clean();
                return $content;
            } else {
                throw new \Exception('Component file cannot be found (' . $file . ')');
            }
        };

        $getComponentResultHTML = function($component) use (&$getComponentFileContent, $options) {
            $srcAttributeValue = $component->getAttribute('src');
            if ($srcAttributeValue === null) {
                if (isset($this->tags[$component->tagName])) {
                    $srcAttributeValue = $this->tags[$component->tagName];
                } else {
                    throw new \Exception('Component tag name is not defined at ' . (string) $component . '!');
                }
            }
            if ($srcAttributeValue !== null) {
                // todo check alias of alias
                if (isset($this->aliases[$srcAttributeValue])) {
                    $sourceParts = explode(':', $this->aliases[$srcAttributeValue], 2);
                } else {
                    $sourceParts = explode(':', $srcAttributeValue, 2);
                }
                if (isset($sourceParts[0], $sourceParts[1])) {
                    $scheme = $sourceParts[0];
                    if ($scheme === 'data') {
                        if (substr($sourceParts[1], 0, 7) === 'base64,') {
                            return base64_decode(substr($sourceParts[1], 7)); //$this->process(, isset($componentOptions) ? $componentOptions : $options);
                        }
                        throw new \Exception('Components data URI scheme only supports base64 (data:base64,ABCD...)!');
                    } elseif ($scheme === 'file') {
                        return $getComponentFileContent(urldecode($sourceParts[1]), $component, isset($options['variables']) && is_array($options['variables']) ? $options['variables'] : []); //$this->process(isset($componentOptions) ? $componentOptions : $options);
                    }
                    throw new \Exception('Components URI scheme not valid! It must be \'file:\', \'data:\' or an alias.');
                }
                throw new \Exception('Components URI scheme or alias not found at ' . (string) $component . '!');
            }
            throw new \Exception('Component src attribute is missing at ' . (string) $component . '!');
        };

        $disableLevelProcessing = false;
        $domDocument = new HTML5DOMDocument();
        if ($content instanceof \IvoPetkov\HTMLServerComponent) {
            $domDocument->loadHTML($getComponentResultHTML($content), HTML5DOMDocument::ALLOW_DUPLICATE_IDS);
            if (isset($options['recursive']) && $options['recursive'] === false) {
                $disableLevelProcessing = true;
            }
        } else {
            $domDocument->loadHTML($content, HTML5DOMDocument::ALLOW_DUPLICATE_IDS);
        }
        if (!$disableLevelProcessing) {
            $tagsQuerySelector = implode(',', $tagNames);
            for ($level = 0; $level < 1000; $level++) {
                $componentElements = $domDocument->querySelectorAll($tagsQuerySelector);
                if ($componentElements->length === 0) {
                    break;
                }
                $insertHTMLSources = [];
                $list = []; // Save the elements into an array because removeChild() messes up the NodeList
                foreach ($componentElements as $componentElement) {
                    $isInOtherComponentTag = false;
                    $parentNode = $componentElement->parentNode;
                    while ($parentNode !== null && isset($parentNode->tagName)) {
                        if (array_search($parentNode->tagName, $tagNames) !== false) {
                            $isInOtherComponentTag = true;
                            break;
                        }
                        $parentNode = $parentNode->parentNode;
                    }
                    if (!$isInOtherComponentTag) {
                        $list[] = $componentElement;
                    }
                }
                foreach ($list as $i => $componentElement) {
                    $component = $this->makeComponent($componentElement->getAttributes(), $componentElement->innerHTML, $componentElement->tagName);
                    $componentResultHTML = $getComponentResultHTML($component);
                    $isInBodyTag = false;
                    $parentNode = $componentElement->parentNode;
                    while ($parentNode !== null && isset($parentNode->tagName)) {
                        if ($parentNode->tagName === 'body') {
                            $isInBodyTag = true;
                            break;
                        }
                        $parentNode = $parentNode->parentNode;
                    }
                    if ($isInBodyTag) {
                        $insertTargetName = 'html-server-components-compiler-insert-target-' . $i;
                        $componentElement->parentNode->insertBefore($domDocument->createInsertTarget($insertTargetName), $componentElement);
                        $componentElement->parentNode->removeChild($componentElement); // must be before insertHTML because a duplicate elements IDs can occur.
                        $insertHTMLSources[] = ['source' => $componentResultHTML, 'target' => $insertTargetName];
                    } else {
                        $componentElement->parentNode->removeChild($componentElement);
                        $insertHTMLSources[] = ['source' => $componentResultHTML];
                    }
                }
                $domDocument->insertHTMLMulti($insertHTMLSources);
                if (isset($options['recursive']) && $options['recursive'] === false) {
                    break;
                }
            }
        }

        $domDocument->modify(
                HTML5DOMDocument::FIX_MULTIPLE_TITLES |
                HTML5DOMDocument::FIX_DUPLICATE_METATAGS |
                HTML5DOMDocument::FIX_MULTIPLE_HEADS |
                HTML5DOMDocument::FIX_MULTIPLE_BODIES |
                HTML5DOMDocument::OPTIMIZE_HEAD
        );
        return $domDocument->saveHTML();
    }
893704
public static function create( $name, $content = NULL, $attributes = array(), $data = array() )
	{
		if( !strlen( $name	= trim( $name ) ) )
			throw new InvalidArgumentException( 'Missing tag name' );
		$name		= strtolower( $name );
		try{
			$attributes	= self::renderAttributes( $attributes );
			$data		= self::renderData( $data );
		}
		catch( InvalidArgumentException $e ) {
			if( version_compare( PHP_VERSION, '5.3.0', '>=' ) )
				throw new RuntimeException( 'Invalid attributes', NULL, $e );						//  throw exception and transport inner exception
			throw new RuntimeException( 'Invalid attributes', NULL );								//  throw exception
		}
		if( $content === NULL || $content === FALSE )												//  no node content defined, not even an empty string
			if( !in_array( $name, self::$shortTagExcludes ) )										//  node name is allowed to be a short tag
				return "<".$name.$attributes.$data."/>";											//  build and return short tag
		if( is_array( $content ) )																	//  content is an array, may be nested
			$content	= self::flattenArray( $content, '' );
		if( is_numeric( $content ) )
			$content	= (string) $content;
		if( is_object( $content ) ){
			if( !method_exists( $content, '__toString' ) ){											//  content is not a renderable object
				$message	= 'Object of class "'.get_class( $content ).'" cannot be rendered';		//  prepare message about not renderable object
				throw new InvalidArgumentException( $message ); 									//  break with error message
			}
			$content	= (string) $content;														//  render object to string
		}
		if( !is_null( $content ) && !is_string( $content ) ){										//  content is neither NULL nor string so far
			$message	= 'Content type "'.gettype( $content ).'" is not supported';				//  prepare message about wrong content data type
			throw new InvalidArgumentException( $message ); 										//  break with error message
		}
		return "<".$name.$attributes.$data.">".$content."</".$name.">";								//  build and return full tag
	}
789142
public function tag($tag, $content, array $attributes = [])
    {
        return $this->htmlBuilder->tag($tag, $content, $attributes);
    }
438962
public static function script(
        string $content, 
        array $attributes = ["type" => "text/javascript"],
        bool $addCdataTag = true
    ) : string
    {
        if ($addCdataTag) {
            $content = "\n//<![CDATA[\n" . $content ."\n//]]>\n";
        }
        return self::tag("script", $content, $attributes);
    }
575937
public static function span(
        string $content = null, 
        array $attributes = []
    ) : string 
    {
        return self::tag("span", $content, $attributes);
    }
12468
protected function _renderTag($attribs = array(), $content = null)
    {
        if($this->getTemplate()->decorator() == 'joomla')
        {
            $meta = parent::_renderTag($attribs, $content);
            JFactory::getDocument()->addCustomTag($meta);
        }
        else return parent::_renderTag($attribs, $content);
    }
130880
public static String tagHtmlContent(String tag, String... content) {
		return openTagHtmlContent(tag, null, null, content) + closeTag(tag);
	}
103183
public function createTag($tag, $attr = NULL, $content = NULL)
    {
        $temp = '<'.$tag;
        if($attr != NULL) {
            $attr = (array) $attr;
            foreach($attr as $key => $val) {
                if(is_numeric($key)) {
                    $val = strtolower(trim($val));
                    if(isset($this->attr[$tag][$val])) {
                        $args[$val] = $this->attr[$tag][$val];
                        //$args[] = $val.($this->attr[$tag][$val] == NULL ? '' : "=\"{$this->attr[$tag][$val]}\"");
                    }
                    else {
                        $args[$val] = NULL;
                    }
                }
                else {
                    if(!isset($args[$key])) {
                        $args[$key] = $val;
                    }
                }
                if(isset($this->attr[$tag][$key])) {
                    if(is_array($this->attr[$tag][$key])) {
                        foreach($this->attr[$tag][$key] as $k => $v) {
                            if(isset($v[$val]) && !isset($args[$val])) {
                                $args[$k] = $v[$val];
                            }
                        }
                    }
                    else {
                        if(!isset($args[$val])) {
                            $args[$key] = $this->attr[$tag][$key];
                        }
                    }
                }
            }
            unset($attr);
            foreach($args as $key => $val) {
                $attr[] = $key.($val == NULL ? '' : "=\"$val\"");
            }
            unset($args);
            $args = array_unique($attr);
            $args = implode(' ', $args);
        }
        $temp .= isset($args) ? ' '.$args.'>' : '>'; 
        if($content != NULL) {
            if(is_array($content)) {
                array_walk($content, function(&$val, $key) { $val = trim($val); } );//5.3
                $content = implode("\n",$content);
                $content = explode("\n", $content);
                $content = preg_replace('/^/', "\t", $content);
                #$content = preg_filter('/^/', "@", $content);
                $content = rtrim("\n".implode("\n", $content), "\n")."\n";
            }
            $temp .= $content;
        }
        if($this->tags[$tag] === true) {
            $temp .= '</'.$tag.'>';
        }
        return $temp;
    }
1338835
static function tagSubsections( $content, $id ) {
		$parent = get_post( $id );
		if ( empty( $parent ) ) {
			return false;
		}
		if ( stripos( $content, '<h1' ) === false ) {
			return false;
		}

		$type = $parent->post_type;
		$s = 1;

		$doc = new HtmlParser();
		$dom = $doc->loadHTML( $content );
		$sections = $dom->getElementsByTagName( 'h1' );
		foreach ( $sections as $section ) {
			/** @var $section \DOMElement */
			$old_id = $section->getAttribute( 'id' );
			$old_class = $section->getAttribute( 'class' );
			$new_id = "{$type}-{$id}-section-" . $s++;
			$new_class = trim( "section-header {$old_class} {$old_id}" );
			$section->setAttribute( 'id', $new_id );
			$section->setAttribute( 'class', $new_class );
		}

		return $doc->saveHTML( $dom );
	}
809475
public static function stripTagsAndAtts($content, $allowedTags = '', $allowedAtts = '')
    {
        if (isset($allowedTags) && is_array($allowedTags)) {
            $content = strip_tags($content, implode($allowedTags));
        } else {
            $content = strip_tags($content);
        }

        //Strip attributes
        $atts = \Municipio\Helper\Html::getHtmlAttributes($content);

        if ($atts && !empty($atts)) {
            if (isset($allowedAtts) && is_array($allowedAtts)) {
                foreach ($allowedAtts as $attribute) {
                    unset($atts[$attribute]);
                }
            }

            foreach ($atts as $att) {
                $content = str_replace($att, "", $content);
            }
        }

        return $content;
    }
669724
public static function getHtmlTags($content, $closeTags = true)
    {
        if ($closeTags == true) {
            $re = '@<[^>]*>@';
        } else {
            $re = '@<[^>/]*>@';
        }

        preg_match_all($re, $content, $matches, PREG_SET_ORDER, 0);

        if (isset($matches) && !empty($matches)) {
            $tags = array();
            foreach ($matches as $match) {
                $tags[] = $match[0];
            }

            $tags = array_unique($tags);

            return $tags;
        }

        return;
    }