* zin: improve zin lib.

This commit is contained in:
sunhao
2024-02-26 17:09:45 +08:00
parent c572bf0067
commit 448a86a606
139 changed files with 1772 additions and 3501 deletions
+1 -1
View File
@@ -155,6 +155,6 @@ formPanel
)
);
useData('title', $title);
setPageData('title', $title);
render();
+9 -11
View File
@@ -1002,28 +1002,26 @@ class baseControl
chdir(dirname($viewFile));
/**
* Set zin context data
* Init zin context data.
* 设置 zin 渲染上下文数据。
*/
\zin\zin::$globalRenderList = array();
\zin\zin::$enabledGlobalRender = true;
\zin\zin::$rendered = false;
\zin\zin::$rawContentCalled = false;
$context = \zin\context();
$context->data = (array)$this->view;
$context->data['zinDebug'] = array();
\zin\zin::$data = (array)$this->view;
\zin\zin::$data['zinDebug'] = array();
if($this->config->debug && $this->config->debug >= 2 && $this->config->installed)
{
\zin\zin::$data['zinDebug']['trace'] = $this->app->loadClass('trace')->getTrace();
$context->data['zinDebug']['trace'] = $this->app->loadClass('trace')->getTrace();
}
/**
* 使用extract和ob方法渲染$viewFile里面的代码。
* Use extract and ob functions to eval the codes in $viewFile.
*/
extract(\zin\zin::$data);
extract($context->data);
/* 将 hooks 文件添加到当前 context 中。 */
if(!empty($hookFiles)) \zin\context::current()->addHookFiles($hookFiles);
if(!empty($hookFiles)) $context->addHookFiles($hookFiles);
/* 加载 common.field.php 和 method.field.php。 */
$commonFieldFile = dirname($viewFile) . DS . 'common.field.php';
@@ -1034,7 +1032,7 @@ class baseControl
ob_start();
include $viewFile;
if(!\zin\zin::$rendered) \zin\render();
if(!$context->rendered) \zin\render();
$content = ob_get_clean();
ob_start();
+120 -21
View File
@@ -16,13 +16,110 @@ use function zin\utils\flat;
require_once dirname(__DIR__) . DS . 'utils' . DS . 'dataset.class.php';
require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php';
require_once dirname(__DIR__) . DS . 'utils' . DS . 'deep.func.php';
class context extends \zin\utils\dataset
{
public string $name;
public array $globalRenderList = array();
public int $globalRenderLevel = 0;
public array $data = array();
public bool $rendered = false;
public bool $rawContentCalled = false;
public function __construct(string $name)
{
parent::__construct();
$this->name = $name;
}
public function __debugInfo(): array
{
return array_merge(array
(
'name' => $this->name,
'globalRenderListLen' => count($this->globalRenderList),
'globalRenderList' => $this->globalRenderList,
'globalRenderLevel' => $this->globalRenderLevel,
'rendered' => $this->rendered,
'rawContentCalled' => $this->rawContentCalled,
), $this->storedData);
}
public function getData(string $namePath, mixed $defaultValue = null): mixed
{
return \zin\utils\deepGet($this->data, $namePath, $defaultValue);
}
public function setData(string $namePath, mixed $value)
{
\zin\utils\deepSet($this->data, $namePath, $value);
}
public function enableGlobalRender()
{
$this->globalRenderLevel--;
}
public function disableGlobalRender()
{
$this->globalRenderLevel++;
}
public function enabledGlobalRender()
{
return $this->globalRenderLevel < 1;
}
public function renderInGlobal(node|iDirective $item): bool
{
if($this->globalRenderLevel > 0)
{
return false;
}
if($item instanceof node)
{
if($item->parent || $item->shortType() === 'wg') return false;
if(!isset($this->globalRenderList[$item->gid])) $this->globalRenderList[$item->gid] = $item;
return true;
}
if(in_array($item, $this->globalRenderList)) return false;
$this->globalRenderList[] = $item;
return true;
}
public function getGlobalRenderList(bool $clear = true): array
{
$globalItems = array();
foreach($this->globalRenderList as $item)
{
if(is_object($item) && ((isset($item->parent) && $item->parent) || (isset($item->notRenderInGlobal) && $item->notRenderInGlobal)))
{
continue;
}
$globalItems[] = $item;
}
/* Clear globalRenderList. */
if($clear) $this->globalRenderList = array();
return $globalItems;
}
public function addHookFiles(string|array ...$files)
{
$files = flat($files);
return $this->mergeToList('hookFiles', $files);
return $this->mergeToList('hookFiles', array_filter(array_values($files)));
}
public function getHookFiles(): array
@@ -30,12 +127,12 @@ class context extends \zin\utils\dataset
return $this->getList('hookFiles');
}
public function addImport(string ...$files)
public function addImports(string ...$files)
{
return $this->mergeToList('import', $files);
}
public function getImportList(): array
public function getImports(): array
{
return $this->getList('import');
}
@@ -57,7 +154,7 @@ class context extends \zin\utils\dataset
public function addJSVar(string $name, mixed $value)
{
return $this->addToList('jsVar', h::createJsVarCode($name, $value));
// return $this->addToList('jsVar', h::createJsVarCode($name, $value));
}
public function addWgWithEvents($wg)
@@ -107,7 +204,7 @@ class context extends \zin\utils\dataset
return $js;
}
public static $map = array();
public static array $stack = array();
public static function js(/* string ...$code */)
{
@@ -121,7 +218,6 @@ class context extends \zin\utils\dataset
call_user_func_array(array($context, 'addJSCall'), func_get_args());
}
public static function jsVar($name, $value)
{
$context = static::current();
@@ -137,7 +233,7 @@ class context extends \zin\utils\dataset
public static function import(/* string ...$files */)
{
$context = static::current();
call_user_func_array(array($context, 'addImport'), func_get_args());
call_user_func_array(array($context, 'addImports'), func_get_args());
}
/**
@@ -148,35 +244,38 @@ class context extends \zin\utils\dataset
*/
public static function current(): context
{
if(empty(static::$map)) static::$map['current'] = new context();
return static::$map['current'];
if(empty(static::$stack))
{
$context = new context('default');
static::$stack['default'] = $context;
return $context;
}
return end(static::$stack);
}
/**
* Create widget context.
* Create context.
*
* @access public
* @param string $gid The widget gid.
* @param string $name Context name.
* @return context
*/
public static function create(string $gid): context
public static function create(string $name): context
{
if(isset(static::$map[$gid])) return static::$map[$gid];
$context = new context();
static::$map[$gid] = $context;
if(isset(static::$stack[$name])) return static::$stack[$name];
$context = new context($name);
static::$stack[$name] = $context;
return $context;
}
/**
* Destroy widget context.
* Pop last context.
*
* @access public
* @param string $gid The widget gid.
* @return void
* @return ?context
*/
public static function destroy(string $gid = null): void
public static function pop(): ?context
{
if($gid === null) unset(static::$map['current']);
elseif(isset(static::$map[$gid])) unset(static::$map[$gid]);
return array_pop(static::$stack);
}
}
+61
View File
@@ -14,6 +14,32 @@ namespace zin;
require_once __DIR__ . DS . 'context.class.php';
function context(?string $name = null): context
{
if($name) return context::create($name);
return context::current();
}
function popContext()
{
return context::pop();
}
function enableGlobalRender()
{
context::current()->enableGlobalRender();
}
function disableGlobalRender()
{
context::current()->disableGlobalRender();
}
function renderInGlobal(node|iDirective $item): bool
{
return context::current()->renderInGlobal($item);
}
function pageJS()
{
call_user_func_array('\zin\context::js', func_get_args());
@@ -38,3 +64,38 @@ function import()
{
call_user_func_array('\zin\context::import', func_get_args());
}
function setPageData($name, $value)
{
$context = context::current();
if(is_array($value) && empty($name))
{
foreach ($value as $key => $val) $context->setData($key, $val);
return;
}
$context->setData($name, $value);
}
function getPageData($name)
{
$context = context::current();
if(is_array($name))
{
$values = array();
foreach($name as $propName)
{
$values[] = $context->getData($propName);
}
return $values;
}
return $context->getData($name);
}
function data()
{
$args = func_get_args();
if(count($args) >= 2) return setPageData($args[0], $args[1]);
return getPageData($args[0]);
}
-55
View File
@@ -1,55 +0,0 @@
<?php
declare(strict_types=1);
/**
* The data function file of zin of ZenTaoPMS.
*
* @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
function setPageData($name, $value)
{
if(is_array($value) && empty($name))
{
foreach ($value as $key => $val) zin::setData($key, $val);
return;
}
zin::setData($name, $value);
}
function getPageData($name)
{
if(is_array($name))
{
$values = array();
foreach($name as $propName)
{
$values[] = zin::getData($propName);
}
return $values;
}
return zin::getData($name);
}
function data()
{
$args = func_get_args();
if(count($args) >= 2) return setPageData($args[0], $args[1]);
return getPageData($args[0]);
}
/**
* Set page data
* @deprecated Use data($name, $value) insteadOf useData($name, $value)
*/
function useData($name, $value)
{
return setPageData($name, $value);
}
+26 -13
View File
@@ -13,8 +13,16 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'zin.class.php';
require_once __DIR__ . DS . 'context.func.php';
class directive
use zin\node;
interface iDirective
{
public function apply(node $node, string $blockName): void;
}
class directive implements iDirective
{
public string $type;
@@ -37,7 +45,10 @@ class directive
$this->data = $data;
$this->options = $options;
zin::renderInGlobal($this);
if(!$options || !isset($options['notRenderInGlobal']) || !$options['notRenderInGlobal'])
{
renderInGlobal($this);
}
}
public function __debugInfo(): array
@@ -49,50 +60,52 @@ class directive
);
}
public function applyToWg(wg &$wg, string $blockName): void
public function apply(node $node, string $blockName): void
{
$this->parent = $wg;
$this->parent = $node;
$data = $this->data;
$type = $this->type;
if($type === 'prop')
{
$wg->setProp($data);
$node->setProp($data);
return;
}
if($type === 'class' || $type === 'style')
{
$wg->setProp($type, $data);
$node->setProp($type, $data);
return;
}
if($type === 'cssVar')
{
$wg->setProp('--', $data);
$node->setProp('--', $data);
return;
}
if($type === 'html')
{
$wg->addToBlock($blockName, $this);
$html = new stdClass();
$html->html = implode("\n", $data);
$node->addToBlock($blockName, $html);
return;
}
if($type === 'text')
{
$wg->addToBlock($blockName, htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, null, false));
$node->addToBlock($blockName, $data);
return;
}
if($type === 'block')
{
foreach($data as $blockName => $blockChildren)
{
$wg->add($blockChildren, $blockName);
$node->add($blockChildren, $blockName);
}
}
}
public static function is(mixed $item, ?string $type = null): bool
public static function is(mixed $item): bool
{
return $item instanceof directive && ($type === null || $item->type === $type);
return ($item instanceof directive) || $item instanceof iDirective || (is_object($item) && method_exists($item, 'apply'));
}
}
@@ -103,5 +116,5 @@ function directive($type, $data, $options = null): directive
function isDirective(mixed $item, ?string $type = null): bool
{
return directive::is($item, $type);
return directive::is($item);
}
+1 -2
View File
@@ -130,8 +130,7 @@ class dom
* @access public
* @return array
*/
public function build()
{
public function build(): mixed {
if($this->wg->removed) return array();
if($this->buildList !== null && $this->buildListInner === $this->renderInner) return $this->buildList;
+98 -174
View File
@@ -12,153 +12,141 @@ declare(strict_types=1);
namespace zin;
require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php';
require_once dirname(__DIR__) . DS . 'utils' . DS . 'json.func.php';
require_once __DIR__ . DS . 'wg.class.php';
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'node.class.php';
require_once __DIR__ . DS . 'text.class.php';
require_once __DIR__ . DS . 'directive.class.php';
class h extends wg
class h extends node
{
protected static array $defineProps = array(
'tagName: string',
'selfClose?: bool'
public static array $defineProps = array
(
'tagName' => 'string',
'selfClose' => '?bool'
);
public function tagName(): string
{
$tagName = $this->prop('tagName');
return $tagName === null ? '' : $tagName;
}
public function type(): string
{
return 'h::' . $this->tagName();
}
public function shortType(): string
{
return $this->tagName();
}
public function isSelfClose(): bool
{
$selfClose = $this->prop('selfClose');
if($selfClose !== null) return boolval($selfClose);
return in_array($this->tagName(), static::$selfCloseTags);
}
protected function onSetProp(array|string $prop, mixed $value)
{
if($prop === 'className') $prop = 'class';
return parent::onSetProp($prop, $value);
}
public function getTagName(): string
public function build(): mixed
{
return $this->props->get('tagName');
}
public function isDomElement(): bool
{
return true;
}
public function isSelfClose()
{
$selfClose = $this->props->get('selfClose');
if($selfClose !== null) return $selfClose;
return in_array($this->getTagName(), static::$selfCloseTags);
}
public function build(): array
{
if($this->isSelfClose()) return array($this->buildSelfCloseTag());
if($this->isSelfClose()) return $this->buildSelfCloseTag();
return array($this->buildTagBegin(), parent::build(), $this->buildTagEnd());
}
public function toJSON(): array
{
$data = parent::toJSON();
$data['type'] = 'h:' . $this->getTagName();
return $data;
}
public function type(): string
{
return $this->getTagName();
}
public function shortType(): string
{
return $this->getTagName();
}
protected function getPropsStr(): string
{
$propStr = $this->props->toStr(array_keys(static::definedPropsList()));
if($this->props->hasEvent() && empty($this->id()) && $this->getTagName() !== 'html') $propStr = "$propStr id='$this->gid'";
if($this->props->hasEvent() && empty($this->id()) && $this->tagName() !== 'html') $propStr = "$propStr id='$this->gid'";
return empty($propStr) ? '' : " $propStr";
}
protected function buildSelfCloseTag(): string
{
$tagName = $this->getTagName();
$tagName = $this->tagName();
$propStr = $this->getPropsStr();
return "<$tagName$propStr />";
}
protected function buildTagBegin(): string
{
$tagName = $this->getTagName();
$tagName = $this->tagName();
$propStr = $this->getPropsStr();
return "<$tagName$propStr>";
}
protected function buildTagEnd(): string
{
$tagName = $this->getTagName();
$tagName = $this->tagName();
return "</$tagName>";
}
public static function create(): h
public static function create(string $tagName, mixed ...$args): h
{
$args = func_get_args();
$tagName = array_shift($args);
return new h(is_string($tagName) ? set('tagName', $tagName) : $tagName, $args);
$h = new h(...$args);
$h->setProp('tagName', $tagName);
return $h;
}
public static function __callStatic(string $tagName, array $args): h
{
return new h(set('tagName', $tagName), $args);
return static::create($tagName, ...$args);
}
public static function a(): h
{
$a = static::create('a', func_get_args());
if($a->prop('target') === '_blank' && !$a->hasProp('rel')) $a->prop('rel', 'noopener noreferrer');
if($a->prop('target') === '_blank' && !$a->hasProp('rel'))
{
$a->setProp('rel', 'noopener noreferrer');
}
return $a;
}
public static function button()
public static function button(mixed ...$args): h
{
return static::create('button', set('type', 'button'), func_get_args());
$button = static::create('button', ...$args);
$button->setDefaultProps('type', 'button');
return $button;
}
public static function input()
public static function input(mixed ...$args): h
{
return static::create('input', set('type', 'text'), func_get_args());
$input = static::create('input', ...$args);
$input->setDefaultProps('type', 'text');
return $input;
}
public static function formHidden(/* $name, $value, ...$args */)
public static function formHidden(string $name, string $value, mixed ...$args): h
{
$args = func_get_args();
$name = array_shift($args);
$value = array_shift($args);
return static::create('input', set('type', 'hidden'), set::name($name), set::value($value), $args);
$input = static::create('input', ...$args);
$input->setDefaultProps(array('type' => 'hidden', 'name' => $name, 'value' => $value));
return $input;
}
public static function checkbox()
public static function checkbox(mixed ...$args): h
{
return static::create('input', set('type', 'checkbox'), func_get_args());
$input = static::create('input', ...$args);
$input->setDefaultProps('type', 'checkbox');
return $input;
}
public static function radio()
public static function radio(mixed ...$args): h
{
return static::create('input', set('type', 'radio'), func_get_args());
$input = static::create('input', ...$args);
$input->setDefaultProps('type', 'radio');
return $input;
}
public static function date()
public static function textarea(mixed ...$args)
{
return static::create('input', set('type', 'date'), func_get_args());
}
public static function file()
{
return static::create('input', set('type', 'file'), func_get_args());
}
public static function textarea(/* ...$args */)
{
$args = func_get_args();
list($code, $args) = h::splitRawCode($args);
return static::create('textarea', $code, $args);
}
@@ -168,33 +156,29 @@ class h extends wg
*
* @access public
* @param string $comment
* @return directive
* @return node
*/
public static function comment(string $comment): directive
public static function comment(string $comment): text
{
return html("<!-- $comment -->");
}
public static function importJs(/* $src, ...$args */)
public static function importJs(string $src, mixed ...$args): h
{
$args = func_get_args();
$src = array_shift($args);
return static::create('script', set('src', $src), $args);
$script = static::create('script', ...$args);
$script->setDefaultProps('src', 'src');
return $script;
}
public static function importCss(/* $src, ...$args */)
public static function importCss(string $href, mixed ...$args): h
{
$args = func_get_args();
$src = array_shift($args);
return static::create('link', set('rel', 'stylesheet'), set('href', $src), $args);
$link = static::create('link', ...$args);
$link->setDefaultProps(array('rel' => 'stylesheet', 'href' => $href));
return $link;
}
public static function import(/* $file, $type = null, ...$args */)
public static function import(string|array $file, ?string $type = null, mixed ...$args): ?h
{
$args = array_merge(func_get_args(), array(null, null));
$file = array_shift($args);
$type = array_shift($args);
if(is_array($file))
{
$children = array();
@@ -210,37 +194,35 @@ class h extends wg
return null;
}
public static function css(/* ...$args */)
public static function css(mixed ...$args): ?h
{
list($code, $args) = h::splitRawCode(func_get_args());
list($code, $args) = h::splitRawCode($args);
if(empty($code)) return null;
return static::create('style', html(implode("\n", $code)), $args);
return static::create('style', html(...$code), $args);
}
public static function globalJS(/* ...$args */)
public static function globalJS(mixed ...$args): ?h
{
list($code, $args) = h::splitRawCode(func_get_args());
list($code, $args) = h::splitRawCode($args);
if(empty($code)) return null;
return static::create('script', html(implode("\n", $code)), $args);
return static::create('script', html(...$code), $args);
}
public static function js(/* ...$args */)
public static function js(mixed ...$args): ?h
{
list($code, $args) = h::splitRawCode(func_get_args());
list($code, $args) = h::splitRawCode($args);
if(empty($code)) return null;
return static::create('script', html(h::createJsScopeCode($code)), $args);
$code = ';(function(){' . implode("\n", $code) . '}());';
return static::create('script', html($code, $args));
}
public static function jsVar(/* $name, $value, ...$args */)
public static function jsVar(string $name, mixed $value, mixed ...$args): ?h
{
$args = func_get_args();
$name = array_shift($args);
$value = array_shift($args);
return static::js(static::createJsVarCode($name, $value), $args);
return static::js(js()->var($name, $value), $args);
}
public static function jsCall(/* $funcName, ...$args */)
public static function jsCall(string $funcName, mixed ...$args): h
{
$args = func_get_args();
$funcName = array_shift($args);
@@ -250,69 +232,11 @@ class h extends wg
foreach($args as $arg)
{
if(isDirective($arg)) $directives[] = $arg;
else $funcArgs[] = $arg;
}
$code = static::createJsCallCode($funcName, $funcArgs);
return static::js($code, $directives);
}
public static function createJsCallCode($func, $args)
{
foreach($args as $index => $arg)
{
$args[$index] = h::encodeJsonWithRawJs($arg, JSON_UNESCAPED_UNICODE);
else $funcArgs[] = $arg;
}
if($func[0] === '~')
{
$func = substr($func, 1);
return "$(() => $func(" . implode(',', $args) . "));";
}
return $func . '(' . implode(',', $args) . ');';
}
public static function createJsVarCode($name, $value)
{
$vars = is_string($name) ? array($name => $value) : $name;
$jsCode = '';
foreach($vars as $var => $val)
{
if(empty($var)) continue;
$val = h::encodeJsonWithRawJs($val);
if(str_starts_with($var, 'window.')) $jsCode .= "$var=" . $val . ';';
elseif(str_starts_with($var, '+')) $jsCode .= 'let ' . substr($var, 1) . '=' . $val . ';';
else $jsCode .= "const $var=" . $val . ';';
}
return $jsCode;
}
public static function createJsScopeCode(string|array $codes): string
{
if(is_array($codes)) $codes = implode("\n", $codes);
return ";(function(){\n$codes\n}());";
}
public static function jsRaw(): string
{
$js = implode('RAWJS_LINE', func_get_args());
$js = str_replace(array("\n", '"'), array('RAWJS_LINE', 'RAWJS_QUOTE'), $js);
return "RAWJS<$js>RAWJS";
}
public static function decodeJSRaw(string $str): string
{
if(!str_contains($str, 'RAWJS')) return $str;
return str_replace(array('RAWJS_LINE', 'RAWJS_QUOTE', '"RAWJS<', '>RAWJS"'), array("\n", '"', '', ''), $str);
}
public static function encodeJsonWithRawJs($data)
{
$json = \zin\utils\jsonEncode($data, JSON_UNESCAPED_UNICODE);
if(empty($json) && (is_array($data) || is_object($data))) return '[]';
return static::decodeJSRaw($json);
$js = js()->call($funcName, ...$funcArgs);
return static::js($js->toJS(), $directives);
}
protected static function splitRawCode($children)
@@ -323,9 +247,9 @@ class h extends wg
foreach($children as $child)
{
if(is_string($child)) $code[] = $child;
else $args[] = $child;
else $args[] = $child;
}
return [$code, $args];
return array($code, $args);
}
public static $selfCloseTags = array('area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr');
+23 -31
View File
@@ -13,35 +13,27 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'h.class.php';
require_once __DIR__ . DS . 'item.class.php';
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'set.class.php';
require_once __DIR__ . DS . 'to.class.php';
require_once __DIR__ . DS . 'data.func.php';
require_once __DIR__ . DS . 'on.class.php';
function h(): h {return call_user_func_array('\zin\h::create', func_get_args());}
function div(): h {return call_user_func_array('\zin\h::div', func_get_args());}
function span(): h {return call_user_func_array('\zin\h::span', func_get_args());}
function code(): h {return call_user_func_array('\zin\h::code', func_get_args());}
function canvas(): h {return call_user_func_array('\zin\h::canvas', func_get_args());}
function br(): h {return call_user_func_array('\zin\h::br', func_get_args());}
function a(): h {return call_user_func_array('\zin\h::a', func_get_args());}
function p(): h {return call_user_func_array('\zin\h::p', func_get_args());}
function img(): h {return call_user_func_array('\zin\h::img', func_get_args());}
function button(): h {return call_user_func_array('\zin\h::button', func_get_args());}
function h1(): h {return call_user_func_array('\zin\h::h1', func_get_args());}
function h2(): h {return call_user_func_array('\zin\h::h2', func_get_args());}
function h3(): h {return call_user_func_array('\zin\h::h3', func_get_args());}
function h4(): h {return call_user_func_array('\zin\h::h4', func_get_args());}
function h5(): h {return call_user_func_array('\zin\h::h5', func_get_args());}
function h6(): h {return call_user_func_array('\zin\h::h6', func_get_args());}
function ul(): h {return call_user_func_array('\zin\h::ul', func_get_args());}
function li(): h {return call_user_func_array('\zin\h::li', func_get_args());}
function template(): h {return call_user_func_array('\zin\h::template', func_get_args());}
function formHidden(): h {return call_user_func_array('\zin\h::formHidden', func_get_args());}
function fieldset(): h {return call_user_func_array('\zin\h::fieldset', func_get_args());}
function legend(): h {return call_user_func_array('\zin\h::legend', func_get_args());}
function jsRaw(): string {return call_user_func_array('\zin\h::jsRaw', func_get_args());}
function h(mixed ...$args): h {return h::create(...$args);}
function div(mixed ...$args): h {return h::div(...$args);}
function span(mixed ...$args): h {return h::span(...$args);}
function code(mixed ...$args): h {return h::code(...$args);}
function canvas(mixed ...$args): h {return h::canvas(...$args);}
function br(mixed ...$args): h {return h::br(...$args);}
function a(mixed ...$args): h {return h::a(...$args);}
function p(mixed ...$args): h {return h::p(...$args);}
function img(mixed ...$args): h {return h::img(...$args);}
function button(mixed ...$args): h {return h::button(...$args);}
function h1(mixed ...$args): h {return h::h1(...$args);}
function h2(mixed ...$args): h {return h::h2(...$args);}
function h3(mixed ...$args): h {return h::h3(...$args);}
function h4(mixed ...$args): h {return h::h4(...$args);}
function h5(mixed ...$args): h {return h::h5(...$args);}
function h6(mixed ...$args): h {return h::h6(...$args);}
function ul(mixed ...$args): h {return h::ul(...$args);}
function li(mixed ...$args): h {return h::li(...$args);}
function template(mixed ...$args): h {return h::template(...$args);}
function formHidden(mixed ...$args): h {return h::formHidden(...$args);}
function fieldset(mixed ...$args): h {return h::fieldset(...$args);}
function legend(mixed ...$args): h {return h::legend(...$args);}
function rawContent(): text {return h::comment('{{RAW_CONTENT}}');}
+41
View File
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/**
* The helpers of zin lib of ZenTaoPMS.
*
* @copyright Copyright 2024 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
/**
* Check if the debug mode is on.
*
* @param int $level - The min debug level.
* @return bool
*/
function isDebug(int $level = 1): bool
{
global $config;
$debug = isset($config->debug) ? $config->debug : 0;
if(is_bool($debug)) $debug = $debug ? 1 : 0;
return $debug >= $level;
}
/**
* Trigger an error.
*
* @param string $message - The error message.
* @param int $level - The error level.
* @param string $scope - The error scope.
* @return void
*/
function triggerError(string $message, int $level = E_USER_ERROR, string $scope = 'ZIN')
{
trigger_error("[$scope] $message", $level);
}
+1 -1
View File
@@ -13,7 +13,7 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'wg.class.php';
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'zin.func.php';
class item extends wg
{
+58 -19
View File
@@ -12,11 +12,14 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'node.class.php';
require_once __DIR__ . DS . 'directive.class.php';
require_once __DIR__ . DS . 'zin.func.php';
use zin\jsContext;
use zin\jsCallback;
use zin\jQuery;
use zin\node;
/**
* Class for generating js code.
@@ -24,8 +27,10 @@ use zin\jQuery;
*
* @access public
*/
class js extends directive implements \JsonSerializable
class js implements \JsonSerializable, iDirective
{
public bool $notRenderInGlobal = true;
/**
* The js code lines.
* JS 代码行。
@@ -43,7 +48,6 @@ class js extends directive implements \JsonSerializable
*/
public function __construct(null|string|js|array ...$codes)
{
parent::__construct('js');
$this->appendLines(...$codes);
}
@@ -104,9 +108,10 @@ class js extends directive implements \JsonSerializable
$argCodes = array();
foreach($args as $arg)
{
$argCodes[] = ($arg instanceof js) ? $arg->toJS() : static::json($arg);
$argCodes[] = ($arg instanceof js) ? $arg->toJS() : static::value($arg);
}
return $this->appendLine($func, '(', implode(',', $argCodes), ')');
return $this->appendLine($func . '(' . implode(',', $argCodes) . ')');
}
/**
@@ -133,7 +138,7 @@ class js extends directive implements \JsonSerializable
*/
public function let(string $name, mixed $value): self
{
return $this->appendLine('let', $name, '=', static::json($value));
return $this->appendLine('let', $name, '=', static::value($value));
}
/**
@@ -147,7 +152,7 @@ class js extends directive implements \JsonSerializable
*/
public function const(string $name, mixed $value): self
{
return $this->appendLine('const', $name, '=', static::json($value));
return $this->appendLine('const', $name, '=', static::value($value));
}
/**
@@ -162,7 +167,21 @@ class js extends directive implements \JsonSerializable
public function globalVar(string $name, mixed $value): self
{
if(!str_starts_with($name, 'window.')) $name = 'window.' . $name;
return $this->appendLine($name, '=', static::json($value));
return $this->appendLine($name, '=', static::value($value));
}
public function var(string|array $nameOrVars, mixed $value = null): self
{
if(is_array($nameOrVars))
{
foreach($nameOrVars as $name => $val) $this->var($name, $val);
return $this;
}
$name = $nameOrVars;
if(str_starts_with($name, '+')) return $this->let(substr($name, 1), $value);
if(str_starts_with($name, 'window.')) return $this->globalVar($name, $value);
return $this->const($name, $value);
}
/**
@@ -295,7 +314,6 @@ class js extends directive implements \JsonSerializable
}
if($line instanceof js)
{
$line->parent = $this;
$line = $line->toJS();
}
$this->appendLine($line);
@@ -348,16 +366,16 @@ class js extends directive implements \JsonSerializable
}
/**
* Apply JS code to zin widget.
* Apply JS code to zin node.
* 将 JS 代码应用到指定的 zin 部件中。
*
* @access public
* @param wg $wg zin widget object.
* @param string $blockName zin widget block name.
* @param node $node zin node object.
* @param string $blockName zin node block name.
*/
public function applyToWg(wg &$wg, string $blockName): void
public function apply(node $node, string $blockName): void
{
$wg->addToBlock($blockName, h::js($this->toJS()));
$node->addToBlock($blockName, h::js($this->toJS()));
}
/**
@@ -371,7 +389,20 @@ class js extends directive implements \JsonSerializable
{
$js = trim($this->toJS());
if(str_ends_with(';', $js)) $js = substr($js, 0, -1);
return h::jsRaw($js);
return js::raw($js);
}
public static function raw(string ...$codes)
{
$js = implode('<RAWJS_LINE>', $codes);
$js = str_replace(array("\n", '"'), array('<RAWJS_LINE>', '<RAWJS_QUOTE>'), $js);
return "RAWJS<$js>RAWJS";
}
public static function decodeRaw(string $str): string
{
if(!str_contains($str, 'RAWJS')) return $str;
return str_replace(array('<RAWJS_LINE>', '<RAWJS_QUOTE>', '"RAWJS<', '>RAWJS"'), array("\n", '"', '', ''), $str);
}
/**
@@ -389,16 +420,19 @@ class js extends directive implements \JsonSerializable
}
/**
* Encode php value to JSON.
* 将 PHP 值编码为 JSON。
* Encode php value to JS code.
* 将 PHP 值编码为 JS 代码。
*
* @access public
* @param mixed $data PHP value.
* @return string
*/
public static function json($data): string
public static function value(mixed $data): string
{
return h::encodeJsonWithRawJs($data);
$js = \zin\utils\jsonEncode($data, JSON_UNESCAPED_UNICODE);
if(empty($js) && (is_array($data) || is_object($data))) return '[]';
return static::decodeRaw($js);
}
/**
@@ -488,3 +522,8 @@ function js(null|string|js|array ...$codes): js
{
return new js(...$codes);
}
function jsRaw(string ...$codes): string
{
return js::raw(...$codes);
}
+1 -1
View File
@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'zin.func.php';
require_once __DIR__ . DS . 'jshelper.class.php';
/**
+643
View File
@@ -0,0 +1,643 @@
<?php
declare(strict_types=1);
/**
* The base node class file of zin of ZenTaoPMS.
*
* @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
require_once __DIR__ . DS . 'helper.func.php';
require_once __DIR__ . DS . 'props.class.php';
/**
* The base node class.
*/
class node implements \JsonSerializable
{
/**
* Define properties
*
* @access public
* @var array
*/
protected static array $defineProps = array();
/**
* Default properties
*
* @access public
* @var array
*/
protected static array $defaultProps = array();
protected static array $defineBlocks = array();
public string $gid;
public ?node $parent = null;
public props $props;
public array $blocks = array();
public bool $removed = false;
public ?array $buildList = null;
public function __construct(mixed ...$args)
{
$this->gid = 'zin_' . uniqid();
$this->props = new props();
disableGlobalRender();
$this->setDefaultProps(static::getDefaultProps());
$this->add($args);
$this->created();
enableGlobalRender();
renderInGlobal($this);
}
public function __debugInfo(): array
{
return (array)$this->toJSON();
}
public function __toString(): string
{
return $this->render();
}
public function type(): string
{
return get_called_class();
}
public function shortType(): string
{
$type = $this->type();
if(str_contains($type, '\\'))
{
$type = substr($type, strrpos($type, '\\') + 1);
}
return $type;
}
public function id(): ?string
{
return $this->props->get('id');
}
public function displayID(): string
{
$displayID = $this->type() . '~' . $this->gid;
$id = $this->id();
if(!empty($id)) $displayID .= "#$id";
return $displayID;
}
public function prop(array|string $name, mixed $defaultValue = null): mixed
{
if(is_array($name))
{
$values = array();
foreach($name as $index => $propName)
{
$values[] = $this->onGetProp($propName, is_array($defaultValue) ? (isset($defaultValue[$propName]) ? $defaultValue[$propName] : $defaultValue[$index]) : $defaultValue);
}
return $values;
}
return $this->onGetProp($name, $defaultValue);
}
/**
* Set property, an array can be passed to set multiple properties
*
* @access public
* @param props|array|string $prop - Property name or properties list
* @param mixed $value - Property value
*/
public function setProp(props|array|string $prop, mixed $value = null)
{
if($prop instanceof props) $prop = $prop->toJSON();
if(is_array($prop))
{
foreach($prop as $name => $value) $this->setProp($name, $value);
return $this;
}
if(!is_string($prop) || empty($prop)) return $this;
if($prop[0] === '#')
{
$this->add($value, substr($prop, 1));
return $this;
}
$this->onSetProp($prop, $value);
return $this;
}
public function hasProp(): bool
{
$names = func_get_args();
if(empty($names)) return false;
foreach($names as $name)
{
if(!$this->props->has($name)) return false;
}
return true;
}
public function setDefaultProps(string|array $props, mixed $value = null)
{
if(is_string($props)) $props = array($props => $value);
if(!is_array($props) || empty($props)) return;
foreach($props as $name => $value)
{
if($this->props->isset($name)) continue;
$this->setProp($name, $value);
}
}
public function getRestProps(): array
{
return $this->props->skip(array_keys(static::definedPropsList()));
}
public function getDefinedProps(): array
{
return $this->props->pick(array_keys(static::definedPropsList()));
}
public function add($item, string $blockName = 'children')
{
if($item === null || is_bool($item)) return;
if(is_array($item))
{
foreach($item as $child) $this->add($child, $blockName);
return;
}
if(isDirective($item)) $this->directive($item, $blockName);
else $this->addToBlock($blockName, $item);
}
public function addToBlock(string $name, mixed $child)
{
if($child === null || is_bool($child)) return;
if(is_array($child))
{
foreach($child as $blockChild)
{
$this->addToBlock($name, $blockChild);
}
return;
}
if($child instanceof node) $child->parent = $this;
if($name === 'children' && $child instanceof node)
{
$blockName = static::getNameFromBlockMap($child->type());
if($blockName !== null) $name = $blockName;
}
$result = $name === 'children' ? $this->onAddChild($child) : $this->onAddBlock($child, $name);
if($result === false) return;
if($result !== null && $result !== true) $child = $result;
if(isset($this->blocks[$name])) $this->blocks[$name][] = $child;
else $this->blocks[$name] = array($child);
}
public function directive(iDirective $directive, string $blockName = 'children')
{
$directive->parent = $this;
$directive->apply($this, $blockName);
}
public function addChild(mixed $child)
{
return $this->addToBlock('children', $child);
}
public function render(): string
{
if($this->removed) return '';
return renderToHtml(...$this->prebuild());
}
public function prebuild(): array
{
if($this->removed) return array();
if($this->buildList === null)
{
$list = $this->build();
$list = is_array($list) ? $list : array($list);
$list = array_merge($this->buildBefore(), $list, $this->buildAfter());
$this->buildList = $list;
}
return $this->buildList;
}
public function children(): array
{
return $this->block('children');
}
public function block(string $name): array
{
$list = array();
if(isset($this->blocks[$name]))
{
$items = $this->blocks[$name];
foreach($items as $item)
{
if(is_array($item)) $list = array_merge($list, $item);
else $list[] = $item;
}
}
return $list;
}
public function hasBlock(string $name): bool
{
return isset($this->blocks[$name]);
}
/**
* Convert to JSON object.
*
* @access public
* @return object
*/
public function toJSON(): object
{
$json = new stdClass();
$json->gid = $this->gid;
$json->type = $this->shortType();
$json->props = $this->props->toJSON();
$json->blocks = array();
foreach($this->blocks as $key => $block)
{
if($key === 'children')
{
$json->$key = $block;
unset($json->blocks[$key]);
}
else
{
$json->blocks[$key] = $block;
}
}
if(!$json->blocks) unset($json->blocks);
$id = $this->id();
if($id !== null) $json->id = $id;
$parent = $this->parent;
if($parent !== null) $json->parent = $parent->displayID();
if($this->removed) $json->removed = true;
return $json;
}
/**
* Serialized to JSON string.
*
* @access public
* @return string
*/
public function jsonSerialize(): string
{
return json_encode($this->toJSON());
}
/**
* Trigger error in debug mode.
*
* @access public
* @param string $message
* @param int $level
* @return void
*/
public function triggerError(string $message, int $level = E_USER_ERROR)
{
triggerError("{$this->displayID()}: $message", $level);
}
protected function build()
{
return $this->children();
}
protected function buildBefore(): array
{
return $this->block('before');
}
protected function buildAfter(): array
{
return $this->block('after');
}
protected function created()
{
}
protected function onAddChild(mixed $child)
{
return $child;
}
protected function onAddBlock(mixed $child, string $name)
{
return $child;
}
protected function onSetProp(array|string $prop, mixed $value)
{
if($prop === 'id' && $value === '$GID') $value = $this->gid;
$this->props->set($prop, $value);
}
protected function onGetProp(string $prop, mixed $defaultValue): mixed
{
return $this->props->get($prop, $defaultValue);
}
/**
* Check errors in debug mode.
*
* @access protected
* @return void
*/
protected function checkErrors()
{
if(!isDebug()) return;
$definedProps = static::definedPropsList();
foreach($definedProps as $name => $definition)
{
if($this->hasProp($name)) continue;
if(isset($definition['default']) && $definition['default'] !== null) continue;
if(isset($definition['optional']) && $definition['optional']) continue;
$this->triggerError("The value of property \"$name: {$definition['type']}\" is required.");
}
$wgErrors = $this->onCheckErrors();
if(empty($wgErrors)) return;
foreach($wgErrors as $error)
{
if(is_array($error)) $this->triggerError(...$error);
else $this->triggerError($error);
}
}
/**
* The lifecycle method for checking errors in debug mode.
*
* @access protected
* @return array|null
*/
protected function onCheckErrors(): ?array
{
return null;
}
protected static array $definedPropsMap = array();
protected static array $blockMap = array();
public static function getBlockMap(): array
{
$type = get_called_class();
if(!isset(node::$blockMap[$type]))
{
$blockMap = array();
if(is_array(static::$defineBlocks))
{
foreach(static::$defineBlocks as $blockName => $setting)
{
if(!isset($setting['map'])) continue;
$map = $setting['map'];
if(is_string($map)) $map = explode(',', $map);
foreach($map as $name) $blockMap[$name] = $blockName;
}
}
node::$blockMap[$type] = $blockMap;
}
return node::$blockMap[$type];
}
public static function getNameFromBlockMap(string $type): ?string
{
$blockMap = static::getBlockMap();
if(str_starts_with($type, 'zin\\')) $type = substr($type, 4);
return isset($blockMap[$type]) ? $blockMap[$type] : null;
}
public static function definedPropsList(?string $type = null): array
{
if($type === null) $type = get_called_class();
if(!isset(node::$definedPropsMap[$type]) && $type === get_called_class())
{
node::$definedPropsMap[$type] = static::parsePropsDefinition(static::$defineProps);
}
return node::$definedPropsMap[$type];
}
public static function getDefaultProps(?string $type = null): array
{
$defaultProps = array();
foreach(static::definedPropsList($type) as $name => $definition)
{
if(!isset($definition['default'])) continue;
$defaultProps[$name] = $definition['default'];
}
return $defaultProps;
}
/**
* Parse props definition
* @param $definition
* @example
*
* $definition = array('name', 'desc:string', 'title?:string|array', 'icon?:string="star"');
* $definition = array('name' => 'mixed', 'desc' => '?string', 'title' => array('type' => 'string|array', 'optional' => true), 'icon' => array('type' => 'string', 'default' => 'star', 'optional' => true))))
*/
protected static function parsePropsDefinition(array $definition): array
{
$parentClass = get_parent_class(get_called_class());
$parentProps = array();
$defaultProps = static::$defaultProps;
if($parentClass)
{
$parentProps = call_user_func("$parentClass::definedPropsList", $parentClass);
if($defaultProps === $parentClass::$defaultProps)
{
$defaultProps = array();
}
}
return parsePropsMap($definition, $parentProps, $defaultProps);
}
}
function renderToHtml(mixed ...$items): string
{
$html = '';
foreach($items as $item)
{
if(is_array($item))
{
$html .= renderToHtml(...$item);
continue;
}
if($item instanceof node || (is_object($item) && method_exists($item, 'render')))
{
$html .= $item->render();
continue;
}
if(is_object($item) && isset($item->html))
{
$html .= $item->html;
continue;
}
if(!is_string($item)) $item = strval($item);
$html .= htmlspecialchars(strval($item), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, null, false);
}
return $html;
}
/**
* Parse the props definition.
*
* @param array $definition - The props definition.
* @param array $parentProps - The parent props.
* @param array $defaultValues - The default values.
* @return array
*/
function parsePropsMap(array $definition, array $parentProps = array(), array $defaultValues = array())
{
$props = $parentProps;
foreach($definition as $name => $value)
{
$prop = parseProp($value, is_string($name) ? $name : null);
$name = $prop['name'];
if($prop['default'] === null)
{
if(isset($defaultValues[$prop['name']])) $prop['default'] = $defaultValues[$prop['name']];
else if(isset($parentProps[$prop['name']])) $prop['default'] = $parentProps[$prop['name']]['default'];
}
$props[$name] = $prop;
}
return $props;
}
/**
* Parse the prop definition.
*
* @param string|array $definition - The prop definition.
* @param string|null $name - The prop name.
* @param mixed $default - The default value.
* @return array
*/
function parseProp(string|array $definition, ?string $name = null, mixed $default = null)
{
$optional = false;
$type = 'mixed';
if(is_string($definition)) $definition = trim($definition);
/* Parse definition like `'name?: type1|type2="default"'` . */
if(!$name && is_string($definition))
{
if(str_contains($definition, ':'))
{
list($name, $definition) = explode(':', $definition, 2);
}
else
{
$name = $definition;
$definition = '';
}
$name = trim($name);
if(str_ends_with($name, '?'))
{
$name = substr($name, 0, strlen($name) - 1);
$optional = true;
}
}
/* Parse definition like `'name' => '?type1|type2="default"'` . */
if(is_array($definition))
{
if(isset($definition['type'])) $type = $definition['type'];
if(isset($definition['default'])) $default = $definition['default'];
if(isset($definition['optional'])) $optional = $definition['optional'];
}
else if(is_string($definition))
{
if(str_contains($definition, '='))
{
list($type, $default) = explode('=', $definition, 2);
}
else
{
$type = $definition;
}
if(is_string($default)) $default = json_decode(trim($default));
}
$type = trim($type);
if(str_starts_with($type, '?'))
{
$type = substr($type, 1);
$optional = true;
}
$typeList = explode('|', $type);
if(in_array('null', $typeList) || in_array('mixed', $typeList))
{
$optional = true;
}
elseif($optional)
{
array_unshift($typeList, 'null');
}
return array('name' => $name, 'type' => implode('|', $typeList), 'default' => $default, 'optional' => $default !== null || $optional);
}
+8 -8
View File
@@ -12,10 +12,10 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'zin.func.php';
require_once __DIR__ . DS . 'jscallback.class.php';
use zin\wg;
use zin\node;
/**
* Events binding class.
@@ -170,16 +170,16 @@ class on extends jsCallback
}
/**
* Apply to widget.
* Apply to node.
* 应用到部件。
*
* @access public
* @param wg $wg The widget instance.
* @param node $node The node instance.
* @param string $blockName The block name.
* @return void
* @override
*/
public function applyToWg(wg &$wg, string $blockName): void
public function apply(node $node, string $blockName): void
{
if($this->compatible)
{
@@ -187,12 +187,12 @@ class on extends jsCallback
$options['selector'] = $this->selector;
$options['handler'] = parent::buildBody('');
$wg->setProp("@{$this->event}", (object)$options);
$node->setProp("@{$this->event}", (object)$options);
return;
}
$zuiInitCode = $wg->prop('zui-init', '');
$wg->setProp('zui-init', $zuiInitCode . "\n" . $this->toJS());
$zuiInitCode = $node->prop('zui-init', '');
$node->setProp('zui-init', $zuiInitCode . "\n" . $this->toJS());
}
/**
-13
View File
@@ -70,8 +70,6 @@ class props extends \zin\utils\dataset
elseif(str_starts_with($prop, '~')) $this->style->set(substr($prop, 1), $value);
elseif($prop === '--') $this->style->cssVar($value);
elseif(str_starts_with($prop, '--')) $this->style->cssVar(substr($prop, 2), $value);
elseif($prop === '!') $this->hx($value);
elseif(str_starts_with($prop, '!')) $this->hx(substr($prop, 1), $value);
elseif(str_starts_with($prop, ':')) $this->set('data-' . substr($prop, 1), $value);
elseif($prop === '@') $this->bindEvent($value);
elseif(str_starts_with($prop, '@')) $this->bindEvent(substr($prop, 1), $value);
@@ -149,17 +147,6 @@ class props extends \zin\utils\dataset
return false;
}
public function hx(array|string $name, ?string $value = null)
{
if(is_array($name))
{
foreach($name as $key => $val) $this->set("hx-$key", $val);
return;
}
$this->set("hx-$name", $value);
}
/**
* Convert props to html string
*
-23
View File
@@ -1,23 +0,0 @@
<?php
declare(strict_types=1);
/**
* The rawContent class file of zin lib.
*
* @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
require_once __DIR__ . DS . 'wg.class.php';
class rawContent extends wg
{
protected function build(): directive
{
return h::comment('{{RAW_CONTENT}}');
}
}
+7 -6
View File
@@ -27,7 +27,8 @@ require_once __DIR__ . DS . 'hook.class.php';
function render(string $wgName = '', array $options = array())
{
/* 获取全局渲染部件实例和指令。 Get global render widgets and directives. */
$globalItems = zin::getGlobalRenderList();
$context = context();
$globalItems = $context->getGlobalRenderList();
/* 决定部件名称,如果是 Ajax 请求则进行特殊处理。 Decide widget name, if is ajax request, then do special process. */
if(empty($wgName))
@@ -51,17 +52,17 @@ function render(string $wgName = '', array $options = array())
/* 创建部件实例。 Create widget instance. */
$wg = createWg($wgName, $globalItems);
/* 如果不是渲染一个完整页面,则使用 fragment 进行渲染。 If not render in full page, then render all items in a fragment. */
if(!$isFullPage && $wgName !== 'fragment') $wg = fragment($wg);
/* 设置全局根部件。 Set global root widget. */
hook::$globalRoot = $wg;
/* 添加 hooks 内容。Add hooks contents. */
$wg->add(includeHooks());
/* 如果不是渲染一个完整页面,则使用 fragment 进行渲染。 If not render in full page, then render all items in a fragment. */
if(!$isFullPage && $wgName !== 'fragment') $wg = fragment($wg);
/* 渲染并输出 HTML。 Render and display html. */
$wg->display($options);
// $wg->display($options);
zin::$rendered = true;
$context->rendered = true;
}
+123 -5
View File
@@ -12,12 +12,34 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'setting.class.php';
require_once __DIR__ . DS . 'directive.class.php';
require_once __DIR__ . DS . 'context.func.php';
class set
class set extends setting implements iDirective
{
public static function __callStatic($prop, $args)
/**
* Create an instance, the initialed data can be passed.
*
* @access public
* @param array|object|string $data Properties list array.
* @param mixed $value Property value.
*/
public function __construct(array|string $data = null, mixed $value = null)
{
parent::__construct($data, $value);
renderInGlobal($this);
}
public function apply(node $node, string $blockName): void
{
$node->setProp($this->toArray());
}
public static function __callStatic($prop, $args): set
{
$set = new set();
if($prop === 'class' || strtolower($prop) === 'classname')
{
global $config;
@@ -25,13 +47,13 @@ class set
{
trigger_error("[ZIN] Use set::className() instead of set::class() to compatible with php 5.4.", E_USER_WARNING);
}
return directive('prop', array('class' => $args));
return $set->setClass('class', $args);
}
/* Compatible with zui prop className. */
if($prop === '_className')
{
return directive('prop', array('className' => $args));
return $set->setClass('className', $args);
}
/* Support to set url with createLink params. */
@@ -44,6 +66,102 @@ class set
$value = count($args) > 1 ? $args : array_shift($args);
}
return directive('prop', array($prop => $value));
return $set->set($prop, $value);
}
}
/**
* Set widget properties.
*
* @param string|array|props|null $name
* @param mixed $value
* @return set
*/
function set(string|array|props|null $name = null, mixed $value = null): set
{
$set = new set();
if($name === null) return $set;
$props = null;
if($name instanceof props) $props = $name->toArray();
else if(is_array($name)) $props = $name;
else if(is_object($name)) $props = (array)$name;
else if(is_string($name)) $props = array($name => $value);
$set->set($props);
return $set;
}
/**
* Set widget CSS class attribute.
*
* @param mixed ...$class
* @return set
*/
function setClass(mixed ...$class): set
{
return set()->setClass('class', ...$class);
}
/**
* Set widget style attribute.
*
* @return set
*/
function setStyle(array|string $name, ?string $value = null): set
{
return set()->addToMap('style', is_array($name) ? $name : array($name => $value));
}
/**
* Set widget CSS variable.
*
* @return set
*/
function setCssVar(array|string $name, ?string $value = null): set
{
return set()->addToMap('--', is_array($name) ? $name : array($name => $value));
}
/**
* Set widget ID attribute.
*
* @return ?set
*/
function setID(?string $id = null): set
{
return set('id', $id);
}
/**
* Set widget element tag name.
*
* @return set
*/
function setTag(string $id): set
{
return set('tagName', $id);
}
/**
* Set widget data-* attribute.
*
* @param string|array $name
* @param mixed $value
* @return set
*/
function setData(null|string|array $name, mixed $value = null): set
{
if($name === null) return set();
$map = is_array($name) ? $name : array($name => $value);
$attrs = array();
foreach($map as $key => $value)
{
if(is_numeric($key)) $key = (string)$key;
$name = 'data-' . strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $key));
if(is_bool($value)) $attrs[$name] = $value ? 'true' : 'false';
else if(is_array($value)) $attrs[$name] = json_encode($value);
else $attrs[$name] = $value;
}
return set($attrs);
}
+52
View File
@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/**
* The text element class file of zin of ZenTaoPMS.
*
* @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
require_once __DIR__ . DS . 'node.class.php';
require_once __DIR__ . DS . 'directive.class.php';
class text extends node
{
public static array $defineProps = array
(
'html' => '?bool',
);
public function type(): string
{
return 'node::' . $this->shortType();
}
public function shortType(): string
{
return $this->prop('html') ? 'html' : 'text';
}
public function render(): string
{
if($this->prop('html')) return implode('', $this->children());
return parent::render();
}
}
function text(string ...$texts): text
{
return new text(...$texts);
}
function html(string ...$codes): text
{
$text = new text(...$codes);
$text->setProp('html', true);
return $text;
}
+1 -1
View File
@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'wg.func.php';
require_once __DIR__ . DS . 'zin.func.php';
class to
{
+49 -772
View File
@@ -12,645 +12,55 @@ declare(strict_types=1);
namespace zin;
require_once __DIR__ . DS . 'props.class.php';
require_once __DIR__ . DS . 'directive.class.php';
require_once __DIR__ . DS . 'setting.class.php';
require_once __DIR__ . DS . 'zin.class.php';
require_once __DIR__ . DS . 'context.class.php';
require_once __DIR__ . DS . 'selector.func.php';
require_once __DIR__ . DS . 'dom.class.php';
require_once __DIR__ . DS . 'node.class.php';
class wg
class wg extends node
{
/**
* Define props for the element
*
* @var array
*/
protected static array $defineProps = array();
// public function buildEvents(): ?string
// {
// $events = $this->props->events();
// if(empty($events)) return null;
protected static array $defaultProps = array();
// $id = $this->id();
// $code = array($this->shortType() === 'html' ? 'const ele = document;' : 'const ele = document.getElementById("' . (empty($id) ? $this->gid : $id) . '");if(!ele)return;const $ele = $(ele); const events = new Set(($ele.attr("data-zin-events") || "").split(" ").filter(Boolean));');
// foreach($events as $event => $bindingList)
// {
// $code[] = "\$ele.on('$event.on.zin', function(e){";
// foreach($bindingList as $binding)
// {
// if(is_string($binding)) $binding = (object)array('handler' => $binding);
// $selector = isset($binding->selector) ? $binding->selector : null;
// $handler = isset($binding->handler) ? trim($binding->handler) : '';
// $stop = isset($binding->stop) ? $binding->stop : null;
// $prevent = isset($binding->prevent) ? $binding->prevent : null;
// $self = isset($binding->self) ? $binding->self : null;
protected static array $defineBlocks = array();
// $code[] = '(function(){';
// if($selector) $code[] = "const target = e.target.closest('$selector');if(!target) return;";
// else $code[] = "const target = ele;";
// if($self) $code[] = "if(ele !== e.target) return;";
// if($stop) $code[] = "e.stopPropagation();";
// if($prevent) $code[] = "e.preventDefault();";
protected static array $wgToBlockMap = array();
// if(preg_match('/^[$A-Z_][0-9A-Z_$\[\]."\']*$/i', $handler)) $code[] = "($handler).call(target,e);";
// else $code[] = $handler;
protected static array $definedPropsMap = array();
// $code[] = '})();';
// }
// $code[] = "});events.add('$event');";
// }
// $code[] = '$ele.attr("data-zin-events", Array.from(events).join(" "));';
// return h::createJsScopeCode($code);
// }
protected static array $pageResources = array();
/**
* The props of the element
*
* @access public
* @var props
*/
public props $props;
public array $blocks = array();
public ?wg $parent = null;
public string $gid;
public bool $displayed = false;
public bool $removed = false;
protected array $renderOptions = array();
public function __construct(/* string|element|object|array|null ...$args */)
public static function getPageCSS(): ?string
{
$this->props = new props();
$this->gid = 'zin_' . uniqid();
$this->setDefaultProps(static::getDefaultProps());
$this->add(func_get_args());
$this->created();
zin::renderInGlobal($this);
static::checkPageResources();
$this->checkErrors();
return null; // No css
}
public function __debugInfo(): array
public static function getPageJS(): ?string
{
return $this->toJSON();
}
public function isDomElement(): bool
{
return false;
}
/**
* Check if the element is match any of the selectors
* @param string|array|object $selectors
*/
public function isMatch(string|array|object $selectors): bool
{
$list = parseWgSelectors($selectors);
foreach($list as $selector)
{
if(isset($selector->command)) continue;
if(!empty($selector->id) && $this->id() !== $selector->id) continue;
if(!empty($selector->tag) && $this->shortType() !== $selector->tag) continue;
if(!empty($selector->class) && !$this->props->class->has($selector->class)) continue;
return true;
}
return false;
}
/**
* Build dom object
* @return dom
*/
public function buildDom(): dom
{
$before = $this->buildBefore();
$children = $this->build();
$after = $this->buildAfter();
$options = $this->renderOptions;
$selectors = (!empty($options) && isset($options['selector'])) ? $options['selector'] : null;
return new dom
(
$this,
[$before, $children, $after],
$selectors,
(!empty($options) && isset($options['type'])) ? $options['type'] : 'html', // TODO: () may not work in lower php
(!empty($options) && isset($options['data'])) ? $options['data'] : null,
);
}
/**
* Mark widget been removed.
*
* @param string $selector
* @access public
* @return void
*/
public function remove(string $selector = '')
{
if(!empty($selector))
{
$list = $this->find($selector);
foreach($list as $item) $item->remove();
return;
}
$this->removed = true;
}
/**
* Find widgets by selector.
*
* @param string|array|object $selector
* @param string $blockName
* @param bool $nested
* @return array
* @access public
*/
public function find(string|array|object $selector, string $blockName = '', bool $nested = true): array
{
$selectors = parseWgSelectors($selector);
$result = array();
$blocks = empty($blockName) ? $this->blocks : array($blockName => isset($this->blocks[$blockName]) ? $this->blocks[$blockName] : array());
foreach($blocks as $items)
{
foreach($items as $item)
{
if(!($item instanceof wg)) continue;
if($item->isMatch($selectors)) $result[] = $item;
elseif($nested) $result = array_merge($result, $item->find($selectors, '', $nested));
}
}
return $result;
}
/**
* Find children widgets by selector.
*
* @param string $selector
* @return array
* @access public
*/
public function findChildren(string $selector): array
{
return $this->find($selector, 'children', false);
}
/**
* Find first widget by selector.
*
* @param string $selector
* @return wg|null
* @access public
*/
public function first(string $selector = ''): wg | null
{
return reset($this->find($selector));
}
/**
* Find last widget by selector.
*
* @param string $selector
* @return wg|null
* @access public
*/
public function last(string $selector = ''): wg | null
{
return end($this->find($selector));
}
/**
* Render widget to html
* @return string
*/
public function render(): string
{
if($this->removed) return '';
$dom = $this->buildDom();
$result = $dom->render();
return is_string($result) ? $result : json_encode($result);
}
public function display(array $options = array()): wg
{
zin::disableGlobalRender();
$this->renderOptions = $options;
$dom = $this->buildDom();
$result = $dom->render();
$context = context::current();
$css = $context->getCSS();
$js = $context->getJS();
global $app, $config;
$zinDebug = null;
if($config->debug && (!isAjaxRequest() || isAjaxRequest('zin')))
{
$zinDebug = data('zinDebug');
if(is_array($zinDebug))
{
$zinDebug['basePath'] = $app->getBasePath();
if(isset($app->zinErrors)) $zinDebug['errors'] = $app->zinErrors;
}
}
$rawContent = ob_get_contents();
if(!is_string($rawContent)) $rawContent = '';
ob_end_clean();
if(is_object($result))
{
if($zinDebug && isset($result['zinDebug'])) $result['zinDebug'] = $zinDebug;
$result = json_encode($result);
}
elseif(is_array($result))
{
foreach($result as $index => $item)
{
if($item['name'] === 'zinDebug' && $zinDebug)
{
$result[$index]['data'] = $zinDebug;
continue;
}
if(!isset($item['type']) || $item['type'] !== 'html') continue;
$data = $item['data'];
$data = str_replace('/*{{ZIN_PAGE_CSS}}*/', $css, $data);
$data = str_replace('/*{{ZIN_PAGE_JS}}*/', $js, $data);
$data = str_replace('<!-- {{RAW_CONTENT}} -->', $rawContent, $data);
$result[$index]['data'] = $data;
}
$result = json_encode($result, JSON_PARTIAL_OUTPUT_ON_ERROR);
}
else
{
if($zinDebug) $js .= h::createJsVarCode('window.zinDebug', $zinDebug);
$result = str_replace('/*{{ZIN_PAGE_CSS}}*/', $css, $result);
$result = str_replace('/*{{ZIN_PAGE_JS}}*/', $js, $result);
$result = str_replace('<!-- {{RAW_CONTENT}} -->', $rawContent, $result);
}
ob_start();
echo $result;
$this->displayed = true;
context::destroy();
return $this;
}
protected function created() {}
protected function buildBefore(): array
{
return $this->block('before');
}
protected function buildAfter(): array
{
return $this->block('after');
}
protected function build()
{
if($this->removed) return array();
return $this->children();
}
public function buildEvents(): ?string
{
$events = $this->props->events();
if(empty($events)) return null;
$id = $this->id();
$code = array($this->shortType() === 'html' ? 'const ele = document;' : 'const ele = document.getElementById("' . (empty($id) ? $this->gid : $id) . '");if(!ele)return;const $ele = $(ele); const events = new Set(($ele.attr("data-zin-events") || "").split(" ").filter(Boolean));');
foreach($events as $event => $bindingList)
{
$code[] = "\$ele.on('$event.on.zin', function(e){";
foreach($bindingList as $binding)
{
if(is_string($binding)) $binding = (object)array('handler' => $binding);
$selector = isset($binding->selector) ? $binding->selector : null;
$handler = isset($binding->handler) ? trim($binding->handler) : '';
$stop = isset($binding->stop) ? $binding->stop : null;
$prevent = isset($binding->prevent) ? $binding->prevent : null;
$self = isset($binding->self) ? $binding->self : null;
$code[] = '(function(){';
if($selector) $code[] = "const target = e.target.closest('$selector');if(!target) return;";
else $code[] = "const target = ele;";
if($self) $code[] = "if(ele !== e.target) return;";
if($stop) $code[] = "e.stopPropagation();";
if($prevent) $code[] = "e.preventDefault();";
if(preg_match('/^[$A-Z_][0-9A-Z_$\[\]."\']*$/i', $handler)) $code[] = "($handler).call(target,e);";
else $code[] = $handler;
$code[] = '})();';
}
$code[] = "});events.add('$event');";
}
$code[] = '$ele.attr("data-zin-events", Array.from(events).join(" "));';
return h::createJsScopeCode($code);
}
protected function onAddBlock(array|string|wg|directive $child, string $name)
{
return $child;
}
protected function onAddChild(array|string|wg|directive $child)
{
return $child;
}
protected function onSetProp(array|string $prop, mixed $value)
{
if($prop === 'id' && $value === '$GID') $value = $this->gid;
if($prop[0] === '@')
{
$this->setDefaultProps(array('id' => $this->gid));
context::current()->addWgWithEvents($this);
}
$this->props->set($prop, $value);
}
protected function onGetProp(string $prop, mixed $defaultValue): mixed
{
return $this->props->get($prop, $defaultValue);
}
public function add($item, string $blockName = 'children')
{
if($item === null || is_bool($item)) return $this;
if(is_array($item))
{
foreach($item as $child) $this->add($child, $blockName);
return $this;
}
zin::disableGlobalRender();
if($item instanceof setting) $item = $item->toDirective();
if($item instanceof wg) $this->addToBlock($blockName, $item);
elseif(is_string($item)) $this->addToBlock($blockName, htmlspecialchars($item, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, null, false));
elseif(isDirective($item)) $this->directive($item, $blockName);
else $this->addToBlock($blockName, htmlspecialchars(strval($item), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, null, false));
zin::enableGlobalRender();
return $this;
}
public function addToBlock(array|string $name, array|string|null|wg|directive $child = null)
{
if(is_array($name))
{
foreach($name as $blockName => $blockChildren)
{
$this->addToBlock($blockName, $blockChildren);
}
return;
}
if(is_array($child))
{
foreach($child as $blockChild)
{
$this->addToBlock($name, $blockChild);
}
return;
}
if($child instanceof wg && empty($child->parent)) $child->parent = &$this;
if($name === 'children' && $child instanceof wg)
{
$blockName = static::getBlockNameForWg($child);
if($blockName !== null) $name = $blockName;
}
$result = $name === 'children' ? $this->onAddChild($child) : $this->onAddBlock($child, $name);
if($result === false) return;
if($result !== null && $result !== true) $child = $result;
if(isset($this->blocks[$name])) $this->blocks[$name][] = $child;
else $this->blocks[$name] = array($child);
}
public function children(): array
{
return $this->block('children');
}
public function block(string $name): array
{
$list = array();
if(isset($this->blocks[$name]))
{
$items = $this->blocks[$name];
foreach($items as $item)
{
$isWg = $item instanceof wg && $item->shortType() === 'wg';
$item = $isWg ? $item->children() : $item;
if(is_array($item)) $list = array_merge($list, $item);
else $list[] = $item;
}
}
return $list;
}
public function hasBlock(string $name): bool
{
return isset($this->blocks[$name]);
}
/**
* Apply directive
*/
public function directive(directive &$directive, string $blockName)
{
$directive->parent = &$this;
$directive->applyToWg($this, $blockName);
}
public function prop(array|string $name, mixed $defaultValue = null): mixed
{
if(is_array($name))
{
$values = array();
foreach($name as $index => $propName)
{
$values[] = $this->onGetProp($propName, is_array($defaultValue) ? (isset($defaultValue[$propName]) ? $defaultValue[$propName] : $defaultValue[$index]) : $defaultValue);
}
return $values;
}
return $this->onGetProp($name, $defaultValue);
}
/**
* Set property, an array can be passed to set multiple properties
*
* @access public
* @param props|array|string $prop - Property name or properties list
* @param mixed $value - Property value
*/
public function setProp(props|array|string $prop, mixed $value = null)
{
if($prop instanceof props) $prop = $prop->toJSON();
if(is_array($prop))
{
foreach($prop as $name => $value) $this->setProp($name, $value);
return $this;
}
if(!is_string($prop) || empty($prop)) return $this;
if($prop[0] === '#')
{
$this->add($value, substr($prop, 1));
return $this;
}
$this->onSetProp($prop, $value);
return $this;
}
public function hasProp(): bool
{
$names = func_get_args();
if(empty($names)) return false;
foreach($names as $name)
{
if(!$this->props->has($name)) return false;
}
return true;
}
public function setDefaultProps(array $props)
{
if(!is_array($props) || empty($props)) return;
foreach($props as $name => $value)
{
if($this->props->has($name)) continue;
$this->setProp($name, $value);
}
}
public function getRestProps(): array
{
return $this->props->skip(array_keys(static::definedPropsList()));
}
public function getDefinedProps(): array
{
return $this->props->pick(array_keys(static::definedPropsList()));
}
public function type(): string
{
return get_called_class();
}
public function shortType(): string
{
$type = $this->type();
$pos = strrpos($type, '\\');
return $pos === false ? $type : substr($type, $pos + 1);
}
public function id(): ?string
{
return $this->prop('id');
}
public function toJSON(): array
{
$data = array();
$data['gid'] = $this->gid;
$data['id'] = $this->id();
$data['removed'] = $this->removed;
$data['props'] = $this->props->toJSON();
$data['type'] = $this->type();
if(str_starts_with($data['type'], 'zin\\')) $data['type'] = substr($data['type'], 4);
$data['blocks'] = array();
foreach($this->blocks as $key => $value)
{
foreach($value as $index => $child)
{
if($child instanceof wg || (is_object($child) && method_exists($child, 'toJSON')))
{
$value[$index] = $child->toJSON();
}
elseif(isDirective($child, 'html'))
{
$value[$index] = $child->data;
}
}
if($key === 'children')
{
unset($data['blocks'][$key]);
$data['children'] = $value;
}
else
{
$data['blocks'][$key] = $value;
}
}
if(empty($data['blocks'])) unset($data['blocks']);
if(!empty($this->parent)) $data['parent'] = $this->parent->gid;
return $data;
}
/**
* Check errors in debug mode.
*
* @access protected
* @return void
*/
protected function checkErrors()
{
global $config;
if(!isset($config->debug) || !$config->debug) return;
$definedProps = static::definedPropsList();
foreach($definedProps as $name => $definition)
{
if($this->hasProp($name)) continue;
if(isset($definition['default']) && $definition['default'] !== null) continue;
if(isset($definition['optional']) && $definition['optional']) continue;
trigger_error("[ZIN] The property \"$name: {$definition['type']}\" of widget \"{$this->type()}#$this->gid\" is required.", E_USER_ERROR);
}
$wgErrors = $this->onCheckErrors();
if(empty($wgErrors)) return;
foreach($wgErrors as $error)
{
if(is_array($error)) trigger_error("[ZIN] $error[0]", count($error) > 1 ? $error[1] : E_USER_WARNING);
else trigger_error("[ZIN] $error", E_USER_ERROR);
}
}
/**
* The lifecycle method for checking errors in debug mode.
*
* @access protected
* @return array|null
*/
protected function onCheckErrors(): array|null
{
return null;
}
public static function getPageCSS(): string|false
{
return false; // No css
}
public static function getPageJS(): string|false
{
return false; // No js
return null; // No js
}
protected static function checkPageResources()
@@ -667,148 +77,15 @@ class wg
if(!empty($pageJS)) context::js($pageJS);
}
public static function wgBlockMap(): array
{
$wgName = get_called_class();
if(!isset(wg::$wgToBlockMap[$wgName]))
{
$wgBlockMap = array();
if(!empty(static::$defineBlocks))
{
foreach(static::$defineBlocks as $blockName => $setting)
{
if(!isset($setting['map'])) continue;
$map = $setting['map'];
if(is_string($map)) $map = explode(',', $map);
foreach($map as $name) $wgBlockMap[$name] = $blockName;
}
}
wg::$wgToBlockMap[$wgName] = $wgBlockMap;
}
return wg::$wgToBlockMap[$wgName];
}
public static function getBlockNameForWg(wg|string $wg): ?string
{
$wgType = ($wg instanceof wg) ? $wg->type() : $wg;
$wgBlockMap = static::wgBlockMap();
if(str_starts_with($wgType, 'zin\\')) $wgType = substr($wgType, 4);
return isset($wgBlockMap[$wgType]) ? $wgBlockMap[$wgType] : null;
}
protected static function definedPropsList(?string $wgName = null): array
{
if($wgName === null) $wgName = get_called_class();
if(!isset(wg::$definedPropsMap[$wgName]) && $wgName === get_called_class())
{
wg::$definedPropsMap[$wgName] = static::parsePropsDefinition(static::$defineProps);
}
return wg::$definedPropsMap[$wgName];
}
protected static function getDefaultProps(?string $wgName = null): array
{
$defaultProps = array();
foreach(static::definedPropsList($wgName) as $name => $definition)
{
if(!isset($definition['default'])) continue;
$defaultProps[$name] = $definition['default'];
}
return $defaultProps;
}
/**
* Parse props definition
* @param $definition
* @example
*
* $definition = array('name', 'desc:string', 'title?:string|element', 'icon?:string="star"');
* $definition = array('name' => 'mixed', 'desc' => 'string', 'title' => array('type' => 'string|element', 'optional' => true), 'icon' => array('type' => 'string', 'default' => 'star', 'optional' => true))))
*/
private static function parsePropsDefinition(array $definition): array
{
$parentClass = get_parent_class(get_called_class());
/**
* @var array
*/
$props = $parentClass ? call_user_func("$parentClass::definedPropsList") : array();
if($parentClass !== false && $definition === $parentClass::$defineProps)
{
if(!empty(static::$defaultProps) && static::$defaultProps !== $parentClass::$defaultProps)
{
foreach($props as $name => $value)
{
if(isset(static::$defaultProps[$name]))
{
$value['default'] = static::$defaultProps[$name];
$props[$name] = $value;
}
}
}
return $props;
}
foreach($definition as $name => $value)
{
$optional = false;
$type = 'mixed';
$default = (isset($props[$name]) && isset($props[$name]['default'])) ? $props[$name]['default'] : null;
if(is_int($name) && is_string($value))
{
$value = trim($value);
if(!str_contains($value, ':'))
{
$name = $value;
$value = '';
}
else
{
list($name, $value) = explode(':', $value, 2);
}
$name = trim($name);
if($name[strlen($name) - 1] === '?')
{
$name = substr($name, 0, strlen($name) - 1);
$optional = true;
}
}
if(is_array($value))
{
$type = isset($value['type']) ? $value['type'] : $type;
$default = isset($value['default']) ? $value['default'] : $default;
$optional = isset($value['optional'])? $value['optional']: $optional;
}
else if(is_string($value))
{
if(!str_contains($value, '='))
{
$type = $value;
$default = null;
}
else
{
list($type, $default) = explode('=', $value, 2);
}
$type = trim($type);
if(is_string($default)) $default = json_decode(trim($default));
}
$props[$name] = array('type' => empty($type) ? 'mixed' : $type, 'default' => $default, 'optional' => $default !== null || $optional);
}
if(static::$defaultProps && (!$parentClass || static::$defaultProps !== $parentClass::$defaultProps))
{
foreach(static::$defaultProps as $name => $value)
{
if(!isset($props[$name])) continue;
$props[$name]['default'] = $value;
}
}
return $props;
}
protected static array $pageResources = array();
}
/**
* Create an new widget.
*
* @return wg
*/
function wg(mixed ...$args): wg
{
return new wg(...$args);
}
-290
View File
@@ -1,290 +0,0 @@
<?php
declare(strict_types=1);
/**
* The widget function file of zin module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author sunhao<sunhao@easycorp.ltd>
* @package zin
* @link http://www.zentao.net
*/
namespace zin;
require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php';
require_once __DIR__ . DS . 'loader.func.php';
require_once __DIR__ . DS . 'props.class.php';
require_once __DIR__ . DS . 'directive.class.php';
require_once __DIR__ . DS . 'setting.class.php';
require_once __DIR__ . DS . 'rawcontent.class.php';
require_once __DIR__ . DS . 'wg.class.php';
require_once __DIR__ . DS . 'context.func.php';
require_once __DIR__ . DS . 'on.class.php';
require_once __DIR__ . DS . 'jquery.class.php';
/**
* Create an new widget.
*
* @return wg
*/
function wg(): wg
{
return new wg(func_get_args());
}
/**
* Set widget properties.
*
* @param string|array|props|null $name
* @param mixed $value
* @return directive|null
*/
function set(string|array|props|null $name, mixed $value = null): ?directive
{
if($name === null) return null;
$props = null;
if($name instanceof props) $props = $name;
else if(is_array($name)) $props = $name;
else if(is_object($name)) $props = (array)$name;
else if(is_string($name)) $props = array($name => $value);
return $props ? directive('prop', $props) : null;
}
/**
* Set widget CSS class attribute.
*
* @param array|string|null ...$classList
* @return directive
*/
function setClass(/* array|string|null ...$classList */): directive
{
return directive('class', func_get_args());
}
/**
* Set widget style attribute.
*
* @return directive
*/
function setStyle(array|string $name, ?string $value = null): directive
{
return directive('style', is_array($name) ? $name : array($name => $value));
}
/**
* Set widget CSS variable.
*
* @return directive
*/
function setCssVar(array|string $name, ?string $value = null): directive
{
return directive('cssVar', is_array($name) ? $name : array($name => $value));
}
/**
* Set widget ID attribute.
*
* @return ?directive
*/
function setID(?string $id = null): directive
{
return set('id', $id);
}
/**
* Set widget element tag name.
*
* @return directive
*/
function setTag(string $id): directive
{
return set('tagName', $id);
}
/**
* Set widget data-* attribute.
*
* @param string|array $name
* @param mixed $value
* @return directive
*/
function setData(null|string|array $name, mixed $value = null): ?directive
{
if($name === null) return null;
$map = is_array($name) ? $name : array($name => $value);
$attrs = array();
foreach($map as $key => $value)
{
if(is_numeric($key)) $key = (string)$key;
$name = 'data-' . strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $key));
if(is_bool($value)) $attrs[$name] = $value ? 'true' : 'false';
else if(is_array($value)) $attrs[$name] = json_encode($value);
else $attrs[$name] = $value;
}
return set($attrs);
}
/**
* Create html content.
*
* @param string ...$lines
* @return directive
*/
function html(/* string ...$lines */): directive
{
return directive('html', implode("\n", \zin\utils\flat(func_get_args())));
}
/**
* Create text content.
*
* @param string ...$lines
* @return directive
*/
function text(/* string ...$lines */): directive
{
return directive('text', implode("\n", \zin\utils\flat(func_get_args())));
}
/**
* Create block content.
*
* @param string $name
* @param mixed ...$wgs
* @return directive
*/
function to(/* string $name, mixed ...$wgs */): directive
{
$args = func_get_args();
$name = array_shift($args);
$wg = new wg(count($args) > 1 ? $args : $args[0]);
return directive('block', array($name => $wg));
}
/**
* Create content for block "before".
*
* @param string $wgs
* @return directive
*/
function before(/* mixed ...$wgs */): directive
{
return to('before', func_get_args());
}
/**
* Create content for block "after".
*
* @param string $wgs
* @return directive
*/
function after(): directive
{
return to('after', func_get_args());
}
/**
* Create widget contents inherited from the given widget.
*
* @param wg|array $item
* @return array
*/
function inherit(wg|array $item): array
{
if(!($item instanceof wg)) $item = new wg($item);
return array(set($item->props), directive('block', $item->blocks), $item->children());
}
/**
* Divorce widget from parent.
*
* @param wg|array $item
* @return array
*/
function divorce(wg|array $item): wg|array
{
if($item instanceof wg)
{
$item->parent = null;
}
else if(is_array($item))
{
foreach($item as $i) divorce($i);
}
return $item;
}
/**
* Check if the given widget list has the given widget type.
*
* @param wg|array $items
* @param string $type
* @return bool
*/
function hasWgInList(wg|array $items, string $type): bool
{
if(!is_array($items)) $items = array($items);
foreach($items as $item)
{
if($item instanceof wg && $item->type() == $type) return true;
}
return false;
}
/**
* Group widgets by type.
*
* @param wg|array $items
* @param string $types
* @return array
*/
function groupWgInList(wg|array $items, string|array $types): array
{
if(is_string($types)) $types = explode(',', $types);
$typesMap = array();
$restList = array();
foreach($types as $type) $typesMap[$type] = array();
foreach($items as $item)
{
if(!($item instanceof wg)) continue;
$type = $item->shortType();
if(isset($typesMap[$type])) $typesMap[$type][] = $item;
else $restList[] = $item;
}
$groups = array();
foreach($types as $index => $type) $groups[] = $typesMap[$type];
$groups[] = $restList;
return $groups;
}
/**
* Create raw content placeholder.
*
* @return rawContent
*/
function rawContent(): rawContent
{
zin::$rawContentCalled = true;
return new rawContent();
}
/**
* Include hooks files.
*/
function includeHooks()
{
$hookFiles = context::current()->getHookFiles();
ob_start();
foreach($hookFiles as $hookFile)
{
if(!empty($hookFile) && file_exists($hookFile)) include $hookFile;
}
$hookCode = ob_get_clean();
return html($hookCode);
}
+140
View File
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
/**
* The widget function file of zin module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author sunhao<sunhao@easycorp.ltd>
* @package zin
* @link http://www.zentao.net
*/
namespace zin;
require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php';
require_once __DIR__ . DS . 'loader.func.php';
require_once __DIR__ . DS . 'node.class.php';
require_once __DIR__ . DS . 'text.class.php';
require_once __DIR__ . DS . 'props.class.php';
require_once __DIR__ . DS . 'directive.class.php';
require_once __DIR__ . DS . 'setting.class.php';
require_once __DIR__ . DS . 'set.class.php';
require_once __DIR__ . DS . 'wg.class.php';
require_once __DIR__ . DS . 'h.class.php';
require_once __DIR__ . DS . 'h.func.php';
require_once __DIR__ . DS . 'item.class.php';
require_once __DIR__ . DS . 'to.class.php';
require_once __DIR__ . DS . 'context.func.php';
require_once __DIR__ . DS . 'on.class.php';
require_once __DIR__ . DS . 'jquery.class.php';
/**
* Create block content.
*
* @param string $name
* @param mixed ...$args
* @return directive
*/
function to(string $blockName, mixed ...$args): directive
{
$node = new node(...$args);
return directive('block', array($blockName => $node));
}
/**
* Create content for block "before".
*
* @param string $args
* @return directive
*/
function before(mixed ...$args): directive
{
return to('before', ...$args);
}
/**
* Create content for block "after".
*
* @param string $args
* @return directive
*/
function after(mixed ...$args): directive
{
return to('after', ...$args);
}
/**
* Create widget contents inherited from the given widget.
*
* @param node|array $item
* @return array
*/
function inherit(node|array $item): array
{
if(!($item instanceof node)) $item = new node($item);
return array(set($item->props), directive('block', $item->blocks), $item->children());
}
/**
* Divorce widget from parent.
*
* @param node|array $item
* @return array
*/
function divorce(node|array $item): node|array
{
if($item instanceof node)
{
$item->parent = null;
}
else if(is_array($item))
{
foreach($item as $i) divorce($i);
}
return $item;
}
/**
* Group widgets by type.
*
* @param wg|array $items
* @param string $types
* @return array
*/
function groupWgInList(wg|array $items, string|array $types): array
{
if(is_string($types)) $types = explode(',', $types);
$typesMap = array();
$restList = array();
foreach($types as $type) $typesMap[$type] = array();
foreach($items as $item)
{
if(!($item instanceof wg)) continue;
$type = $item->shortType();
if(isset($typesMap[$type])) $typesMap[$type][] = $item;
else $restList[] = $item;
}
$groups = array();
foreach($types as $index => $type) $groups[] = $typesMap[$type];
$groups[] = $restList;
return $groups;
}
/**
* Include hooks files.
*/
function includeHooks()
{
$hookFiles = context::current()->getHookFiles();
ob_start();
foreach($hookFiles as $hookFile)
{
if(!empty($hookFile) && file_exists($hookFile)) include $hookFile;
}
$hookCode = ob_get_clean();
return html($hookCode);
}
+143 -1888
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -18,12 +18,12 @@ class aclBox extends wg
'userValue?: string=""', // 用户组默认选中值。
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
protected function build(): wg
protected function build()
{
list($aclItems, $aclValue, $whitelistLabel, $groupLabel, $userLabel, $groupName, $userName, $groupItems, $groupValue, $userValue) = $this->prop(array('aclItems', 'aclValue', 'whitelistLabel', 'groupLabel', 'userLabel', 'groupName', 'userName', 'groupItems', 'groupValue', 'userValue'));
+1 -1
View File
@@ -126,7 +126,7 @@ class actionItem extends wg
);
}
protected function build(): wg
protected function build()
{
list($name, $type, $outerTag, $outerProps, $outerClass) = $this->prop(array('name', 'type', 'outerTag', 'outerProps', 'outerClass'));
+1 -1
View File
@@ -38,7 +38,7 @@ class avatar extends wg
return $child;
}
protected function build(): wg
protected function build()
{
/* Attach classes. */
$this->finalClass[] = $this->prop('className');
+2 -2
View File
@@ -8,12 +8,12 @@ class batchActions extends wg
'actionClass?: string=""',
);
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg
protected function build()
{
return formGroup
(
+1 -1
View File
@@ -90,7 +90,7 @@ class btn extends wg
return $classList;
}
protected function build(): wg
protected function build()
{
$props = $this->getProps();
$children = $this->getChildren();
+1 -1
View File
@@ -28,7 +28,7 @@ class btnGroup extends wg
return $className;
}
protected function build(): wg
protected function build()
{
$items = $this->prop('items');
$className = $this->getclassName();
+1 -1
View File
@@ -13,7 +13,7 @@ class cell extends wg
'align?: string' // align-self 属性,例如 'auto'、'flex-start'、'flex-end'、'center'、'baseline'、'stretch'。
);
protected function build(): wg
protected function build()
{
$basis = null;
$class = array('cell');
+1 -1
View File
@@ -4,7 +4,7 @@ namespace zin;
class center extends wg
{
protected function build(): wg
protected function build()
{
return div
(
+1 -1
View File
@@ -55,7 +55,7 @@ class checkbox extends wg
);
}
protected function build(): wg
protected function build()
{
if($this->prop('primary')) return $this->buildPrimary();
list($text, $type, $typeClass) = $this->prop(array('text', 'type', 'typeClass'));
+4 -4
View File
@@ -14,12 +14,12 @@ class checkboxGroup extends wg
'disabled' => false
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
@@ -30,7 +30,7 @@ class checkboxGroup extends wg
return checkbox(set($title), setClass('checkbox-title'));
}
private function buildCheckboxList(): wg
private function buildCheckboxList(): node
{
$items = $this->prop('items');
$title = array_merge(self::$checkboxProps, $this->prop('title'));
@@ -52,7 +52,7 @@ class checkboxGroup extends wg
return $list;
}
public function build(): wg
public function build()
{
return div
(
+1 -1
View File
@@ -6,7 +6,7 @@ require_once dirname(__DIR__) . DS . 'checkbox' . DS . 'v1.php';
class checkBtn extends checkbox
{
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return <<<CSS
.check-btn > input + label {color: var(--color-gray-500)}
+2 -2
View File
@@ -13,7 +13,7 @@ class checkBtnGroup extends checkList
'type' => 'radio'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return <<<CSS
.check-btn-group {gap: 1px; border: 1px solid var(--form-control-border); padding: 0; border-radius: var(--radius)}
@@ -30,7 +30,7 @@ class checkBtnGroup extends checkList
return new checkBtn(set($props));
}
protected function build(): wg
protected function build()
{
$div = parent::build();
$div->add(setClass('check-btn-group'));
+2 -2
View File
@@ -6,7 +6,7 @@ require_once dirname(__DIR__) . DS . 'checkbtngroup' . DS . 'v1.php';
class checkColorGroup extends checkBtnGroup
{
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return <<<CSS
.check-btn-group {gap: 1px; padding: 0; border-radius: var(--radius); margin-top: 4px;}
@@ -25,7 +25,7 @@ class checkColorGroup extends checkBtnGroup
return parent::buildItem($props);
}
protected function build(): wg
protected function build()
{
return parent::build();
}
+1 -1
View File
@@ -49,7 +49,7 @@ class checkList extends wg
return new checkbox(set($props));
}
protected function build(): wg
protected function build()
{
list($items, $inline, $disabled, $className) = $this->prop(array('items', 'inline', 'disabled', 'className'));
+1 -1
View File
@@ -9,7 +9,7 @@ class col extends wg
'align?:string'
);
protected function build(): wg
protected function build()
{
$classList = 'col';
list($justify, $align) = $this->prop(array('justify', 'align'));
+1 -1
View File
@@ -11,7 +11,7 @@ class collapseBtn extends wg
'parent: string' // 目标元素与按钮共同的父级元素选择器,使用 closest 辅助目标元素的确定。
);
protected function build(): wg
protected function build()
{
$target = $this->prop('target');
$parent = $this->prop('parent');
+1 -1
View File
@@ -44,7 +44,7 @@ class colorInput extends inputControl
*
* @access protected
*/
protected function build(): wg
protected function build()
{
list($id, $name, $value, $inputClass, $colorName, $colorValue, $syncColor) = $this->prop(array('id', 'name', 'value', 'inputClass', 'colorName', 'colorValue', 'syncColor'));
+1 -1
View File
@@ -57,7 +57,7 @@ class colorPicker extends wg
*
* @access protected
*/
protected function build(): wg
protected function build()
{
list($props, $restProps) = $this->props->split(array_keys(static::definedPropsList()));
if(isset($props['id']))
+1 -1
View File
@@ -13,7 +13,7 @@ class commentDialog extends wg
'load?: bool|string'
);
protected function build(): wg
protected function build()
{
global $lang;
$id = $this->prop('id');
+1 -1
View File
@@ -12,7 +12,7 @@ class commentForm extends wg
'method?:string="POST"'
);
protected function build(): wg
protected function build()
{
global $lang;
$url = $this->prop('url');
+2 -2
View File
@@ -20,7 +20,7 @@ class contactList extends wg
'placeholder?: string', // picker 占位符。
);
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
@@ -45,7 +45,7 @@ class contactList extends wg
}
}
protected function build(): wg|array
protected function build()
{
global $app, $lang;
$app->loadLang('user');
+1 -1
View File
@@ -218,7 +218,7 @@ class control extends wg
return new dropdown($this->prop('text'), set($this->props->skip('control,text,name,widget')));
}
protected function build(): wg
protected function build()
{
$builder = $this->prop('builder');
if(is_callable($builder)) return $builder($this->props->skip('builder'), $this->children());
+1 -1
View File
@@ -55,7 +55,7 @@ class dashboard extends wg
/**
* Build widget.
*/
protected function build(): wg
protected function build()
{
return zui::dashboard
(
+1 -1
View File
@@ -65,7 +65,7 @@ class datePicker extends wg
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
list($props, $restProps) = $this->props->split(array_keys(static::definedPropsList()));
if(isset($props['id']))
+1 -1
View File
@@ -112,7 +112,7 @@ class dateRangePicker extends wg
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
$begin = new datePicker(set($this->buildBeginProps()));
$end = new datePicker(set($this->buildEndProps()));
+1 -1
View File
@@ -54,7 +54,7 @@ class datetimePicker extends wg
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
list($props, $restProps) = $this->props->split(array_keys(static::definedPropsList()));
if(isset($props['id']))
+3 -3
View File
@@ -15,17 +15,17 @@ class detailBody extends wg
'floating' => array('map' => 'floatToolbar')
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg
protected function build()
{
$main = $this->block('main');
$side = $this->block('side');
+1 -1
View File
@@ -28,7 +28,7 @@ class detailHeader extends wg
);
}
protected function build(): wg
protected function build()
{
$prefix = $this->block('prefix');
$title = $this->block('title');
+2 -2
View File
@@ -4,7 +4,7 @@ namespace zin;
class detailSide extends wg
{
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return <<<CSS
.detail-side {width: 370px;}
@@ -15,7 +15,7 @@ class detailSide extends wg
CSS;
}
protected function build(): wg
protected function build()
{
return div
(
+1 -1
View File
@@ -4,7 +4,7 @@ namespace zin;
class divider extends wg
{
protected function build(): wg
protected function build()
{
return div
(
+2 -2
View File
@@ -25,12 +25,12 @@ class docMenu extends wg
'hover?: bool=true'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
+1 -1
View File
@@ -47,7 +47,7 @@ class dropmenu extends wg
* @access public
* @return string|false
*/
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
+2 -2
View File
@@ -25,7 +25,7 @@ class dtable extends wg
static $dtableID = 0;
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
@@ -266,7 +266,7 @@ class dtable extends wg
return $setting;
}
protected function build(): wg
protected function build()
{
global $lang, $app;
+2 -2
View File
@@ -10,7 +10,7 @@ class dynamic extends wg
'className?: string'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
@@ -115,7 +115,7 @@ class dynamic extends wg
);
}
protected function build(): wg
protected function build()
{
$users = $this->prop('users', (array)data('users'));
$dynamics = $this->prop('dynamics', (array)data('dynamics'));
+3 -3
View File
@@ -33,12 +33,12 @@ class editor extends wg
.tippy-content zen-editor-menu-item .label {all: unset;}
CSS;
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
$content = file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
$content .= '$.getLib(\'zen-editor/zen-editor.esm.js\', {type: "module"}, () => {document.body.dataset.loadedEditor = true;});';
@@ -75,7 +75,7 @@ class editor extends wg
);
}
protected function build(): wg
protected function build()
{
global $lang;
+2 -2
View File
@@ -23,7 +23,7 @@ class entityLabel extends wg
'suffix' => array()
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
@@ -86,7 +86,7 @@ class entityLabel extends wg
);
}
protected function build(): wg
protected function build()
{
$reverse = $this->prop('reverse');
$prefix = $this->block('prefix');
+1 -1
View File
@@ -143,7 +143,7 @@ class featureBar extends wg
);
}
protected function build(): wg
protected function build()
{
return div
(
+3 -3
View File
@@ -16,12 +16,12 @@ class fileList extends wg
'padding?:bool=true'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
@@ -47,7 +47,7 @@ class fileList extends wg
return $fileListView;
}
protected function build(): wg
protected function build()
{
global $lang;
+1 -1
View File
@@ -76,7 +76,7 @@ class fileSelector extends wg
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
return zui::fileSelector(inherit($this));
}
+1 -1
View File
@@ -82,7 +82,7 @@ class filter extends wg
return $this->buildInput();
}
protected function build(): wg|array
protected function build()
{
$type = $this->prop('type');
$class = $this->prop('class', 'w-1/4');
+3 -3
View File
@@ -9,16 +9,16 @@ class floatPreNextBtn extends wg
'nextLink?:string'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg|array
protected function build()
{
global $app;
$preLink = $this->prop('preLink');
+1 -1
View File
@@ -74,7 +74,7 @@ class floatToolbar extends wg
return array_merge($btns, $block);
}
protected function build(): wg
protected function build()
{
$prefixBtns = $this->buildBtns($this->prop('prefix'));
$mainBtns = $this->buildBtns($this->prop('main'));
+1 -1
View File
@@ -107,7 +107,7 @@ class formBase extends wg
return $after;
}
protected function build(): wg
protected function build()
{
return h::form
(
+1 -1
View File
@@ -136,7 +136,7 @@ class formGroup extends wg
);
}
protected function build(): wg|array
protected function build()
{
list($name, $labelWidth, $required, $width, $id, $hidden, $foldable, $pinned, $children, $wrapBefore, $wrapAfter, $data) = $this->prop(array('name', 'labelWidth', 'required', 'width', 'id', 'hidden', 'foldable', 'pinned', 'children', 'wrapBefore', 'wrapAfter', 'data'));
+2 -2
View File
@@ -14,7 +14,7 @@ class formItemDropdown extends wg
'target?: string'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
@@ -63,7 +63,7 @@ class formItemDropdown extends wg
);
}
protected function build(): wg
protected function build()
{
return div
(
+1 -1
View File
@@ -18,7 +18,7 @@ class formLabel extends wg
'checkbox?: bool|array'
);
protected function build(): wg
protected function build()
{
list($text, $required, $for, $hint, $hintClass, $hintProps, $hintIcon, $actions, $actionsClass, $actionsProps, $checkbox) = $this->prop(array('text', 'required', 'for', 'hint', 'hintClass', 'hintProps', 'hintIcon', 'actions', 'actionsClass', 'actionsProps', 'checkbox'));
+1 -1
View File
@@ -65,7 +65,7 @@ class formPanel extends panel
'customFields?: array=[]' // @deprecated 自定义表单项。
);
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
+1 -1
View File
@@ -23,7 +23,7 @@ class formRow extends wg
return new formGroup(inherit($item));
}
protected function build(): wg
protected function build()
{
list($width, $items, $hidden) = $this->prop(['width', 'items', 'hidden']);
+2 -2
View File
@@ -17,12 +17,12 @@ class formRowGroup extends formRow
'suffix' => array()
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
protected function build(): wg
protected function build()
{
return formRow
(
+3 -3
View File
@@ -19,12 +19,12 @@ class formSettingBtn extends wg
'urlParams' => ''
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
@@ -49,7 +49,7 @@ class formSettingBtn extends wg
return $items;
}
protected function build(): wg
protected function build()
{
$customFields = $this->prop('customFields', array());
+1 -1
View File
@@ -13,7 +13,7 @@ class fragment extends wg
{
$css = array(data('pageCSS'), '/*{{ZIN_PAGE_CSS}}*/');
$js = array('/*{{ZIN_PAGE_JS}}*/', data('pageJS'));
$rawContent = $this->prop('rawContent', !zin::$rawContentCalled);
$rawContent = $this->prop('rawContent', !context()->rawContentCalled);
return array
(
+1 -1
View File
@@ -9,7 +9,7 @@ class gantt extends wg
return file_get_contents(dirname(__DIR__, 4) . '/www/js/dhtmlxgantt/min.css');
}
protected function build(): wg
protected function build()
{
global $app;
$jsFile = $app->getWebRoot() . 'js/dhtmlxgantt/min.js';
+2 -2
View File
@@ -4,12 +4,12 @@ namespace zin;
class globalSearch extends wg
{
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg
protected function build()
{
global $config, $lang;
+1 -1
View File
@@ -64,7 +64,7 @@ class header extends wg
*
* @access protected
*/
protected function build(): wg
protected function build()
{
return h::header
(
+1 -1
View File
@@ -95,7 +95,7 @@ class heading extends wg
*
* @access protected
*/
protected function build(): wg
protected function build()
{
return div
(
+1 -1
View File
@@ -4,7 +4,7 @@ namespace zin;
class hr extends wg
{
protected function build(): wg
protected function build()
{
return h::hr(setClass('my-5'));
}
+1 -1
View File
@@ -18,7 +18,7 @@ class icon extends wg
}
}
protected function build(): wg
protected function build()
{
list($name, $size) = $this->prop(array('name', 'size'));
return h::i
+1 -1
View File
@@ -17,7 +17,7 @@ class imageSelector extends fileSelector
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
return zui::imageSelector(inherit($this));
}
+1 -1
View File
@@ -23,7 +23,7 @@ class input extends wg
'class' => 'form-control'
);
protected function build(): wg
protected function build()
{
$props = $this->props->skip('required');
$required = $this->prop('required');
+1 -1
View File
@@ -19,7 +19,7 @@ class inputControl extends wg
'suffix' => array()
);
protected function build(): wg
protected function build()
{
list($prefix, $suffix, $prefixWidth, $suffixWidth, $class) = $this->prop(array('prefix', 'suffix', 'prefixWidth', 'suffixWidth', 'class'));
+1 -1
View File
@@ -50,7 +50,7 @@ class inputGroup extends wg
return new input(set::type($control), set($item->props->skip('control')));
}
protected function build(): wg
protected function build()
{
list($items, $seg) = $this->prop(['items', 'seg']);
$children = $this->children();
+1 -1
View File
@@ -20,7 +20,7 @@ namespace zin;
*/
class inputGroupAddon extends wg
{
protected function build(): wg
protected function build()
{
return h::span(setClass('input-group-addon'), set($this->props), $this->children());
}
+2 -2
View File
@@ -8,7 +8,7 @@ class label extends wg
'text?:string'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
@@ -22,7 +22,7 @@ class label extends wg
}
}
public function build(): wg
public function build()
{
return span
(
+1 -1
View File
@@ -134,7 +134,7 @@ class main extends wg
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
return div
(
+2 -2
View File
@@ -40,7 +40,7 @@ class mainNavbar extends nav
* @access public
* @return string|false
*/
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
@@ -99,7 +99,7 @@ class mainNavbar extends nav
* @access protected
* @return wg
*/
protected function build(): wg
protected function build()
{
global $app, $config;
+1 -1
View File
@@ -24,7 +24,7 @@ class menu extends wg
/**
* @return builder
*/
protected function build(): wg
protected function build()
{
$items = $this->prop('items');
return h::menu
+1 -1
View File
@@ -15,7 +15,7 @@ class modal extends modalDialog
'modalProps' => array()
);
protected function build(): wg
protected function build()
{
list($id, $modalProps) = $this->prop(array('id', 'modalProps'));
+2 -2
View File
@@ -88,7 +88,7 @@ class modalDialog extends wg
protected function buildBody()
{
$rawContent = $this->prop('rawContent', !zin::$rawContentCalled);
$rawContent = $this->prop('rawContent', !context()->rawContentCalled);
return div
(
setClass('modal-body scrollbar-hover', $this->prop('bodyClass')),
@@ -125,7 +125,7 @@ class modalDialog extends wg
return "$objectType:$objectID";
}
protected function build(): wg
protected function build()
{
return div
(
+1 -1
View File
@@ -34,7 +34,7 @@ class modalHeader extends wg
$this->setDefaultProps(array('title' => $title, 'entityText' => $entityText, 'entityID' => $entityID));
}
protected function build(): wg|array
protected function build()
{
list($title, $entityText, $entityID, $inModal) = $this->prop(array('title', 'entityText', 'entityID', 'inModal'));
if(empty($inModal)) $inModal = false;
+2 -2
View File
@@ -9,12 +9,12 @@ class modalNextStep extends wg
'items: array'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
protected function build(): wg
protected function build()
{
$tip = $this->prop('tip');
$items = $this->prop('items');
+1 -1
View File
@@ -24,7 +24,7 @@ class moduleMenu extends wg
'onCheck?: function'
);
public static function getPageCSS(): string|false
public static function getPageCSS(): ?string
{
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
}
+2 -2
View File
@@ -22,12 +22,12 @@ class modulePicker extends wg
'manageLink?: string' // 维护模块链接
);
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg|array
protected function build()
{
global $app, $lang;
$app->loadLang('tree');
+2 -2
View File
@@ -20,12 +20,12 @@ class monaco extends wg
'onMouseDown' => '',
'onMouseMouse' => ''
);
public static function getPageJS(): string|false
public static function getPageJS(): ?string
{
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
}
protected function build(): wg
protected function build()
{
global $app;
$vsPath = $app->getWebRoot() . 'js/monaco-editor/min/vs';
+1 -1
View File
@@ -23,7 +23,7 @@ class nav extends wg
);
}
protected function build(): wg
protected function build()
{
list($items, $type, $stacked, $justified) = $this->prop(array('items', 'type', 'stacked', 'justified'));
return h::menu
+1 -1
View File
@@ -291,7 +291,7 @@ class navbar extends wg
*
* @access protected
*/
protected function build(): wg
protected function build()
{
return h::nav
(

Some files were not shown because too many files have changed in this diff Show More