* @package zin * @version $Id * @link https://www.zentao.net */ namespace zin; require_once __DIR__ . DS . 'node.class.php'; require_once __DIR__ . DS . 'text.class.php'; require_once __DIR__ . DS . 'directive.class.php'; class h extends node { /** * @var mixed[] */ public static $h5Tags = array('div', 'span', 'strong', 'small', 'code', 'canvas', 'br', 'a', 'p', 'img', 'button', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'li', 'template', 'fieldset', 'legend', 'iframe'); /** * @var mixed[] */ public static $defineProps = array ( 'tagName' => 'string', 'selfClose' => '?bool' ); public function tagName() { $tagName = $this->prop('tagName'); return $tagName === null ? '' : $tagName; } public function fullType() { return 'zin\\' . $this->tagName(); } public function type() { return $this->tagName(); } public function isSelfClose() { $selfClose = $this->prop('selfClose'); if($selfClose !== null) return boolval($selfClose); return in_array($this->tagName(), static::$selfCloseTags); } /** * @param mixed[]|string $prop * @param mixed $value */ protected function onSetProp($prop, $value) { if($prop === 'className') $prop = 'class'; return parent::onSetProp($prop, $value); } /** * @return mixed */ public function build() { if($this->isSelfClose()) return $this->buildSelfCloseTag(); $content = array($this->buildTagBegin()); $build = parent::build(); if(is_array($build)) $content = array_merge($content, $build); else $content[] = $build; $content[] = $this->buildTagEnd(); return $content; } protected function getPropsStr() { $propStr = $this->props->toStr(array_keys(static::definedPropsList())); if($this->props->hasEvent() && empty($this->id()) && $this->tagName() !== 'html') $propStr = "$propStr id='$this->gid'"; return empty($propStr) ? '' : " $propStr"; } protected function buildSelfCloseTag() { $tagName = $this->tagName(); $propStr = $this->getPropsStr(); return "<$tagName$propStr />"; } protected function buildTagBegin() { $tagName = $this->tagName(); $propStr = $this->getPropsStr(); return "<$tagName$propStr>"; } protected function buildTagEnd() { $tagName = $this->tagName(); return ""; } /** * @param mixed ...$args * @param string $tagName */ public static function create($tagName, ...$args) { $h = new h(...$args); $h->setProp('tagName', $tagName); return $h; } /** * @param string $tagName * @param mixed[] $args */ public static function __callStatic($tagName, $args) { return static::create($tagName, ...$args); } public static function a() { $a = static::create('a', func_get_args()); if($a->prop('target') === '_blank' && !$a->hasProp('rel')) { $a->setProp('rel', 'noopener noreferrer'); } return $a; } /** * @param mixed ...$args */ public static function button(...$args) { $button = static::create('button', ...$args); $button->setDefaultProps('type', 'button'); return $button; } /** * @param mixed ...$args */ public static function input(...$args) { $input = static::create('input', ...$args); if($input->prop('type') === 'file') { $name = $input->prop('name'); if($name && !str_contains($name, '[')) $input->setProp('name', "{$name}[]"); } else { $input->setDefaultProps('type', 'text'); } return $input; } /** * @param mixed $value * @param mixed ...$args * @param string $name */ public static function formHidden($name, $value, ...$args) { $input = static::create('input', ...$args); $input->setDefaultProps(array('type' => 'hidden', 'name' => $name, 'value' => strval($value))); return $input; } /** * @param mixed ...$args */ public static function checkbox(...$args) { $input = static::create('input', ...$args); $input->setDefaultProps('type', 'checkbox'); return $input; } /** * @param mixed ...$args */ public static function radio(...$args) { $input = static::create('input', ...$args); $input->setDefaultProps('type', 'radio'); return $input; } /** * @param mixed ...$args */ public static function textarea(...$args) { list($code, $args) = h::splitRawCode($args); return static::create('textarea', $code, $args); } /** * create a html comment tag * * @access public * @param string $comment * @return node */ public static function comment($comment) { return html(""); } /** * @param mixed ...$args * @param string $src */ public static function importJs($src, ...$args) { $script = static::create('script', ...$args); $script->setDefaultProps('src', static::formatResourceUrl($src)); return $script; } /** * @param mixed ...$args * @param string $href */ public static function importCss($href, ...$args) { $link = static::create('link', ...$args); $link->setDefaultProps(array('rel' => 'stylesheet', 'href' => static::formatResourceUrl($href))); return $link; } /** * @param string $url */ public static function formatResourceUrl($url) { global $config; $pathInfo = parse_url($url); $mark = !empty($pathInfo['query']) ? '&' : '?'; return "$url{$mark}v={$config->version}"; } /** * @param mixed ...$args * @param string $url */ public static function favicon($url, ...$args) { return array ( static::create('link', set(array('rel' => 'icon', 'href' => $url, 'type' => 'image/x-icon')), ...$args), static::create('link', set(array('rel' => 'shortcut icon', 'href' => $url, 'type' => 'image/x-icon')), ...$args) ); } /** * @param string|mixed[] $file * @param mixed ...$args * @param string|null $type */ public static function import($file, $type = null, ...$args) { if(is_array($file)) { $children = array(); foreach($file as $file) { $children[] = static::import($file, $type); } return $children; } if($type === null) $type = pathinfo($file, PATHINFO_EXTENSION); if($type == 'js' || $type == 'cjs') return static::importJs($file, $args); if($type == 'css') return static::importCss($file, $args); return null; } /** * @param mixed ...$args */ public static function css(...$args) { list($code, $args) = h::splitRawCode($args); if(empty($code)) return null; return static::create('style', html(...$code), $args); } /** * @param mixed ...$args */ public static function globalJS(...$args) { list($code, $args) = h::splitRawCode($args, true); if(empty($code)) return null; return static::create('script', html(...$code), $args); } /** * @param mixed ...$args */ public static function js(...$args) { list($code, $args) = h::splitRawCode($args, true); if(empty($code)) return null; $code = ';(function(){' . implode("\n", $code) . '}());'; return static::create('script', html($code), ...$args); } /** * @param mixed $value * @param mixed ...$args * @param string $name */ public static function jsVar($name, $value, ...$args) { return static::js(js()->var($name, $value), $args); } /** * @param mixed ...$args * @param string $funcName */ public static function jsCall($funcName, ...$args) { $args = func_get_args(); $funcName = array_shift($args); $funcArgs = array(); $directives = array(); foreach($args as $arg) { if(isDirective($arg)) $directives[] = $arg; else $funcArgs[] = $arg; } if(str_starts_with($funcName, '~')) { $funcName = substr($funcName, 1); $js = js()->call('$', jsCallback()->do(js()->call($funcName, ...$funcArgs))); } else { $js = js()->call($funcName, ...$funcArgs); } return static::js($js, $directives); } protected static function splitRawCode($children, $includeJS = false) { $children = \zin\utils\flat($children); $code = array(); $args = array(); foreach($children as $child) { if($includeJS && $child instanceof js) $child = $child->toJS(); if(is_string($child)) $code[] = $child; else $args[] = $child; } return array($code, $args); } public static $selfCloseTags = array('area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'); }