h.class.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. /**
  3. * The html element class file of zin of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
  6. * @author Hao Sun <sunhao@easycorp.ltd>
  7. * @package zin
  8. * @version $Id
  9. * @link https://www.zentao.net
  10. */
  11. namespace zin;
  12. require_once __DIR__ . DS . 'node.class.php';
  13. require_once __DIR__ . DS . 'text.class.php';
  14. require_once __DIR__ . DS . 'directive.class.php';
  15. class h extends node
  16. {
  17. /**
  18. * @var mixed[]
  19. */
  20. 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');
  21. /**
  22. * @var mixed[]
  23. */
  24. public static $defineProps = array
  25. (
  26. 'tagName' => 'string',
  27. 'selfClose' => '?bool'
  28. );
  29. public function tagName()
  30. {
  31. $tagName = $this->prop('tagName');
  32. return $tagName === null ? '' : $tagName;
  33. }
  34. public function fullType()
  35. {
  36. return 'zin\\' . $this->tagName();
  37. }
  38. public function type()
  39. {
  40. return $this->tagName();
  41. }
  42. public function isSelfClose()
  43. {
  44. $selfClose = $this->prop('selfClose');
  45. if($selfClose !== null) return boolval($selfClose);
  46. return in_array($this->tagName(), static::$selfCloseTags);
  47. }
  48. /**
  49. * @param mixed[]|string $prop
  50. * @param mixed $value
  51. */
  52. protected function onSetProp($prop, $value)
  53. {
  54. if($prop === 'className') $prop = 'class';
  55. return parent::onSetProp($prop, $value);
  56. }
  57. /**
  58. * @return mixed
  59. */
  60. public function build()
  61. {
  62. if($this->isSelfClose()) return $this->buildSelfCloseTag();
  63. $content = array($this->buildTagBegin());
  64. $build = parent::build();
  65. if(is_array($build)) $content = array_merge($content, $build);
  66. else $content[] = $build;
  67. $content[] = $this->buildTagEnd();
  68. return $content;
  69. }
  70. protected function getPropsStr()
  71. {
  72. $propStr = $this->props->toStr(array_keys(static::definedPropsList()));
  73. if($this->props->hasEvent() && empty($this->id()) && $this->tagName() !== 'html') $propStr = "$propStr id='$this->gid'";
  74. return empty($propStr) ? '' : " $propStr";
  75. }
  76. protected function buildSelfCloseTag()
  77. {
  78. $tagName = $this->tagName();
  79. $propStr = $this->getPropsStr();
  80. return "<$tagName$propStr />";
  81. }
  82. protected function buildTagBegin()
  83. {
  84. $tagName = $this->tagName();
  85. $propStr = $this->getPropsStr();
  86. return "<$tagName$propStr>";
  87. }
  88. protected function buildTagEnd()
  89. {
  90. $tagName = $this->tagName();
  91. return "</$tagName>";
  92. }
  93. /**
  94. * @param mixed ...$args
  95. * @param string $tagName
  96. */
  97. public static function create($tagName, ...$args)
  98. {
  99. $h = new h(...$args);
  100. $h->setProp('tagName', $tagName);
  101. return $h;
  102. }
  103. /**
  104. * @param string $tagName
  105. * @param mixed[] $args
  106. */
  107. public static function __callStatic($tagName, $args)
  108. {
  109. return static::create($tagName, ...$args);
  110. }
  111. public static function a()
  112. {
  113. $a = static::create('a', func_get_args());
  114. if($a->prop('target') === '_blank' && !$a->hasProp('rel'))
  115. {
  116. $a->setProp('rel', 'noopener noreferrer');
  117. }
  118. return $a;
  119. }
  120. /**
  121. * @param mixed ...$args
  122. */
  123. public static function button(...$args)
  124. {
  125. $button = static::create('button', ...$args);
  126. $button->setDefaultProps('type', 'button');
  127. return $button;
  128. }
  129. /**
  130. * @param mixed ...$args
  131. */
  132. public static function input(...$args)
  133. {
  134. $input = static::create('input', ...$args);
  135. if($input->prop('type') === 'file')
  136. {
  137. $name = $input->prop('name');
  138. if($name && !str_contains($name, '[')) $input->setProp('name', "{$name}[]");
  139. }
  140. else
  141. {
  142. $input->setDefaultProps('type', 'text');
  143. }
  144. return $input;
  145. }
  146. /**
  147. * @param mixed $value
  148. * @param mixed ...$args
  149. * @param string $name
  150. */
  151. public static function formHidden($name, $value, ...$args)
  152. {
  153. $input = static::create('input', ...$args);
  154. $input->setDefaultProps(array('type' => 'hidden', 'name' => $name, 'value' => strval($value)));
  155. return $input;
  156. }
  157. /**
  158. * @param mixed ...$args
  159. */
  160. public static function checkbox(...$args)
  161. {
  162. $input = static::create('input', ...$args);
  163. $input->setDefaultProps('type', 'checkbox');
  164. return $input;
  165. }
  166. /**
  167. * @param mixed ...$args
  168. */
  169. public static function radio(...$args)
  170. {
  171. $input = static::create('input', ...$args);
  172. $input->setDefaultProps('type', 'radio');
  173. return $input;
  174. }
  175. /**
  176. * @param mixed ...$args
  177. */
  178. public static function textarea(...$args)
  179. {
  180. list($code, $args) = h::splitRawCode($args);
  181. return static::create('textarea', $code, $args);
  182. }
  183. /**
  184. * create a html comment tag <!--...-->
  185. *
  186. * @access public
  187. * @param string $comment
  188. * @return node
  189. */
  190. public static function comment($comment)
  191. {
  192. return html("<!-- $comment -->");
  193. }
  194. /**
  195. * @param mixed ...$args
  196. * @param string $src
  197. */
  198. public static function importJs($src, ...$args)
  199. {
  200. $script = static::create('script', ...$args);
  201. $script->setDefaultProps('src', static::formatResourceUrl($src));
  202. return $script;
  203. }
  204. /**
  205. * @param mixed ...$args
  206. * @param string $href
  207. */
  208. public static function importCss($href, ...$args)
  209. {
  210. $link = static::create('link', ...$args);
  211. $link->setDefaultProps(array('rel' => 'stylesheet', 'href' => static::formatResourceUrl($href)));
  212. return $link;
  213. }
  214. /**
  215. * @param string $url
  216. */
  217. public static function formatResourceUrl($url)
  218. {
  219. global $config;
  220. $pathInfo = parse_url($url);
  221. $mark = !empty($pathInfo['query']) ? '&' : '?';
  222. return "$url{$mark}v={$config->version}";
  223. }
  224. /**
  225. * @param mixed ...$args
  226. * @param string $url
  227. */
  228. public static function favicon($url, ...$args)
  229. {
  230. return array
  231. (
  232. static::create('link', set(array('rel' => 'icon', 'href' => $url, 'type' => 'image/x-icon')), ...$args),
  233. static::create('link', set(array('rel' => 'shortcut icon', 'href' => $url, 'type' => 'image/x-icon')), ...$args)
  234. );
  235. }
  236. /**
  237. * @param string|mixed[] $file
  238. * @param mixed ...$args
  239. * @param string|null $type
  240. */
  241. public static function import($file, $type = null, ...$args)
  242. {
  243. if(is_array($file))
  244. {
  245. $children = array();
  246. foreach($file as $file)
  247. {
  248. $children[] = static::import($file, $type);
  249. }
  250. return $children;
  251. }
  252. if($type === null) $type = pathinfo($file, PATHINFO_EXTENSION);
  253. if($type == 'js' || $type == 'cjs') return static::importJs($file, $args);
  254. if($type == 'css') return static::importCss($file, $args);
  255. return null;
  256. }
  257. /**
  258. * @param mixed ...$args
  259. */
  260. public static function css(...$args)
  261. {
  262. list($code, $args) = h::splitRawCode($args);
  263. if(empty($code)) return null;
  264. return static::create('style', html(...$code), $args);
  265. }
  266. /**
  267. * @param mixed ...$args
  268. */
  269. public static function globalJS(...$args)
  270. {
  271. list($code, $args) = h::splitRawCode($args, true);
  272. if(empty($code)) return null;
  273. return static::create('script', html(...$code), $args);
  274. }
  275. /**
  276. * @param mixed ...$args
  277. */
  278. public static function js(...$args)
  279. {
  280. list($code, $args) = h::splitRawCode($args, true);
  281. if(empty($code)) return null;
  282. $code = ';(function(){' . implode("\n", $code) . '}());';
  283. return static::create('script', html($code), ...$args);
  284. }
  285. /**
  286. * @param mixed $value
  287. * @param mixed ...$args
  288. * @param string $name
  289. */
  290. public static function jsVar($name, $value, ...$args)
  291. {
  292. return static::js(js()->var($name, $value), $args);
  293. }
  294. /**
  295. * @param mixed ...$args
  296. * @param string $funcName
  297. */
  298. public static function jsCall($funcName, ...$args)
  299. {
  300. $args = func_get_args();
  301. $funcName = array_shift($args);
  302. $funcArgs = array();
  303. $directives = array();
  304. foreach($args as $arg)
  305. {
  306. if(isDirective($arg)) $directives[] = $arg;
  307. else $funcArgs[] = $arg;
  308. }
  309. if(str_starts_with($funcName, '~'))
  310. {
  311. $funcName = substr($funcName, 1);
  312. $js = js()->call('$', jsCallback()->do(js()->call($funcName, ...$funcArgs)));
  313. }
  314. else
  315. {
  316. $js = js()->call($funcName, ...$funcArgs);
  317. }
  318. return static::js($js, $directives);
  319. }
  320. protected static function splitRawCode($children, $includeJS = false)
  321. {
  322. $children = \zin\utils\flat($children);
  323. $code = array();
  324. $args = array();
  325. foreach($children as $child)
  326. {
  327. if($includeJS && $child instanceof js) $child = $child->toJS();
  328. if(is_string($child)) $code[] = $child;
  329. else $args[] = $child;
  330. }
  331. return array($code, $args);
  332. }
  333. public static $selfCloseTags = array('area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr');
  334. }