diff --git a/config/actionsmap.php b/config/actionsmap.php new file mode 100644 index 0000000000..3331a57e6e --- /dev/null +++ b/config/actionsmap.php @@ -0,0 +1,34 @@ +actionsMap = new stdclass(); + +/* Normal. */ +$config->actionsMap->icon = new stdclass(); +$config->actionsMap->icon->start = 'icon-start'; +$config->actionsMap->icon->suspend = 'icon-pause'; +$config->actionsMap->icon->close = 'icon-off'; +$config->actionsMap->icon->activate = 'icon-magic'; +$config->actionsMap->icon->edit = 'icon-edit'; +$config->actionsMap->icon->create = 'icon-split'; +$config->actionsMap->icon->delete = 'icon-trash'; +$config->actionsMap->icon->team = 'icon-group'; +$config->actionsMap->icon->group = 'icon-lock'; +$config->actionsMap->icon->link = 'icon-link'; +$config->actionsMap->icon->whitelist = 'icon-shield-check'; +$config->actionsMap->icon->delete = 'icon-trash'; + +/* Other. */ +$config->actionsMap->other = new stdclass(); +$config->actionsMap->other->type = 'dropdown'; +$config->actionsMap->other->caret = true; + +$config->actionsMap->other->dropdown = new stdclass(); +$config->actionsMap->other->dropdown->placement = 'bottom-end'; + +/* More. */ +$config->actionsMap->more = new stdclass(); +$config->actionsMap->more->type = 'dropdown'; +$config->actionsMap->more->icon = 'icon-ellipsis-v'; +$config->actionsMap->more->caret = false; + +$config->actionsMap->more->dropdown = new stdclass(); +$config->actionsMap->more->dropdown->placement = 'bottom-end'; diff --git a/config/config.php b/config/config.php index 0825ec893f..4095dbba33 100644 --- a/config/config.php +++ b/config/config.php @@ -179,6 +179,10 @@ if(file_exists($myConfig)) include $myConfig; $zentaopmsConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'zentaopms.php'; if(file_exists($zentaopmsConfig)) include $zentaopmsConfig; +/* 数据表格操作配置文件。dtable actions settings. */ +$actionsMapConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'actionsmap.php'; +if(file_exists($actionsMapConfig)) include $actionsMapConfig; + /* API路由配置。API route settings. */ $routesConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'routes.php'; if(file_exists($routesConfig)) include $routesConfig; diff --git a/config/zentaopms.php b/config/zentaopms.php index c7d8450900..72336b593c 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -458,6 +458,9 @@ $config->maxPriValue = '256'; $config->importWhiteList = array('user', 'task', 'story', 'bug', 'testcase', 'feedback', 'ticket'); +$config->dtable = new stdclass(); +$config->dtable->colVars = array('width', 'minWidth', 'type', 'flex', 'fixed', 'sortType', 'checkbox', 'nestedToggle', 'statusMap', 'actionsMap', 'group'); + $config->featureGroup = new stdclass(); $config->featureGroup->my = array('score'); $config->featureGroup->product = array('roadmap', 'track', 'UR'); diff --git a/framework/base/control.class.php b/framework/base/control.class.php index 25dc9fc83d..13884ef2d7 100644 --- a/framework/base/control.class.php +++ b/framework/base/control.class.php @@ -393,19 +393,20 @@ class baseControl * * @param string $moduleName module name * @param string $methodName method name + * @param string $viewDir * @access public * @return string the view file */ - public function setViewFile($moduleName, $methodName) + public function setViewFile($moduleName, $methodName, $viewDir = 'view') { $moduleName = strtolower(trim($moduleName)); $methodName = strtolower(trim($methodName)); $modulePath = $this->app->getModulePath($this->appName, $moduleName); - $viewExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, 'view'); + $viewExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, $viewDir); $viewType = $this->viewType == 'mhtml' ? 'html' : $this->viewType; - $mainViewFile = $modulePath . 'view' . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php'; + $mainViewFile = $modulePath . $viewDir . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php'; $viewFile = $mainViewFile; if(!empty($viewExtPath)) @@ -470,7 +471,7 @@ class baseControl * @access public * @return string */ - public function getCSS($moduleName, $methodName) + public function getCSS($moduleName, $methodName, $suffix = '') { $moduleName = strtolower(trim($moduleName)); $methodName = strtolower(trim($methodName)); @@ -486,21 +487,21 @@ class baseControl $mainCssPath = $modulePath . 'css' . DS; /* Common css file. like module/story/css/common.css. */ - $mainCssFile = $mainCssPath . $devicePrefix . 'common.css'; + $mainCssFile = $mainCssPath . $devicePrefix . "common{$suffix}.css"; if(is_file($mainCssFile)) $css .= file_get_contents($mainCssFile); /* Common css file with lang. like module/story/css/common.en.css. */ - $mainCssLangFile = $mainCssPath . $devicePrefix . "common.{$clientLang}.css"; + $mainCssLangFile = $mainCssPath . $devicePrefix . "common.{$clientLang}{$suffix}.css"; if(!file_exists($mainCssLangFile) and $notCNLang) $mainCssLangFile = $mainCssPath . $devicePrefix . "common.en.css"; if(is_file($mainCssLangFile)) $css .= file_get_contents($mainCssLangFile); /* Method css file. like module/story/css/create.css. */ - $methodCssFile = $mainCssPath . $devicePrefix . $methodName . '.css'; + $methodCssFile = $mainCssPath . $devicePrefix . $methodName . "$suffix.css"; if(is_file($methodCssFile)) $css .= file_get_contents($methodCssFile); /* Method css file with lang. like module/story/css/create.en.css. */ - $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}.{$clientLang}.css"; - if(!file_exists($methodCssLangFile) and $notCNLang) $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}.en.css"; + $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}{$suffix}.{$clientLang}.css"; + if(!file_exists($methodCssLangFile) and $notCNLang) $methodCssLangFile = $mainCssPath . $devicePrefix . "{$methodName}{$suffix}.en.css"; if(is_file($methodCssLangFile)) $css .= file_get_contents($methodCssLangFile); if(!empty($cssExtPath)) @@ -584,7 +585,7 @@ class baseControl * @access public * @return string */ - public function getJS($moduleName, $methodName) + public function getJS($moduleName, $methodName, $suffix = '') { $moduleName = strtolower(trim($moduleName)); $methodName = strtolower(trim($methodName)); @@ -593,8 +594,8 @@ class baseControl $jsExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, 'js'); $js = ''; - $mainJsFile = $modulePath . 'js' . DS . $this->devicePrefix . 'common.js'; - $methodJsFile = $modulePath . 'js' . DS . $this->devicePrefix . $methodName . '.js'; + $mainJsFile = $modulePath . 'js' . DS . $this->devicePrefix . "common{$suffix}.js"; + $methodJsFile = $modulePath . 'js' . DS . $this->devicePrefix . $methodName . $suffix . '.js'; if(file_exists($mainJsFile)) $js .= file_get_contents($mainJsFile); if(is_file($methodJsFile)) $js .= file_get_contents($methodJsFile); @@ -914,10 +915,96 @@ class baseControl */ public function display($moduleName = '', $methodName = '') { + if($this->config->debug && $this->viewType === 'html' && (!isset($_GET['zin']) || $_GET['zin'] != '0')) + { + if(empty($moduleName)) $moduleName = $this->moduleName; + if(empty($methodName)) $methodName = $this->methodName; + $modulePath = $this->app->getModulePath($this->appName, $moduleName); + $viewType = $this->viewType == 'mhtml' ? 'html' : $this->viewType; + $mainViewFile = $modulePath . 'ui' . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php'; + if(file_exists($mainViewFile)) return $this->render($moduleName, $methodName); + } + if(empty($this->output)) $this->parse($moduleName, $methodName); echo $this->output; } + /** + * 向浏览器输出内容。 + * Print the content of the view. + * + * @param string $moduleName module name + * @param string $methodName method name + * @access public + * @return void + */ + public function render($moduleName = '', $methodName = '') + { + if(isset($_GET['zin']) && $_GET['zin'] == '0') + { + $this->display($moduleName, $methodName); + return; + } + + define('ZIN', true); + + if(empty($moduleName)) $moduleName = $this->moduleName; + if(empty($methodName)) $methodName = $this->methodName; + + include $this->app->getBasePath() . 'zin' . DS . 'zin.php'; + + /** + * 设置视图文件。(PHP7有一个bug,不能直接$viewFile = $this->setViewFile())。 + * Set viewFile. (Can't assign $viewFile = $this->setViewFile() directly because one php7's bug.) + */ + $results = $this->setViewFile($moduleName, $methodName, 'ui'); + + $viewFile = $results; + if(is_array($results)) extract($results); + + /** + * 获得当前页面的CSS和JS。 + * Get css and js codes for current method. + */ + $css = $this->getCSS($moduleName, $methodName, '.ui'); + $js = $this->getJS($moduleName, $methodName, '.ui'); + if($css) $this->view->pageCSS = $css; + if($js) $this->view->pageJS = $js; + + /** + * 切换到视图文件所在的目录,以保证视图文件里面的include语句能够正常运行。 + * Change the dir to the view file to keep the relative paths work. + */ + $currentPWD = getcwd(); + chdir(dirname($viewFile)); + + /** + * Set zin context data + */ + \zin\zin::$data = (array)$this->view; + + /** + * 使用extract安定ob方法渲染$viewFile里面的代码。 + * Use extract and ob functions to eval the codes in $viewFile. + */ + extract(\zin\zin::$data); + + include $viewFile; + /* + extract((array)$this->view); + ob_start(); + if(isset($hookFiles)) foreach($hookFiles as $hookFile) if(file_exists($hookFile)) include $hookFile; + $this->output .= ob_get_contents(); + ob_end_clean(); + */ + + /** + * 渲染完毕后,再切换回之前的路径。 + * At the end, chang the dir to the previous. + */ + chdir($currentPWD); + } + /** * 直接输出data数据,通常用于ajax请求中。 * Send data directly, for ajax requests. diff --git a/framework/base/router.class.php b/framework/base/router.class.php index 70a7550b9a..f24000191a 100644 --- a/framework/base/router.class.php +++ b/framework/base/router.class.php @@ -1041,6 +1041,19 @@ class baseRouter */ public function setOpenApp() { + if(isset($this->config->zin)) + { + $module = $this->rawModule; + $tab = ''; + + if(isset($_SERVER['HTTP_X_ZIN_APP'])) $tab = $_SERVER['HTTP_X_ZIN_APP']; + elseif(isset($this->lang->navGroup)) $tab = zget($this->lang->navGroup, $module, 'my'); + elseif(isset($_COOKIE['tab']) && $_COOKIE['tab'] && preg_match('/^\w+$/', $_COOKIE['tab'])) $tab = $_COOKIE['tab']; + + $this->tab = empty($tab) ? 'my' : $tab; + return; + } + $module = $this->rawModule; $this->tab = 'my'; if(isset($this->lang->navGroup)) $this->tab = zget($this->lang->navGroup, $module, 'my'); @@ -2866,10 +2879,19 @@ class baseRouter { if(!empty($this->config->debug) and $this->config->debug > 1) { - $cmd = "vim +$line $file"; - $size = strlen($cmd); - echo "
$message: ";
-                echo "
"; + if(isset($this->config->zin) || isset($_SERVER['HTTP_X_ZIN_OPTIONS'])) + { + if(!isset($this->zinErrors)) $this->zinErrors = []; + $this->zinErrors[] = ['file' => $file, 'line' => $line, 'message' => $message]; + } + else + { + $cmd = "vim +$line $file"; + $size = strlen($cmd); + + echo "
$message: ";
+                    echo "
"; + } } } diff --git a/framework/control.class.php b/framework/control.class.php index 82549c6859..c41e9933f1 100644 --- a/framework/control.class.php +++ b/framework/control.class.php @@ -249,19 +249,20 @@ class control extends baseControl * * @param string $moduleName module name * @param string $methodName method name + * @param string $viewDir * @access public * @return string the view file */ - public function setViewFile($moduleName, $methodName) + public function setViewFile($moduleName, $methodName, $viewDir = 'view') { $moduleName = strtolower(trim($moduleName)); $methodName = strtolower(trim($methodName)); $modulePath = $this->app->getModulePath($this->appName, $moduleName); - $viewExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, 'view'); + $viewExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, $viewDir); $viewType = ($this->viewType == 'mhtml' or $this->viewType == 'xhtml') ? 'html' : $this->viewType; - $mainViewFile = $modulePath . 'view' . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php'; + $mainViewFile = $modulePath . $viewDir . DS . $this->devicePrefix . $methodName . '.' . $viewType . '.php'; /* If the main view file doesn't exist, set the device prefix to empty and reset the main view file. */ if(!file_exists($mainViewFile) and $this->app->clientDevice != 'mobile') diff --git a/lib/base/front/front.class.php b/lib/base/front/front.class.php index e00226eae8..23aa179d48 100644 --- a/lib/base/front/front.class.php +++ b/lib/base/front/front.class.php @@ -484,6 +484,42 @@ class baseHTML return " "; } + /** + * Get goback link. + * 获取返回按钮链接 + */ + public static function getGobackLink() + { + global $app, $config; + + $gobackLink = ''; + $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; + $refererParts = parse_url($referer); + + if($config->requestType == 'PATH_INFO' and empty($refererParts)) return $gobackLink; + if($config->requestType == 'GET' and !isset($refererParts['query'])) return $gobackLink; + + $tab = $app->tab; + $gobackList = isset($_COOKIE['goback']) ? json_decode($_COOKIE['goback'], true) : array(); + $gobackLink = isset($gobackList[$tab]) ? $gobackList[$tab] : ''; + + /* Make sure href is opened in the same tab. */ + if(!empty($gobackLink)) $gobackLink .= "#app=$tab"; + + /* If the link of the referer is not the link of the current page or the link of the index, the cookie and gobackLink will be updated. */ + $currentModule = $app->getModuleName(); + $currentMethod = $app->getMethodName(); + $refererLink = $config->requestType == 'PATH_INFO' ? $refererParts['path'] : $refererParts['query']; + if(!preg_match("/(m=|\/)(index|search|$currentModule)(&f=|-)(index|buildquery|$currentMethod)(&|-|\.)?/", strtolower($refererLink))) + { + $gobackList[$tab] = $referer; + $gobackLink = $referer; + setcookie('goback', json_encode($gobackList), $config->cookieLife, $config->webRoot, '', $config->cookieSecure, false); + } + + return empty($gobackLink) ? 'javascript:history.go(-1)' : $gobackLink; + } + /** * 创建返回按钮。 * Back button. @@ -1160,18 +1196,8 @@ EOT; return $js; } - /** - * 导出$config到js,因为js的createLink()方法需要获取config信息。 - * Export the config vars for createLink() js version. - * - * @static - * @access public - * @return void - */ - static public function exportConfigVars() + static function getJSConfigVars() { - if(!function_exists('json_encode')) return false; - global $app, $config, $lang; $defaultViewType = $app->getViewType(); $themeRoot = $app->getWebRoot() . 'theme/'; @@ -1207,6 +1233,25 @@ EOT; $jsConfig->tabSession = $config->tabSession; if($config->tabSession and helper::isWithTID()) $jsConfig->tid = zget($_GET, 'tid', ''); + return $jsConfig; + } + + /** + * 导出$config到js,因为js的createLink()方法需要获取config信息。 + * Export the config vars for createLink() js version. + * + * @static + * @access public + * @return void + */ + static public function exportConfigVars() + { + if(!function_exists('json_encode')) return false; + + global $lang; + + $jsConfig = static::getJSConfigVars(); + $jsLang = new stdclass(); $jsLang->submitting = isset($lang->loading) ? $lang->loading : ''; $jsLang->save = $jsConfig->save; diff --git a/module/action/model.php b/module/action/model.php index b2d40af67a..7ec6ba71e4 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -871,9 +871,9 @@ class actionModel extends model * @access public * @return void */ - public function printAction($action, $desc = '') + public function renderAction($action, $desc = '') { - if(!isset($action->objectType) or !isset($action->action)) return false; + if(!isset($action->objectType) || !isset($action->action)) return false; $objectType = $action->objectType; $actionType = strtolower($action->action); @@ -887,19 +887,19 @@ class actionModel extends model */ if(empty($desc)) { - if($action->objectType == 'story' and $action->action == 'reviewed' and strpos($action->extra, ',') !== false) + if($action->objectType == 'story' && $action->action == 'reviewed' && strpos($action->extra, ',') !== false) { $desc = $this->lang->$objectType->action->rejectreviewed; } - elseif($action->objectType == 'productplan' and in_array($action->action, array('startedbychild','finishedbychild','closedbychild','activatedbychild', 'createchild'))) + elseif($action->objectType == 'productplan' && in_array($action->action, array('startedbychild','finishedbychild','closedbychild','activatedbychild', 'createchild'))) { $desc = $this->lang->$objectType->action->changebychild; } - elseif($action->objectType == 'module' and in_array($action->action, array('created', 'moved', 'deleted'))) + elseif($action->objectType == 'module' && in_array($action->action, array('created', 'moved', 'deleted'))) { $desc = $this->lang->$objectType->action->{$action->action}; } - elseif(strpos('createmr,editmr,removemr', $action->action) !== false and strpos($action->extra, '::') !== false) + elseif(strpos('createmr,editmr,removemr', $action->action) !== false && strpos($action->extra, '::') !== false) { $mrAction = str_replace('mr', '', $action->action) . 'Action'; list($mrDate, $mrActor, $mrLink) = explode('::', $action->extra); @@ -909,7 +909,7 @@ class actionModel extends model $this->app->loadLang('mr'); $desc = sprintf($this->lang->mr->$mrAction, $mrDate, $mrActor, $mrLink); } - elseif($this->config->edition == 'max' and strpos($this->config->action->assetType, ",{$action->objectType},") !== false and $action->action == 'approved') + elseif($this->config->edition == 'max' && strpos($this->config->action->assetType, ",{$action->objectType},") !== false && $action->action == 'approved') { $desc = empty($this->lang->action->approve->{$action->extra}) ? '' : $this->lang->action->approve->{$action->extra}; } @@ -939,7 +939,7 @@ class actionModel extends model if(is_array($desc)) { if($key == 'extra') continue; - if($action->objectType == 'story' and $action->action == 'reviewed' and strpos($action->extra, '|') !== false and $key == 'actor') + if($action->objectType == 'story' && $action->action == 'reviewed' && strpos($action->extra, '|') !== false && $key == 'actor') { $desc['main'] = str_replace('$actor', $this->lang->action->superReviewer . ' ' . $value, $desc['main']); } @@ -957,70 +957,84 @@ class actionModel extends model } /* If the desc is an array, process extra. Please bug/lang. */ - if(is_array($desc)) + if(!is_array($desc)) return $desc; + + $extra = strtolower($action->extra); + + /* Fix bug #741. */ + if(isset($desc['extra'])) $desc['extra'] = $this->lang->$objectType->{$desc['extra']}; + + $actionDesc = ''; + if(isset($desc['extra'][$extra])) { - $extra = strtolower($action->extra); - - /* Fix bug #741. */ - if(isset($desc['extra'])) $desc['extra'] = $this->lang->$objectType->{$desc['extra']}; - - $actionDesc = ''; - if(isset($desc['extra'][$extra])) - { - $actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']); - } - else - { - $actionDesc = str_replace('$extra', $action->extra, $desc['main']); - } - - if($action->objectType == 'story' and $action->action == 'reviewed') - { - if(strpos($action->extra, ',') !== false) - { - list($extra, $reason) = explode(',', $extra); - $desc['reason'] = $this->lang->$objectType->{$desc['reason']}; - $actionDesc = str_replace(array('$extra', '$reason'), array($desc['extra'][$extra], $desc['reason'][$reason]), $desc['main']); - } - - if(strpos($action->extra, '|') !== false) - { - list($extra, $isSuperReviewer) = explode('|', $extra); - $actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']); - } - } - - if($action->objectType == 'story' and $action->action == 'synctwins') - { - if(!empty($extra) and strpos($extra, '|') !== false) - { - list($operate, $storyID) = explode('|', $extra); - $desc['operate'] = $this->lang->$objectType->{$desc['operate']}; - $link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID"; - $actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']); - } - } - - if($action->objectType == 'module' and strpos(',created,moved,', $action->action) !== false) - { - $moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', ''); - $modules = explode(',', $action->extra); - $moduleNames = array_intersect_key($moduleNames, array_combine($modules, $modules)); - $moduleNames = implode(', ', $moduleNames); - $actionDesc = str_replace('$extra', $moduleNames, $desc['main']); - } - elseif($action->objectType == 'module' and $action->action == 'deleted') - { - $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($action->objectID)->fetch(); - $moduleNames = $this->loadModel('tree')->getOptionMenu($module->root, 'story', 0, 'all', ''); - $actionDesc = str_replace('$extra', zget($moduleNames, $action->objectID), $desc['main']); - } - echo $actionDesc; + $actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']); } else { - echo $desc; + $actionDesc = str_replace('$extra', $action->extra, $desc['main']); } + + if($action->objectType == 'story' && $action->action == 'reviewed') + { + if(strpos($action->extra, ',') !== false) + { + list($extra, $reason) = explode(',', $extra); + $desc['reason'] = $this->lang->$objectType->{$desc['reason']}; + $actionDesc = str_replace(array('$extra', '$reason'), array($desc['extra'][$extra], $desc['reason'][$reason]), $desc['main']); + } + + if(strpos($action->extra, '|') !== false) + { + list($extra, $isSuperReviewer) = explode('|', $extra); + $actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']); + } + } + + if($action->objectType == 'story' && $action->action == 'synctwins') + { + if(!empty($extra) && strpos($extra, '|') !== false) + { + list($operate, $storyID) = explode('|', $extra); + $desc['operate'] = $this->lang->$objectType->{$desc['operate']}; + $link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID"; + $actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']); + } + } + + if($action->objectType == 'module' && strpos(',created,moved,', $action->action) !== false) + { + $moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', ''); + $modules = explode(',', $action->extra); + $moduleNames = array_intersect_key($moduleNames, array_combine($modules, $modules)); + $moduleNames = implode(', ', $moduleNames); + $actionDesc = str_replace('$extra', $moduleNames, $desc['main']); + } + elseif($action->objectType == 'module' && $action->action == 'deleted') + { + $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($action->objectID)->fetch(); + $moduleNames = $this->loadModel('tree')->getOptionMenu($module->root, 'story', 0, 'all', ''); + $actionDesc = str_replace('$extra', zget($moduleNames, $action->objectID), $desc['main']); + } + return $actionDesc; + } + + /** + * Print actions of an object. + * + * @param object $action + * @param string $desc + * @access public + * @return void + */ + public function printAction($action, $desc = '') + { + $content = $this->renderAction($action, $desc); + if(is_string($content)) + { + echo $content; + return; + } + return false; } /** @@ -1815,7 +1829,7 @@ class actionModel extends model * @access public * @return void */ - public function printChanges($objectType, $histories, $canChangeTag = true) + public function renderChanges($objectType, $histories, $canChangeTag = true) { if(empty($histories)) return; @@ -1835,23 +1849,41 @@ class actionModel extends model } $histories = array_merge($historiesWithoutDiff, $historiesWithDiff); + $content = ''; + foreach($histories as $history) { $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space); if($history->diff != '') { $history->diff = str_replace(array('', '', '', ''), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff); - $history->diff = ($history->field != 'subversion' and $history->field != 'git') ? htmlSpecialString($history->diff) : $history->diff; // Keep the diff link. + $history->diff = ($history->field != 'subversion' && $history->field != 'git') ? htmlSpecialString($history->diff) : $history->diff; // Keep the diff link. $history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('', '', '', ''), $history->diff); $history->diff = nl2br($history->diff); $history->noTagDiff = $canChangeTag ? preg_replace('/<\/?([a-z][a-z0-9]*)[^\/]*\/?>/Ui', '', $history->diff) : ''; - printf($this->lang->action->desc->diff2, $history->fieldLabel, $history->noTagDiff, $history->diff); + $content .= sprintf($this->lang->action->desc->diff2, $history->fieldLabel, $history->noTagDiff, $history->diff); } else { - printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new); + $content .= sprintf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new); } } + return $content; + } + + /** + * Print changes of every action. + * + * @param string $objectType + * @param array $histories + * @param bool $canChangeTag + * @access public + * @return void + */ + public function printChanges($objectType, $histories, $canChangeTag = true) + { + $content = $this->renderChanges($objectType, $histories, $canChangeTag); + if(is_string($content)) echo $content; } /** diff --git a/module/common/lang/de.php b/module/common/lang/de.php index 6d45763189..7f9c6cc5f2 100644 --- a/module/common/lang/de.php +++ b/module/common/lang/de.php @@ -498,6 +498,8 @@ $lang->pager->totalCount = "Total: {recTotal} items"; $lang->pager->pageSize = "{recPerPage} per page"; $lang->pager->itemsRange = "From {start} to {end}"; $lang->pager->pageOfTotal = "Page {page} of {totalPage}"; +$lang->pager->totalCountAB = "Total: {recTotal} items"; +$lang->pager->pageSizeAB = "{recPerPage} per page"; $lang->colorPicker = new stdclass(); $lang->colorPicker->errorTip = 'Not a valid color value'; diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 8b1f83b8e9..48400a7458 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -161,70 +161,72 @@ $lang->code = 'Code'; $lang->pri = 'Priority'; $lang->delayed = 'Delayed'; -$lang->common->common = 'Common Module'; -$lang->common->story = 'Story'; -$lang->my->common = 'My'; -$lang->todo->common = 'Todo'; -$lang->block->common = 'Block'; -$lang->program->common = 'Program'; -$lang->product->common = $lang->productCommon; -$lang->project->common = $lang->projectCommon; -$lang->execution->common = 'Execution'; -$lang->kanban->common = 'Kanban'; -$lang->qa->common = 'QA'; -$lang->devops->common = 'DevOps'; -$lang->doc->common = 'Doc'; -$lang->repo->common = 'Code'; -$lang->repo->codeRepo = 'Code Repo'; -$lang->bi->common = 'BI'; -$lang->screen->common = 'Screen'; -$lang->pivot->common = 'Pivot Table'; -$lang->chart->common = 'Chart'; -$lang->report->common = 'Report'; -$lang->system->common = 'System'; -$lang->admin->common = 'Admin'; -$lang->story->common = 'Story'; -$lang->task->common = 'Task'; -$lang->bug->common = 'Bug'; -$lang->testcase->common = 'Testcase'; -$lang->testtask->common = 'Request'; -$lang->score->common = 'Score'; -$lang->build->common = 'Build'; -$lang->testreport->common = 'Report'; -$lang->automation->common = 'Automation'; -$lang->team->common = 'Team'; -$lang->user->common = 'User'; -$lang->custom->common = 'Custom'; -$lang->custom->mode = 'Mode'; -$lang->custom->flow = 'Concept'; -$lang->extension->common = 'Extension'; -$lang->company->common = 'Company'; -$lang->dept->common = 'Dept'; -$lang->upgrade->common = 'Update'; -$lang->editor->common = 'Editor'; -$lang->program->list = 'Program List'; -$lang->program->kanban = 'Program Kanban'; -$lang->design->common = 'Design'; -$lang->design->HLDS = 'Preliminary Design'; -$lang->design->DDS = 'Detailed Design'; -$lang->design->DBDS = 'Database Design'; -$lang->design->ADS = 'Interface Design'; -$lang->stage->common = 'Stage'; -$lang->stage->type = 'Stage Type'; -$lang->stage->list = 'Stage List'; -$lang->stage->percent = 'Workload Ratio'; -$lang->execution->list = "{$lang->executionCommon} List"; -$lang->execution->CFD = "Cumulative Flow Diagrams"; -$lang->kanban->common = 'Kanban'; -$lang->backup->common = 'Backup'; -$lang->action->trash = 'Recycle'; -$lang->app->common = 'APP'; -$lang->app->serverLink = 'Server Link'; -$lang->review->common = 'Review'; -$lang->zahost->common = 'ZAhost'; -$lang->zanode->common = 'ZAnode'; -$lang->dimension->common = 'Dimension'; -$lang->contact->common = 'Contacts'; +$lang->common->common = 'Common Module'; +$lang->common->story = 'Story'; +$lang->my->common = 'My'; +$lang->todo->common = 'Todo'; +$lang->block->common = 'Block'; +$lang->program->common = 'Program'; +$lang->product->common = $lang->productCommon; +$lang->project->common = $lang->projectCommon; +$lang->execution->common = 'Execution'; +$lang->kanban->common = 'Kanban'; +$lang->qa->common = 'QA'; +$lang->devops->common = 'DevOps'; +$lang->doc->common = 'Doc'; +$lang->repo->common = 'Code'; +$lang->repo->codeRepo = 'Code Repo'; +$lang->bi->common = 'BI'; +$lang->screen->common = 'Screen'; +$lang->pivot->common = 'Pivot Table'; +$lang->chart->common = 'Chart'; +$lang->report->common = 'Report'; +$lang->system->common = 'System'; +$lang->admin->common = 'Admin'; +$lang->story->common = 'Story'; +$lang->task->common = 'Task'; +$lang->bug->common = 'Bug'; +$lang->testcase->common = 'Testcase'; +$lang->testtask->common = 'Request'; +$lang->score->common = 'Score'; +$lang->build->common = 'Build'; +$lang->testreport->common = 'Report'; +$lang->automation->common = 'Automation'; +$lang->team->common = 'Team'; +$lang->user->common = 'User'; +$lang->custom->common = 'Custom'; +$lang->custom->mode = 'Mode'; +$lang->custom->flow = 'Concept'; +$lang->extension->common = 'Extension'; +$lang->company->common = 'Company'; +$lang->dept->common = 'Dept'; +$lang->upgrade->common = 'Update'; +$lang->editor->common = 'Editor'; +$lang->program->list = 'Program List'; +$lang->program->kanban = 'Program Kanban'; +$lang->program->projectView = '项目视角'; +$lang->program->productView = '产品视角'; +$lang->design->common = 'Design'; +$lang->design->HLDS = 'Preliminary Design'; +$lang->design->DDS = 'Detailed Design'; +$lang->design->DBDS = 'Database Design'; +$lang->design->ADS = 'Interface Design'; +$lang->stage->common = 'Stage'; +$lang->stage->type = 'Stage Type'; +$lang->stage->list = 'Stage List'; +$lang->stage->percent = 'Workload Ratio'; +$lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->CFD = "Cumulative Flow Diagrams"; +$lang->kanban->common = 'Kanban'; +$lang->backup->common = 'Backup'; +$lang->action->trash = 'Recycle'; +$lang->app->common = 'APP'; +$lang->app->serverLink = 'Server Link'; +$lang->review->common = 'Review'; +$lang->zahost->common = 'ZAhost'; +$lang->zanode->common = 'ZAnode'; +$lang->dimension->common = 'Dimension'; +$lang->contact->common = 'Contacts'; $lang->programstakeholder->common = 'Stakeholder'; $lang->featureswitch->common = 'Features On/Off'; @@ -498,6 +500,8 @@ $lang->pager->totalCount = "Total: {recTotal} items"; $lang->pager->pageSize = "{recPerPage} per page"; $lang->pager->itemsRange = "From {start} to {end}"; $lang->pager->pageOfTotal = "Page {page} of {totalPage}"; +$lang->pager->totalCountAB = "Total: {recTotal} items"; +$lang->pager->pageSizeAB = "{recPerPage} per page"; $lang->colorPicker = new stdclass(); $lang->colorPicker->errorTip = 'Not a valid color value'; diff --git a/module/common/lang/fr.php b/module/common/lang/fr.php index fbeb1d42cc..fa41af2778 100644 --- a/module/common/lang/fr.php +++ b/module/common/lang/fr.php @@ -498,6 +498,8 @@ $lang->pager->totalCount = "Total: {recTotal} lignes"; $lang->pager->pageSize = "{recPerPage} par page"; $lang->pager->itemsRange = "De {start} à {end}"; $lang->pager->pageOfTotal = "Page {page} sur {totalPage}"; +$lang->pager->totalCountAB = "Total: {recTotal} lignes"; +$lang->pager->pageSizeAB = "{recPerPage} par page"; $lang->colorPicker = new stdclass(); $lang->colorPicker->errorTip = "Ce n'est pas une valeur de couleur valide"; diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index 5041070f5f..2a95620bde 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -133,8 +133,10 @@ $lang->my->dividerMenu = ',work,dynamic,'; /* Program menu. */ $lang->program->homeMenu = new stdclass(); -$lang->program->homeMenu->browse = array('link' => "{$lang->program->list}|program|browse|", 'alias' => 'create,edit', 'subModule' => 'project'); -$lang->program->homeMenu->kanban = array('link' => "{$lang->program->kanban}|program|kanban|"); +$lang->program->homeMenu->browse = array('link' => "{$lang->program->list}|program|browse|", 'alias' => 'create,edit', 'subModule' => 'project'); +$lang->program->homeMenu->projectView = array('link' => "{$lang->program->projectView}|program|projectview|", 'alias' => 'create,edit', 'subModule' => 'project'); +$lang->program->homeMenu->productView = array('link' => "{$lang->program->productView}|program|productview|", 'alias' => 'create,edit', 'subModule' => 'project'); +$lang->program->homeMenu->kanban = array('link' => "{$lang->program->kanban}|program|kanban|"); $lang->program->menu = new stdclass(); $lang->program->menu->product = array('link' => "{$lang->productCommon}|program|product|programID=%s", 'alias' => 'view'); diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index faa9f643db..fc6bc7f691 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -161,70 +161,72 @@ $lang->code = '代号'; $lang->pri = '优先级'; $lang->delayed = '已延期'; -$lang->common->common = '公有模块'; -$lang->common->story = '需求'; -$lang->my->common = '地盘'; -$lang->todo->common = '待办'; -$lang->block->common = '区块'; -$lang->program->common = '项目集'; -$lang->product->common = $lang->productCommon; -$lang->project->common = $lang->projectCommon; -$lang->execution->common = '执行'; -$lang->kanban->common = '看板'; -$lang->qa->common = '测试'; -$lang->devops->common = 'DevOps'; -$lang->doc->common = '文档'; -$lang->repo->common = '代码'; -$lang->repo->codeRepo = '代码库'; -$lang->bi->common = 'BI'; -$lang->screen->common = '大屏'; -$lang->pivot->common = '透视表'; -$lang->chart->common = '图表'; -$lang->report->common = '统计'; -$lang->system->common = '组织'; -$lang->admin->common = '后台'; -$lang->story->common = $lang->SRCommon; -$lang->task->common = '任务'; -$lang->bug->common = 'Bug'; -$lang->testcase->common = '用例'; -$lang->testtask->common = '测试单'; -$lang->score->common = '我的积分'; -$lang->build->common = '版本'; -$lang->testreport->common = '测试报告'; -$lang->automation->common = '自动化'; -$lang->team->common = '团队'; -$lang->user->common = '用户'; -$lang->custom->common = '自定义'; -$lang->custom->mode = '模式'; -$lang->custom->flow = '流程设置'; -$lang->extension->common = '插件'; -$lang->company->common = '公司'; -$lang->dept->common = '部门'; -$lang->upgrade->common = '升级'; -$lang->editor->common = '编辑器'; -$lang->program->list = '项目集列表'; -$lang->program->kanban = '项目集看板'; -$lang->design->common = '设计'; -$lang->design->HLDS = '概要设计'; -$lang->design->DDS = '详细设计'; -$lang->design->DBDS = '数据库设计'; -$lang->design->ADS = '接口设计'; -$lang->stage->common = '阶段'; -$lang->stage->type = '阶段类型'; -$lang->stage->list = '阶段列表'; -$lang->stage->percent = '工作量占比'; -$lang->execution->list = "{$lang->executionCommon}列表"; -$lang->execution->CFD = "累积流图"; -$lang->kanban->common = '看板'; -$lang->backup->common = '备份'; -$lang->action->trash = '回收站'; -$lang->app->common = '应用'; -$lang->app->serverLink = '服务器链接'; -$lang->review->common = '审批'; -$lang->zahost->common = '宿主机'; -$lang->zanode->common = '执行节点'; -$lang->dimension->common = '维度'; -$lang->contact->common = '联系人'; +$lang->common->common = '公有模块'; +$lang->common->story = '需求'; +$lang->my->common = '地盘'; +$lang->todo->common = '待办'; +$lang->block->common = '区块'; +$lang->program->common = '项目集'; +$lang->product->common = $lang->productCommon; +$lang->project->common = $lang->projectCommon; +$lang->execution->common = '执行'; +$lang->kanban->common = '看板'; +$lang->qa->common = '测试'; +$lang->devops->common = 'DevOps'; +$lang->doc->common = '文档'; +$lang->repo->common = '代码'; +$lang->repo->codeRepo = '代码库'; +$lang->bi->common = 'BI'; +$lang->screen->common = '大屏'; +$lang->pivot->common = '透视表'; +$lang->chart->common = '图表'; +$lang->report->common = '统计'; +$lang->system->common = '组织'; +$lang->admin->common = '后台'; +$lang->story->common = $lang->SRCommon; +$lang->task->common = '任务'; +$lang->bug->common = 'Bug'; +$lang->testcase->common = '用例'; +$lang->testtask->common = '测试单'; +$lang->score->common = '我的积分'; +$lang->build->common = '版本'; +$lang->testreport->common = '测试报告'; +$lang->automation->common = '自动化'; +$lang->team->common = '团队'; +$lang->user->common = '用户'; +$lang->custom->common = '自定义'; +$lang->custom->mode = '模式'; +$lang->custom->flow = '流程设置'; +$lang->extension->common = '插件'; +$lang->company->common = '公司'; +$lang->dept->common = '部门'; +$lang->upgrade->common = '升级'; +$lang->editor->common = '编辑器'; +$lang->program->list = '项目集列表'; +$lang->program->kanban = '项目集看板'; +$lang->program->projectView = '项目视角'; +$lang->program->productView = '产品视角'; +$lang->design->common = '设计'; +$lang->design->HLDS = '概要设计'; +$lang->design->DDS = '详细设计'; +$lang->design->DBDS = '数据库设计'; +$lang->design->ADS = '接口设计'; +$lang->stage->common = '阶段'; +$lang->stage->type = '阶段类型'; +$lang->stage->list = '阶段列表'; +$lang->stage->percent = '工作量占比'; +$lang->execution->list = "{$lang->executionCommon}列表"; +$lang->execution->CFD = "累积流图"; +$lang->kanban->common = '看板'; +$lang->backup->common = '备份'; +$lang->action->trash = '回收站'; +$lang->app->common = '应用'; +$lang->app->serverLink = '服务器链接'; +$lang->review->common = '审批'; +$lang->zahost->common = '宿主机'; +$lang->zanode->common = '执行节点'; +$lang->dimension->common = '维度'; +$lang->contact->common = '联系人'; $lang->programstakeholder->common = '干系人'; $lang->featureswitch->common = '功能开关'; @@ -498,6 +500,8 @@ $lang->pager->totalCount = '共 {recTotal} 项'; $lang->pager->pageSize = '每页 {recPerPage} 项'; $lang->pager->itemsRange = '第 {start} ~ {end} 项'; $lang->pager->pageOfTotal = '第 {page}/{totalPage} 页'; +$lang->pager->totalCountAB = '共 {recTotal} 项'; +$lang->pager->pageSizeAB = '每页 {recPerPage} 项'; $lang->colorPicker = new stdclass(); $lang->colorPicker->errorTip = '不是有效的颜色值'; diff --git a/module/common/view/action.html.php b/module/common/view/action.html.php index 24dd9fcd79..a39ec32cad 100755 --- a/module/common/view/action.html.php +++ b/module/common/view/action.html.php @@ -59,45 +59,45 @@ ?> action->printAction($action);?> history)):?> - -
- action->printChanges($action->objectType, $action->history);?> -
+ +
+ action->printChanges($action->objectType, $action->history);?> +
comment))) != 0):?> - - ', "title='{$lang->action->editComment}'", 'btn btn-link btn-icon btn-sm btn-edit-comment');?> - - -
-
- comment, '
') !== false)
-            {
-                $before   = explode('
', $action->comment);
-                $after    = explode('
', $before[1]); - $htmlCode = $after[0]; - $text = $before[0] . htmlspecialchars($htmlCode) . $after[1]; - echo $text; - } - else - { - echo strip_tags($action->comment) == $action->comment ? nl2br($action->comment) : $action->comment; - } - ?> + + ', "title='{$lang->action->editComment}'", 'btn btn-link btn-icon btn-sm btn-edit-comment');?> + + +
+
+ comment, '
') !== false)
+              {
+                  $before   = explode('
', $action->comment);
+                  $after    = explode('
', $before[1]); + $htmlCode = $after[0]; + $text = $before[0] . htmlspecialchars($htmlCode) . $after[1]; + echo $text; + } + else + { + echo strip_tags($action->comment) == $action->comment ? nl2br($action->comment) : $action->comment; + } + ?> +
-
- -
id")?>'> -
- comment), "rows='8' autofocus='autofocus'");?> -
-
- save);?> - close, '', 'btn btn-wide btn-hide-form');?> -
-
- + +
id")?>'> +
+ comment), "rows='8' autofocus='autofocus'");?> +
+
+ save);?> + close, '', 'btn btn-wide btn-hide-form');?> +
+
+ diff --git a/module/common/view/header.lite.html.php b/module/common/view/header.lite.html.php old mode 100755 new mode 100644 index c942e35bee..19396547e7 --- a/module/common/view/header.lite.html.php +++ b/module/common/view/header.lite.html.php @@ -26,15 +26,17 @@ $commonLang = array('zh-cn', 'zh-tw', 'en', 'fr', 'de'); css::import($themeRoot . 'zui/css/min.css?t=' . $timestamp); css::import($defaultTheme . 'style.css?t=' . $timestamp); - css::import($langTheme); + if(strpos($clientTheme, 'default') === false) css::import($clientTheme . 'style.css?t=' . $timestamp); js::import($jsRoot . 'jquery/lib.js'); js::import($jsRoot . 'zui/min.js?t=' . $timestamp); + if(!in_array($clientLang, $commonLang)) js::import($jsRoot . 'zui/lang.' . $clientLang . '.min.js?t=' . $timestamp); js::import($jsRoot . 'my.full.js?t=' . $timestamp); + if(isset($config->zinTool)) js::import($jsRoot . 'zui3/zintool.js'); } else { @@ -84,7 +86,7 @@ if(file_exists($xuanExtFile)) include $xuanExtFile; app->getViewType() == 'xhtml' ? 'allow-self-open' : ''; if(isset($pageBodyClass)) $bodyClass = $bodyClass . ' ' . $pageBodyClass; -if($this->moduleName == 'index' && $this->methodName == 'index') $bodyClass .= ' menu-' . ($this->cookie->hideMenu ? 'hide' : 'show'); +if($this->app->moduleName == 'index' && $this->app->methodName == 'index') $bodyClass .= ' menu-' . ($this->cookie->hideMenu ? 'hide' : 'show'); if(strpos($_SERVER['HTTP_USER_AGENT'], 'xuanxuan') !== false) $bodyClass .= ' xxc-embed'; ?> diff --git a/module/index/control.php b/module/index/control.php index b4f6cef1e2..52f9a59a44 100644 --- a/module/index/control.php +++ b/module/index/control.php @@ -46,6 +46,17 @@ class index extends control $this->display(); } + public function index2($open = '') + { + $this->index($open); + } + + public function app($open = '') + { + $this->view->defaultUrl = helper::safe64Decode($open); + $this->display(); + } + /** * Get the log record according to the version. * diff --git a/module/index/css/index2.ui.css b/module/index/css/index2.ui.css new file mode 100644 index 0000000000..efeceecc66 --- /dev/null +++ b/module/index/css/index2.ui.css @@ -0,0 +1,41 @@ +#menu {position: fixed; left: 0; top: 0; bottom: 0; background: var(--zt-menu-bg, var(--color-slate-800)); width: var(--zt-menu-width, 96px); color: rgba(var(--color-canvas-rgb), .8); transition: width .2s; user-select: none;} +#menu .nav {flex-direction: column; align-items: stretch;} +#menu .nav > li {display: block; height: var(--zt-menu-height, 38px); padding: 4px 12px; transition: padding .2s;} +#menu .nav > .divider {background: var(--color-canvas); opacity: .12; height: 1px; padding: 0; margin: 6px 12px;} +#menu .nav > li > a {color: inherit; display: flex; align-items: center; gap: 8px; padding: 0 6px; height: calc(var(--zt-menu-height, 38px) - 8px); transition: color .2s, background-color .2s; border-radius: var(--radius-md);} +#menu .nav > li > a.active, +#menu .nav > li > a:hover {background: var(--zt-menu-hover-bg, var(--color-primary-500)); color: var(--color-canvas);} +#menu .nav > li > a > .text {white-space: nowrap;} + +#menuNav {padding: 6px 0; position: absolute; left: 0; right: 0; top: 0; bottom: 46px;} +#menuFooter {position: absolute; bottom: 6px; left: 0; right: 0;} + +#menuMoreNav {display: none;} +.show-more-nav #menuMoreNav {display: block;} + +.hide-menu #menu {width: var(--zt-menu-fold-width, 40px);} +.hide-menu #menu .nav > li {padding: 4px} +.hide-menu #menu .nav > .divider {padding: 0; margin: 6px} +.hide-menu #menu .nav > li > a {justify-content: center;} +.hide-menu #menu .nav > li > a > .text {display: none;} +.hide-menu #menu .menu-toggle > .icon {transform: rotate(180deg);} + +#apps {position: fixed; left: var(--zt-menu-width, 96px); top: 0; bottom: var(--zt-apps-bar-height, 40px); right: 0; background-color: var(--zt-page-bg); transition: left .2s;} +.hide-menu #apps {left: var(--zt-menu-fold-width, 40px);} + +#appsBar {position: fixed; left: var(--zt-menu-width, 96px); bottom: 0; right: 0; height: var(--zt-apps-bar-height, 40px); background: var(--zt-apps-bar-bg, var(--color-canvas)); box-shadow: 0 -2px 12px rgba(0,0,0,.02); transition: left .2s;} +.hide-menu #appsBar {left: var(--zt-menu-fold-width, 40px);} +#appTabs {position: absolute; left: 4px; right: 280px; top: 0; bottom: 0; user-select: none;} +#appTabs > li > a {border-radius: var(--radius-md); opacity: .7;} +#appTabs > li + li::before {display: block; content: ' '; position: absolute; left: 0; top: 8px; bottom: 8px; width: 1px; background: var(--color-inverse); opacity: .12;} +#appTabs > li > a.active {color: inherit; opacity: 1; color: var(--color-primary-500)} +#appsToolbar {position: absolute; right: 4px; width: 280px; top: 0; bottom: 0; display: flex; justify-content: flex-end;} +#appsToolbar > .btn {color: inherit} +#appsToolbar > .btn-zentao > .icon {color: var(--color-primary-400)} + +.app-container {position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; transition-duration: .3s; background: var(--zt-page-bg) linear-gradient(180deg, var(--zt-header-bg) 0, var(--zt-header-bg) 48px, rgba(255,0,0,0) 48px) no-repeat;} +.app-container.loading:before {background-color: rgba(0,0,0,.1);} +.app-container.loading:before, .ap p-container.loading::after {transition-delay: 3s;} +.app-container.loading.open-from-hidden {transition-delay: 0s;} +.app-container.loading.open-from-hidden > iframe {opacity: 0;} +.app-container > iframe {width: 100%; height: 100%; background: inherit;} diff --git a/module/index/js/app.ui.js b/module/index/js/app.ui.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/module/index/js/index2.ui.js b/module/index/js/index2.ui.js new file mode 100644 index 0000000000..09fe2ffebb --- /dev/null +++ b/module/index/js/index2.ui.js @@ -0,0 +1,637 @@ +/** + * @typedef {Object} ZentaoApp + * @property {string} code + * @property {string} icon + * @property {string} url + * @property {string} text + * @property {string} title + * @property {boolean} active + * @property {string} group + * @property {string} moduleName + * @property {string} methodName + * @property {string} vars + * @property {boolean} [external] + * @property {boolean} [opened] + * @typedef {Object} ZentaoOpenedProps + * @property {true} opened + * @property {HTMLIFrameElement} iframe + * @property {number} zIndex + * @property {string} currentTitle + * @property {string} currentUrl + * @property {number} [zIndex] + * @property {HTMLIframe} iframe + * @property {jQuery} $app + * @property {jQuery} $bar + * @typedef {ZentaoApp & ZentaoOpenedProps} ZentaoOpenedApp + */ + + +/* Init variables */ +const apps = +{ + /** @type {Record} */ + map: {}, + /** @type {Record} */ + openedMap: {}, + defaultCode: '', + lastCode: '', + zIndex: 10, + frameContent: null +}; + +const debug = config.debug; + +function triggerAppEvent(code, event, args) +{ + const app = apps.openedMap[code]; + if(!app) return; + + if(debug) console.log('[APPS]', 'event:', event, code, args); + event = event + '.apps'; + if(!Array.isArray(args)) args = [args]; + if(app.$app) app.$app.trigger(event, args); + if(app.iframe && app.iframe.contentWindow.$) return app.iframe.contentWindow.$(app.iframe.contentWindow.document).trigger(event, args); +} + +/** + * Open app + * @param {string} url + * @param {string} [code] + * @param {boolean} [forceReload] + * @returns {ZentaoOpenedApp|undefined} + */ +function openApp(url, code, forceReload) +{ + if(!code) + { + if(apps.map[url]) + { + code = url; + url = ''; + } + else if(url) + { + code = getAppCodeFromUrl(url); + } + if(!code) return openApp('my'); + } + const app = apps.map[code]; + if(!app) + { + zui.Messager.show('App not found', {type: 'danger', time: 2000}); + return; + } + if(!url) url = app.url; + + /* Create iframe for app */ + let openedApp = apps.openedMap[code]; + if(!openedApp) + { + openedApp = $.extend({opened: true, url: url, zIndex: 0, currentUrl: url}, app); + forceReload = false; + apps.openedMap[code] = openedApp; + + const $iframe = + $([ + '' + ].join(' ')); + const iframe = $iframe[0]; + openedApp.iframe = iframe; + openedApp.$app = $('
') + .append($iframe) + .appendTo('#apps'); + + iframe.onload = iframe.onreadystatechange = function(e) + { + const finishLoad = () => $iframe.removeClass('loading').addClass('in'); + iframe.contentWindow.$(iframe.contentDocument).one('pageload.app', finishLoad); + setTimeout(finishLoad, 10000); + triggerAppEvent(openedApp.code, 'loadapp', [openedApp, e]); + }; + } + + /* Set tab cookie */ + $.cookie.set('tab', code, {expires: config.cookieLife, path: config.webRoot}); + + /* Highlight on left menu */ + const $menuNav = $('#menuMainNav,#menuMoreNav'); + const $lastItem = $menuNav.find('li>a.active'); + if($lastItem.data('app') !== code) + { + $lastItem.removeClass('active'); + $menuNav.find('li[data-app="' + code + '"]>a').addClass('active'); + } + + /* Show and load app */ + const isSameUrl = openedApp.currentUrl === url; + const needLoad = !isSameUrl || forceReload !== false; + if(needLoad) + { + reloadApp(code, url); + openedApp.$app.toggleClass('open-from-hidden', openedApp.zIndex < apps.zIndex) + } + else + { + updateApp(code, url, openedApp.currentTitle, 'show'); + } + openedApp.zIndex = ++apps.zIndex; + openedApp.$app.show().css('z-index', openedApp.zIndex); + + /* Update on app tabs bar */ + const $tabs = $('#appTabs'); + let $tabItem = $('#appTab-' + code); + if(!$tabItem.length) + { + if (app.text === undefined) return false; + const $link= $('') + .attr('data-app', code) + .addClass('show-in-app') + .append($('').text(app.text)); + $tabItem = $('') + .attr({'data-app': code, id: 'appTab-' + code}) + .append($link) + .appendTo($tabs); + openedApp.$bar = $tabItem; + } + const $lastTab = $tabs.find('li>a.active'); + if($lastTab.data('app') !== code) + { + $lastTab.removeClass('active'); + $tabs.find('li[data-app="' + code + '"]>a').addClass('active'); + } + + if(debug) console.log('[APPS]', 'open:', code); + triggerAppEvent(code, 'openapp', [openedApp, {load: needLoad}]); + + return openedApp; +} + +/** + * Show app + * @param {string} code + */ +function showApp(code) +{ + return openApp('', code, false); +} + +/** + * Reload app + * @param {string} code + * @param {string} url + */ +function reloadApp(code, url) +{ + const app = apps.openedMap[code]; + if(!app) return; + + if(url === true) url = app.url; + else if(!url) url = app.currentUrl; + + const iframe = app.iframe; + try + { + if(app.external) iframe.src = url; + else if(iframe.contentWindow.loadPage) iframe.contentWindow.loadPage(url); + else console.error('[APPS]', 'reload: Cannot load page when iframe is not ready.'); + } + catch(error) + { + iframe.src = url; + } + + app.currentUrl = url; +} + +function updateApp(code, url, title, type) +{ + const app = apps.openedMap[code]; + if(!app) return; + + const state = typeof code === 'object' ? code : {code: code, url: url, title: title, type: type}; + const oldState = window.history.state; + + if(title) + { + document.title = title; + app.currentTitle = title; + } + + if(oldState && oldState.code === code && oldState.url === url) return; + + const displayUrl = $.createLink('index', 'index2', 'open=' + btoa(url)); + app.currentUrl = url; + window.history.pushState(state, title, displayUrl); + if(debug) console.log('[APPS]', 'update:', {code, url, title, type}); +} + +/** + * Get last opened app + * @param {boolean} [onlyShowed] If set to true then only get last app from apps are showed + * @returns {object} The opened app info object + */ +function getLastApp(onlyShowed) +{ + let lastShowIndex = 0; + let lastApp = null; + Object.values(apps.openedMap).forEach(app => + { + if((!onlyShowed || app.show) && lastShowIndex < app.zIndex && !app.closed) + { + lastShowIndex = app.zIndex; + lastApp = app; + } + }); + return lastApp; +} + +/** + * Close app + * @param {string} code + * @returns {ZentaoOpenedApp|undefined|false} + */ +function closeApp(code) +{ + code = code || apps.lastCode; + const app = apps.openedMap[code]; + if(!app) return; + + const iframe = app.iframe; + if(iframe) + { + if(iframe && iframe.contentDocument && iframe.contentWindow && iframe.contentWindow.onCloseApp) + { + var result = iframe.contentWindow.onCloseApp(); + if(result === false) return false; + } + } + + $('#appTabs a.active[data-app="' + code + '"]').parent().remove(); + + app.closed = true; + app.$app.remove(); + app.$bar.remove(); + + hideApp(code); + delete apps.openedMap[code]; + + triggerAppEvent(code, 'closeapp', app); + return app; +} + +/** + * Hide app + * @param {string} code + * @returns {ZentaoOpenedApp|undefined} + */ +function hideApp(code) +{ + code = code || apps.lastCode; + const app = apps.openedMap[code]; + if(!app) return; + + $('#menuNav a.active[data-app="' + code + '"]').removeClass('active'); + + if(!app.closed) triggerAppEvent(code, 'hideapp', app); + + app.$app.hide(); + apps.lastCode = null; + + /* Active last app */ + const lastApp = getLastApp(true) || getLastApp(); + showApp(lastApp ? lastApp.code : apps.defaultCode); + return app; +} + +/** + * Get app code from url + * @param {String} urlOrModuleName Url string + * @return {String} + */ +function getAppCodeFromUrl(urlOrModuleName) +{ + var code = navGroup[urlOrModuleName]; + if(code) return code; + + var link = $.parseLink(urlOrModuleName); + if(!link.moduleName || link.isOnlyBody || (link.moduleName === 'index' && link.methodName === 'index')) return ''; + + if(link.hash && link.hash.indexOf('app=') === 0) return link.hash.substr(4); + + /* Handling special situations */ + var moduleName = link.moduleName; + var methodName = link.methodName; + if (moduleName === 'index' && methodName === 'index') return 'my'; + + var methodLowerCase = methodName.toLowerCase(); + if(moduleName === 'doc') + { + if(link.prj) return 'project'; + + if((link.params.from || link.params.$3) == 'product') + { + if(['objectlibs', 'showfiles', 'browse', 'view', 'edit', 'delete', 'create'].includes(methodLowerCase)) return 'product'; + } + return 'doc'; + } + if(['caselib', 'testreport', 'testsuite', 'testtask', 'testcase', 'bug', 'qa'].includes(moduleName)) + { + return link.prj ? 'project' : 'qa'; + } + if(moduleName === 'report') + { + if(['usereport', 'editreport', 'deletereport', 'custom'].includes(methodLowerCase) && link.params.from) return 'system'; + else return link.prj ? 'project' : 'report'; + } + if(moduleName === 'story' && vision === 'lite') return 'project' + if(moduleName === 'testcase' && methodLowerCase === 'zerocase') + { + return link.params.from == 'project' ? 'project' : 'qa'; + } + if(moduleName === 'execution' && methodLowerCase === 'all') + { + return (link.params.from || link.params.$3) == 'project' ? 'project' : 'execution'; + } + if(moduleName === 'issue' || moduleName === 'risk' || moduleName === 'opportunity' || moduleName === 'pssp' || moduleName === 'auditplan' || moduleName === 'meeting' || moduleName === 'nc') + { + if(link.params.$2 == 'my' || link.params.from == 'my') return 'my'; + if(link.params.$2 == 'project' || link.params.from == 'project') return 'project'; + if(link.params.$2 == 'execution' || link.params.from == 'execution') return 'execution'; + } + if(moduleName === 'product') + { + if(methodLowerCase === 'create' && (link.params.programID || link.params.$1)) return 'program'; + if(methodLowerCase === 'edit' && (link.params.programID || link.params.$4)) return 'program'; + if(methodLowerCase === 'batchedit') return 'program'; + var moduleGroup = link.params.moduleGroup ? link.params.moduleGroup : link.params.$2; + if(methodLowerCase === 'showerrornone' && (moduleGroup || moduleGroup)) return moduleGroup; + } + if(moduleName === 'stakeholder') + { + if(methodLowerCase === 'create' && (link.params.programID || link.params.$1)) return 'program'; + } + if(moduleName === 'user') + { + if(['todo', 'todocalendar', 'effortcalendar', 'effort', 'task', 'todo', 'story', 'bug', 'testtask', 'testcase', 'execution', 'dynamic', 'profile', 'view', 'issue', 'risk'].includes(methodLowerCase)) return 'system'; + } + if(moduleName === 'my') + { + if(['team'].includes(methodLowerCase)) return 'system'; + } + if(moduleName === 'company') if(methodLowerCase == 'browse') return 'admin'; + if(moduleName === 'opportunity' || moduleName === 'risk' || moduleName == 'trainplan') if(methodLowerCase == 'view') return 'project'; + if(moduleName === 'tree') + { + if(methodLowerCase === 'browse') + { + var viewType = link.params.view || link.params.$2; + if(['bug', 'case', 'caselib'].includes(viewType)) return link.params.$5 === 'project' ? 'project' : 'qa'; + + if(viewType === 'doc' && (link.params.from === 'product' || link.params.$5 == 'product')) return 'product'; + if(viewType === 'doc' && (link.params.from === 'project' || link.params.$5 == 'project')) return 'project'; + if(viewType === 'doc') return 'doc'; + if(viewType === 'story') return 'product'; + } + else if(methodLowerCase === 'browsetask') + { + return 'project'; + } + } + if(moduleName === 'search' && methodLowerCase === 'buildindex') return 'admin'; + + code = navGroup[moduleName] || moduleName || urlOrModuleName; + return apps.map[code] ? code : ''; +} + +/** + * Toggle left menu + * @param {boolean} [toggle] + * @returns {boolean} + */ +function toggleMenu(toggle) +{ + var $body = $('body'); + if (toggle === undefined) toggle = $body.hasClass('hide-menu'); + $body.toggleClass('hide-menu', !toggle).toggleClass('show-menu', !!toggle); + + const $toggle = $('#menuToggleMenu .menu-toggle'); + $toggle.attr('data-title', $toggle.data(toggle ? 'collapseText' : 'unfoldText')); + + $.cookie.set('hideMenu', String(!toggle), {expires: config.cookieLife, path: config.webRoot}); + return toggle; +} + +/** + * Refresh more menu in #menuNav + * @return {void} + */ +function refreshMenu() +{ + const $mainNav = $('#menuMainNav'); + const $list = $('#menuMoreList'); + const $menuNav = $('#menuNav'); + const $menuItems = $mainNav.children('li'); + const itemHeight = $menuItems.first().outerHeight(); + const maxHeight = $menuNav.outerHeight() - 12; + const dividerHeight = 13; + let showMoreMenu = false; + let currentHeight = itemHeight; + let moreMenuHeight = 12; + + $menuItems.each(function() + { + var $item = $(this); + var isDivider = $item.hasClass('divider'); + var height = isDivider ? dividerHeight : itemHeight; + currentHeight += height; + + if(currentHeight > maxHeight) + { + $item.addClass('hidden'); + if(!showMoreMenu) + { + showMoreMenu = true; + $list.empty(); + + var $prevItem = $item.prev(); + if($prevItem.hasClass('divider')) $prevItem.addClass('hidden'); + + if(isDivider) return; + } + moreMenuHeight += isDivider ? dividerHeight : itemHeight; + $list.append($item.clone().removeClass('hidden')); + } + else + { + $item.removeClass('hidden'); + } + }); + + /* The magic number "111" is the space between dropdown trigger btn and the bottom of screen */ + let listStyle = {maxHeight: 'initial', top: moreMenuHeight > 111 ? 111 - moreMenuHeight : ''}; + if($list[0] && $list[0].getBoundingClientRect) + { + const btnBounding = $list.prev('a')[0].getBoundingClientRect(); + if(btnBounding.height) + { + const winHeight = $(window).height(); + if(winHeight < moreMenuHeight) + { + listStyle.maxHeight = winHeight; + listStyle.overflow = 'auto'; + listStyle.top = 5 - btnBounding.top; + } + else if(moreMenuHeight > (winHeight - btnBounding.top)) + { + listStyle.top = winHeight - btnBounding.top - moreMenuHeight + 5; + } + } + } + $list.css(listStyle); + $menuNav.toggleClass('show-more-nav', showMoreMenu); + + if(showMoreMenu && !$list.data('listened-click')) + { + $list.data('listened-click', true).on('click', function() + { + $list.addClass('hidden'); + setTimeout(function(){$list.removeClass('hidden')}, 200); + }); + } +} + +/** + * Init apps menu list + */ +(() => +{ + const $helpLink = $('#helpLink'); + if($helpLink.length) + { + apps.map.help = + { + code: 'help', + icon: 'icon-help', + url: manualUrl || $helpLink.attr('href'), + external: true, + text: manualText || $helpLink.text(), + appUrl: config.webRoot + '#app=help' + }; + } + + const $menuMainNav = $('#menuMainNav').empty(); + appsItems.forEach(function(item) + { + if(item === 'divider') return $menuMainNav.append('
  • '); + + const $link= $('') + .attr('data-app', item.code) + .addClass('rounded show-in-app') + .html(item.title); + + item.icon = ($link.find('.icon').attr('class') || '').replace('icon ', ''); + item.text = $link.text().trim(); + $link.html('' + item.text + ''); + if(item.code === 'devops') $link.find('.text').addClass('num'); + apps.map[item.code] = item; + + $('
  • ').attr('data-app', item.code) + .attr({'data-toggle': 'tooltip', 'data-placement': 'right', 'data-title': item.text}) + .append($link) + .appendTo($menuMainNav); + + if(!apps.defaultCode) apps.defaultCode = item.code; + }); + + apps.map.search = + { + opened: false, + code: 'search', + group: 'search', + icon: 'icon-search', + methodName: 'index', + moduleName: 'search', + text: lang.search, + title: ' ' + lang.search, + url: '/index.php?m=search&f=index', + vars: '' + }; +})(); + +/* Refresh more menu on window resize */ +$(window).on('resize', refreshMenu); +refreshMenu(); +setTimeout(refreshMenu, 500); + +/* Bind event for menut-toggle */ +$(document).on('click', '.menu-toggle', () => toggleMenu()); +toggleMenu(!$('body').hasClass('hide-menu')); + +/* Bind events for app trigger */ +$(document).on('click', '.open-in-app,.show-in-app', function(e) +{ + const $link = $(this); + if($link.is('[data-modal],[data-toggle],.iframe,.not-in-app')) return; + const url = $link.attr('href') || $link.data('url'); + if(url && url.includes('onlybody=yes')) return; + if(openApp(url, $link.data('app'), !$link.hasClass('show-in-app'))) + { + e.preventDefault(); + } +}).on('contextmenu', '.open-in-app,.show-in-app', function(event) +{ + const $btn = $(this); + const code = $btn.data('app'); + if(!code) return; + + const app = apps.openedMap[code]; + const items = [{text: lang.open, disabled: app && apps.lastCode === code, onClick: function(){showApp(code)}}]; + if(app) + { + items.push({text: lang.reload, onClick: function(){reloadApp(code)}}); + if(code !== 'my') items.push({text: lang.close, onClick: function(){closeApp(code)}}); + } + + const options = {items: items, event: event, onClickItem: function(_item, _$item, e){e.preventDefault();}}; + zui.ContextMenu.show(options); + event.preventDefault(); +}); + +$(window).on('popstate', function(event) +{ + const state = event.state; + if(debug) console.log('[APPS]', 'popstate:', state); + openApp(state.url, state.code, state.type !== 'show'); +}); + +$.get($.createLink('index', 'app'), html => +{ + apps.frameContent = html; + + /* Open default app */ + let defaultOpenUrl = defaultOpen || apps.defaultCode; + if(location.hash.indexOf('#app=') === 0) + { + const params = $.parseSearchParams(location.hash.substring(1)); + defaultOpenUrl = params.app; + } + openApp.apply(null, defaultOpenUrl.split(',')); +}); + +$.apps = $.extend(apps, +{ + openApp: openApp, + reloadApp: reloadApp, + showApp: showApp, + updateApp: updateApp, + getLastApp: getLastApp, +}); diff --git a/module/index/ui/app.html.php b/module/index/ui/app.html.php new file mode 100644 index 0000000000..64b7699ee2 --- /dev/null +++ b/module/index/ui/app.html.php @@ -0,0 +1,7 @@ +visions, ',') == 'lite') +{ + $version = $config->liteVersion; + $versionName = $lang->liteName . $config->liteVersion; +} +else +{ + $version = $config->version; + $versionName = $lang->pmsName . $config->version; +} + +jsVar('vision', $config->vision); +jsVar('navGroup', $lang->navGroup); +jsVar('appsItems', commonModel::getMainNavList($app->rawModule)); +jsVar('defaultOpen', (isset($open) and !empty($open)) ? $open : ''); +jsVar('manualText', $lang->manual); +jsVar('manualUrl', ((!empty($config->isINT)) ? $config->manualUrl['int'] : $config->manualUrl['home']) . '&theme=' . $_COOKIE['theme']); +jsVar('searchObjectList', array_keys($lang->searchObjects)); +jsVar('lang', array_merge(['search' => $lang->index->search, 'searchAB' => $lang->searchAB], (array)$lang->index->app)); + +set::zui(true); +set::bodyClass($this->cookie->hideMenu ? 'hide-menu' : 'show-menu'); + +/* The menu fixed on left */ +div +( + set::id('menu'), + div + ( + set::id('menuNav'), + ul(set::class('nav'), set::id('menuMainNav')), + ul + ( + set::class('nav'), + set::id('menuMoreNav'), + li(set::class('divider')), + li + ( + a + ( + set::title($lang->more), + set::href('#menuMoreList'), + icon('more-circle'), + span(set::class('text'), $lang->more), + toggle('dropdown') + ), + ul(set::class('menu dropdown-menu menu-popup'), set::id('menuMoreList')) + ) + ), + ), + div + ( + set::id('menuFooter'), + ul + ( + set::class('nav'), + li + ( + set::id('menuToggleMenu'), + a + ( + set::class('menu-toggle justify-center'), + toggle::tooltip(['placement' => 'right', 'collapse-text' => $lang->collapseMenu, 'unfold-text' => $lang->unfoldMenu]), + icon('menu-collapse icon-sm') + ) + ) + ) + ) +); + +div +( + set::id('appsBar'), + ul + ( + set::id('appTabs'), + set::class('nav') + ), + toolbar + ( + set::id('appsToolbar'), + item + ( + set::class('ghost btn-zentao'), + set::icon('zentao text-2xl'), + set::url('$lang->website'), + set::target('_blank'), + set::hint($version), + set::text($versionName) + ) + ) +); + +div +( + set::id('apps'), +); + +render('pagebase'); diff --git a/module/product/config.php b/module/product/config.php index 93a32df9cf..2bd1423009 100644 --- a/module/product/config.php +++ b/module/product/config.php @@ -134,6 +134,161 @@ $config->product->edit = new stdclass(); $config->product->create->requiredFields = 'name,code'; $config->product->edit->requiredFields = 'name,code'; +$config->product->create->fields['program'] = array('control' => 'select', 'options' => ''); +$config->product->create->fields['name'] = array('control' => 'input'); +$config->product->create->fields['code'] = array('control' => 'input'); +$config->product->create->fields['PO'] = array('control' => 'select', 'options' => ''); +$config->product->create->fields['QD'] = array('control' => 'select', 'options' => ''); +$config->product->create->fields['RD'] = array('control' => 'select', 'options' => ''); +$config->product->create->fields['reviewer'] = array('control' => 'select', 'options' => 'users'); +$config->product->create->fields['type'] = array('control' => 'select', 'options' => $lang->product->typeList); +$config->product->create->fields['desc'] = array('control' => 'textarea'); +$config->product->create->fields['acl'] = array('control' => 'radio', 'options' => $lang->product->aclList); +$config->product->create->fields['whitelist'] = array('control' => 'multi-select', 'options' => 'users'); + +$config->product->edit->fields['program'] = array('control' => 'select', 'options' => ''); +$config->product->edit->fields['line'] = array('control' => 'select', 'options' => ''); +$config->product->edit->fields['name'] = array('control' => 'input'); +$config->product->edit->fields['code'] = array('control' => 'input'); +$config->product->edit->fields['PO'] = array('control' => 'select', 'options' => ''); +$config->product->edit->fields['QD'] = array('control' => 'select', 'options' => ''); +$config->product->edit->fields['RD'] = array('control' => 'select', 'options' => ''); +$config->product->edit->fields['reviewer'] = array('control' => 'select', 'options' => 'users'); +$config->product->edit->fields['type'] = array('control' => 'select', 'options' => $lang->product->typeList); +$config->product->edit->fields['status'] = array('control' => 'select', 'options' => $lang->product->statusList); +$config->product->edit->fields['desc'] = array('control' => 'textarea'); +$config->product->edit->fields['acl'] = array('control' => 'radio', 'options' => $lang->product->aclList); +$config->product->edit->fields['whitelist'] = array('control' => 'multi-select', 'options' => 'users'); + +$config->product->all->dtable = new stdclass(); +$config->product->all->dtable->fieldList['name']['name'] = 'name'; +$config->product->all->dtable->fieldList['name']['title'] = $lang->product->name; +$config->product->all->dtable->fieldList['name']['minWidth'] = 212; +$config->product->all->dtable->fieldList['name']['fixed'] = 'left'; +$config->product->all->dtable->fieldList['name']['type'] = 'link'; +$config->product->all->dtable->fieldList['name']['flex'] = 1; +$config->product->all->dtable->fieldList['name']['nestedToggle'] = false; +$config->product->all->dtable->fieldList['name']['checkbox'] = true; +$config->product->all->dtable->fieldList['name']['iconRender'] = true; +$config->product->all->dtable->fieldList['name']['sortType'] = true; +$config->product->all->dtable->fieldList['name']['iconRender'] = 'RAWJSRAWJS'; +$config->product->all->dtable->fieldList['name']['align'] = 'left'; + +$config->product->all->dtable->fieldList['productLine']['name'] = 'productLine'; +$config->product->all->dtable->fieldList['productLine']['title'] = $lang->product->belongingLine; +$config->product->all->dtable->fieldList['productLine']['minWidth'] = 114; +$config->product->all->dtable->fieldList['productLine']['type'] = 'format'; +$config->product->all->dtable->fieldList['productLine']['sortType'] = true; +$config->product->all->dtable->fieldList['productLine']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['productLine']['border'] = 'right'; +$config->product->all->dtable->fieldList['productLine']['align'] = 'left'; +$config->product->all->dtable->fieldList['productLine']['flex'] = 1; + +$config->product->all->dtable->fieldList['PO']['name'] = 'PO'; +$config->product->all->dtable->fieldList['PO']['title'] = $lang->product->manager; +$config->product->all->dtable->fieldList['PO']['minWidth'] = 104; +$config->product->all->dtable->fieldList['PO']['type'] = 'avatarBtn'; +$config->product->all->dtable->fieldList['PO']['sortType'] = false; +$config->product->all->dtable->fieldList['PO']['border'] = 'right'; +$config->product->all->dtable->fieldList['PO']['align'] = 'left'; + +$config->product->all->dtable->fieldList['feedback']['name'] = 'feedback'; +$config->product->all->dtable->fieldList['feedback']['title'] = $lang->product->feedback; +$config->product->all->dtable->fieldList['feedback']['minWidth'] = 62; +$config->product->all->dtable->fieldList['feedback']['type'] = 'format'; +$config->product->all->dtable->fieldList['feedback']['sortType'] = false; +$config->product->all->dtable->fieldList['feedback']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['feedback']['border'] = 'right'; +$config->product->all->dtable->fieldList['feedback']['align'] = 'center'; + +$config->product->all->dtable->fieldList['draftStories']['name'] = 'draftStories'; +$config->product->all->dtable->fieldList['draftStories']['title'] = $lang->product->draftStory; +$config->product->all->dtable->fieldList['draftStories']['minWidth'] = 82; +$config->product->all->dtable->fieldList['draftStories']['type'] = 'format'; +$config->product->all->dtable->fieldList['draftStories']['sortType'] = false; +$config->product->all->dtable->fieldList['draftStories']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['draftStories']['align'] = 'center'; + +$config->product->all->dtable->fieldList['activeStories']['name'] = 'activeStories'; +$config->product->all->dtable->fieldList['activeStories']['title'] = $lang->product->activeStory; +$config->product->all->dtable->fieldList['activeStories']['minWidth'] = 62; +$config->product->all->dtable->fieldList['activeStories']['type'] = 'format'; +$config->product->all->dtable->fieldList['activeStories']['sortType'] = false; +$config->product->all->dtable->fieldList['activeStories']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['activeStories']['align'] = 'center'; + +$config->product->all->dtable->fieldList['changingStories']['name'] = 'changingStories'; +$config->product->all->dtable->fieldList['changingStories']['title'] = $lang->product->changingStory; +$config->product->all->dtable->fieldList['changingStories']['minWidth'] = 62; +$config->product->all->dtable->fieldList['changingStories']['type'] = 'format'; +$config->product->all->dtable->fieldList['changingStories']['sortType'] = false; +$config->product->all->dtable->fieldList['changingStories']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['changingStories']['align'] = 'center'; + +$config->product->all->dtable->fieldList['reviewingStories']['name'] = 'reviewingStories'; +$config->product->all->dtable->fieldList['reviewingStories']['title'] = $lang->product->reviewingStory; +$config->product->all->dtable->fieldList['reviewingStories']['minWidth'] = 62; +$config->product->all->dtable->fieldList['reviewingStories']['type'] = 'format'; +$config->product->all->dtable->fieldList['reviewingStories']['sortType'] = false; +$config->product->all->dtable->fieldList['reviewingStories']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['reviewingStories']['align'] = 'center'; + +$config->product->all->dtable->fieldList['storyCompleteRate']['name'] = 'storyCompleteRate'; +$config->product->all->dtable->fieldList['storyCompleteRate']['title'] = $lang->product->storyCompleteRate; +$config->product->all->dtable->fieldList['storyCompleteRate']['minWidth'] = 62; +$config->product->all->dtable->fieldList['storyCompleteRate']['type'] = 'circleProgress'; +$config->product->all->dtable->fieldList['storyCompleteRate']['sortType'] = false; +$config->product->all->dtable->fieldList['storyCompleteRate']['group'] = $lang->SRCommon; +$config->product->all->dtable->fieldList['storyCompleteRate']['border'] = 'right'; + +$config->product->all->dtable->fieldList['plans']['name'] = 'plans'; +$config->product->all->dtable->fieldList['plans']['title'] = $lang->product->plan; +$config->product->all->dtable->fieldList['plans']['minWidth'] = 66; +$config->product->all->dtable->fieldList['plans']['type'] = 'format'; +$config->product->all->dtable->fieldList['plans']['sortType'] = false; +$config->product->all->dtable->fieldList['plans']['border'] = 'right'; +$config->product->all->dtable->fieldList['plans']['align'] = 'center'; + +$config->product->all->dtable->fieldList['execution']['name'] = 'execution'; +$config->product->all->dtable->fieldList['execution']['title'] = $lang->execution->common; +$config->product->all->dtable->fieldList['execution']['minWidth'] = 66; +$config->product->all->dtable->fieldList['execution']['type'] = 'format'; +$config->product->all->dtable->fieldList['execution']['sortType'] = false; +$config->product->all->dtable->fieldList['execution']['border'] = 'right'; +$config->product->all->dtable->fieldList['execution']['align'] = 'center'; + +$config->product->all->dtable->fieldList['testCaseCoverage']['name'] = 'testCaseCoverage'; +$config->product->all->dtable->fieldList['testCaseCoverage']['title'] = $lang->product->testCaseCoverage; +$config->product->all->dtable->fieldList['testCaseCoverage']['minWidth'] = 86; +$config->product->all->dtable->fieldList['testCaseCoverage']['type'] = 'circleProgress'; +$config->product->all->dtable->fieldList['testCaseCoverage']['sortType'] = false; +$config->product->all->dtable->fieldList['testCaseCoverage']['border'] = 'right'; + +$config->product->all->dtable->fieldList['unResolvedBugs']['name'] = 'unResolvedBugs'; +$config->product->all->dtable->fieldList['unResolvedBugs']['title'] = $lang->product->activatedBug; +$config->product->all->dtable->fieldList['unResolvedBugs']['minWidth'] = 62; +$config->product->all->dtable->fieldList['unResolvedBugs']['type'] = 'format'; +$config->product->all->dtable->fieldList['unResolvedBugs']['sortType'] = false; +$config->product->all->dtable->fieldList['unResolvedBugs']['group'] = 'Bug'; +$config->product->all->dtable->fieldList['unResolvedBugs']['align'] = 'center'; + +$config->product->all->dtable->fieldList['bugFixedRate']['name'] = 'bugFixedRate'; +$config->product->all->dtable->fieldList['bugFixedRate']['title'] = $lang->product->bugFixedRate; +$config->product->all->dtable->fieldList['bugFixedRate']['minWidth'] = 62; +$config->product->all->dtable->fieldList['bugFixedRate']['type'] = 'circleProgress'; +$config->product->all->dtable->fieldList['bugFixedRate']['sortType'] = false; +$config->product->all->dtable->fieldList['bugFixedRate']['group'] = 'Bug'; +$config->product->all->dtable->fieldList['bugFixedRate']['border'] = 'right'; + +$config->product->all->dtable->fieldList['releases']['name'] = 'releases'; +$config->product->all->dtable->fieldList['releases']['title'] = $lang->product->release; +$config->product->all->dtable->fieldList['releases']['minWidth'] = 68; +$config->product->all->dtable->fieldList['releases']['type'] = 'format'; +$config->product->all->dtable->fieldList['releases']['sortType'] = false; +$config->product->all->dtable->fieldList['releases']['align'] = 'center'; + +$config->product->actionsMap['normal'] = array('edit'); + $config->product->editor = new stdclass(); $config->product->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'); $config->product->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools'); diff --git a/module/product/control.php b/module/product/control.php index 05964988d9..b40881ffe1 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -387,7 +387,9 @@ class product extends control $this->view->from = $this->app->tab; $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'story', $showModule) : array(); $this->view->project = $project; - $this->display(); + $this->view->recTotal = $pager->recTotal; + + $this->render(); } /** @@ -462,6 +464,7 @@ class product extends control $this->view->poUsers = $poUsers; $this->view->qdUsers = $qdUsers; $this->view->rdUsers = $rdUsers; + $this->view->fields = $this->product->buildFormFields($this->config->product->create->fields); $this->view->users = $this->user->getPairs('nodeleted|noclosed'); $this->view->programs = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed'); $this->view->lines = $lines; @@ -554,13 +557,15 @@ class product extends control $this->view->poUsers = $poUsers; $this->view->qdUsers = $qdUsers; $this->view->rdUsers = $rdUsers; + $this->view->fields = $this->product->buildFormFields($this->config->product->edit->fields, $product); $this->view->users = $this->user->getPairs('nodeleted|noclosed'); $this->view->programs = array('') + $programs; $this->view->lines = $lines; $this->view->URSRPairs = $this->loadModel('custom')->getURSRPairs(); unset($this->lang->product->typeList['']); - $this->display(); + //$this->display(); + $this->render(); } /** @@ -1274,13 +1279,13 @@ class product extends control * @access public * @return void */ - public function all($browseType = 'noclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) + public function all($browseType = 'noclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1, $programID = 0) { /* Load module and set session. */ $this->loadModel('program'); $this->session->set('productList', $this->app->getURI(true), 'product'); - $queryID = ($browseType == 'bySearch') ? (int)$param : 0; + $queryID = ($browseType == 'bySearch' or !empty($param)) ? (int)$param : 0; if($this->app->viewType == 'mhtml') { @@ -1322,8 +1327,13 @@ class product extends control $this->view->browseType = $browseType; $this->view->pager = $pager; $this->view->showBatchEdit = $this->cookie->showProductBatchEdit; + $this->view->param = $param; + $this->view->recPerPage = $recPerPage; + $this->view->pageID = $pageID; + $this->view->programID = $programID; - $this->display(); + //$this->display(); + $this->render(); } /** diff --git a/module/product/css/all.ui.css b/module/product/css/all.ui.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/module/product/js/all.ui.js b/module/product/js/all.ui.js new file mode 100644 index 0000000000..a6ccf517a9 --- /dev/null +++ b/module/product/js/all.ui.js @@ -0,0 +1,24 @@ +window.footerGenerator = function() +{ + const count = this.layout.allRows.filter((x) => x.data.type === "product").length; + const statistic = langSummary.replace('%s', ' ' + count + ' '); + return [{children: statistic, className: "text-dark"}, "flex", "pager"]; +} + +window.renderReleaseCountCell = function(result, {col, row}) +{ + if(!col || !row || col.name !== 'releases') return result; + + var changed = row.data.releases - row.data.releasesOld; + + if(changed === 0) result[0] = 0; + if(changed > 0) result[0] = {html: row.data.releases + ' +' + changed + ''}; + if(changed < 0) result[0] = {html: row.data.releases + ' ' + changed + ''}; + + return result; +} + +window.programMenuOnClick = function(data, url) +{ + location.href = url.replace('%d', data.item.key); +} diff --git a/module/product/lang/de.php b/module/product/lang/de.php index 3bdb1f74fb..9abe84e793 100644 --- a/module/product/lang/de.php +++ b/module/product/lang/de.php @@ -158,6 +158,13 @@ $lang->product->unplan = 'Warten'; $lang->product->viewByUser = 'By User'; $lang->product->assignedByMe = 'AssignedByMe'; +$lang->product->storyCompleteRate = 'Completion Rate'; +$lang->product->bugFixedRate = 'Fixed Rate'; +$lang->product->belongingLine = 'Belong To'; +$lang->product->feedback = 'Feedback'; +$lang->product->testCaseCoverage = 'Coverage'; +$lang->product->activatedBug = 'Activated'; + /* Product Kanban. */ $lang->product->myProduct = "{$lang->productCommon}s Ownedbyme"; $lang->product->otherProduct = "Other {$lang->productCommon}s"; diff --git a/module/product/lang/en.php b/module/product/lang/en.php index deb0b55668..f6f951ec11 100644 --- a/module/product/lang/en.php +++ b/module/product/lang/en.php @@ -158,6 +158,13 @@ $lang->product->unplan = 'Unplanned'; $lang->product->viewByUser = 'By User'; $lang->product->assignedByMe = 'AssignedByMe'; +$lang->product->storyCompleteRate = 'Completion Rate'; +$lang->product->bugFixedRate = 'Fixed Rate'; +$lang->product->belongingLine = 'Belong To'; +$lang->product->feedback = 'Feedback'; +$lang->product->testCaseCoverage = 'Coverage'; +$lang->product->activatedBug = 'Activated'; + /* Product Kanban. */ $lang->product->myProduct = "{$lang->productCommon}s Ownedbyme"; $lang->product->otherProduct = "Other {$lang->productCommon}s"; diff --git a/module/product/model.php b/module/product/model.php index b34abb85fb..1991697930 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -1129,6 +1129,41 @@ class productModel extends model return $this->loadModel('story')->batchGetStoryStage($storyIdList); } + /** + * Build form fields. + * + * @param array $fields + * @param object $project + * @access public + * @return void + */ + public function buildFormFields($fields, $product = null) + { + $this->loadModel('user'); + $poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed', '', $this->config->maxCount); + $qdUsers = $this->user->getPairs('nodeleted|qdfirst|noclosed', '', $this->config->maxCount); + $rdUsers = $this->user->getPairs('nodeleted|devfirst|noclosed', '', $this->config->maxCount); + $users = $this->user->getPairs('nodeleted|noclosed'); + + foreach($fields as $field => $attr) + { + if(isset($attr['options']) and $attr['options'] == 'users') $fields[$field]['options'] = $users; + $fields[$field]['name'] = $field; + $fields[$field]['title'] = $this->lang->product->$field; + if($product and isset($product->$field)) $fields[$field]['default'] = $product->$field; + } + + $fields['program']['options'] = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed'); + $fields['PO']['options'] = $poUsers; + $fields['QD']['options'] = $qdUsers; + $fields['RD']['options'] = $rdUsers; + + if($product and $product->program)$fields['line']['options'] = array('') + $this->getLinePairs($product->program); + if(empty($product->program) or $this->config->systemMode != 'ALM') unset($fields['line']); + + return $fields; + } + /** * Build search form. * @@ -2224,6 +2259,7 @@ class productModel extends model /* Program name. */ $productStructure[$product->program]['programName'] = $product->programName; $productStructure[$product->program]['programPM'] = $product->programPM; + $productStructure[$product->program]['id'] = $product->program; $productStructure[$product->program] = $this->statisticData('program', $productStructure, $product); } } @@ -2655,4 +2691,113 @@ class productModel extends model return $statsData; } + + public function buildRows($productStructure, $params = array()) + { + $programLines = zget($params, 'programLines', array()); + $users = zget($params, 'users', array()); + $usersAvatar = zget($params, 'usersAvatar', array()); + $userIdPairs = zget($params, 'userIdPairs', array()); + + $rows = array(); + foreach($productStructure as $programID => $program) + { + if($programID and $this->config->systemMode == 'ALM') $rows[] = $this->buildRowData($programID, $program, 'program', $params); + + if(isset($programLines[$programID])) + { + foreach($programLines[$programID] as $lineID => $lineName) + { + if(!isset($program[$lineID])) + { + $program[$lineID] = array(); + $program[$lineID]['product'] = ''; + $program[$lineID]['lineName'] = $lineName; + } + } + } + + foreach($program as $lineID => $line) + { + $showLine = (isset($line['lineName']) and $this->config->systemMode == 'ALM'); + if($showLine) + { + $params['parent'] = 'program_' . $programID; + $rows[] = $this->buildRowData($lineID, $line, 'line', $params); + } + + if(isset($line['products']) and is_array($line['products'])) + { + foreach($line['products'] as $productID => $product) + { + $params['parent'] = $showLine ? 'line_' . $lineID : 'program_' . $programID; + $rows[] = $this->buildRowData($productID, $product, 'product', $params); + } + } + } + } + + return $rows; + } + + public function buildRowData($id, $data, $type = 'program', $params = array()) + { + $programLines = zget($params, 'programLines', array()); + $users = zget($params, 'users', array()); + $usersAvatar = zget($params, 'usersAvatar', array()); + $userIdPairs = zget($params, 'userIdPairs', array()); + + $row = new stdclass(); + $row->id = $id; + if($type == 'program') $row->id = 'program_' . $id; + if($type == 'line') $row->id = 'line_' . $id; + + $row->name = ''; + if($type == 'program') $row->name = zget($data, 'programName', ''); + if($type == 'line') $row->name = zget($data, 'lineName', ''); + if($type == 'product') $row->name = common::hasPriv('product', 'browse') ? html::a(helper::createLink('product', 'browse', 'productID=' . $id), $data->name) : $data->name; + + $row->draftStories = zget($data, 'draftStories', 0); + $row->activeStories = zget($data, 'activeStories', 0); + $row->changingStories = zget($data, 'changingStories', 0); + $row->reviewingStories = zget($data, 'reviewingStories', 0); + $row->unResolvedBugs = zget($data, 'unResolvedBugs', 0); + $row->plans = zget($data, 'plans', 0); + $row->releases = zget($data, 'releases', 0); + + $totalStories = zget($data, 'finishClosedStories', 0) + zget($data, 'unclosedStories', 0); + $totalBugs = zget($data, 'unResolvedBugs', 0) + zget($data, 'fixedBugs', 0); + $row->storyCompleteRate = $totalStories == 0 ? 0 : (round(zget($data, 'finishClosedStories', 0) / $totalStories, 3) * 100) . '%'; + $row->bugFixedRate = $totalBugs == 0 ? 0 : (round(zget($data, 'fixedBugs', 0) / $totalBugs, 3) * 100) . '%'; + $row->actions = $type == 'product' ? $this->buildOperateMenu($data, 'list') : ''; + $row->parent = $type == 'program' ? '' : zget($params, 'parent', ''); + $row->type = $type; + + if($type == 'product') + { + $row->draftStories = $data->stories['draft']; + $row->activeStories = $data->stories['active']; + $row->changingStories = $data->stories['changing']; + $row->reviewingStories = $data->stories['reviewing']; + $row->unResolvedBugs = $data->unResolved; + + $totalStories = $data->stories['finishClosed'] + $data->stories['unclosed']; + $totalBugs = $data->unResolved + $data->fixedBugs; + $row->storyCompleteRate = $totalStories == 0 ? 0 : (round($data->stories['finishClosed'] / $totalStories, 3) * 100) . '%'; + $row->bugFixedRate = $totalBugs == 0 ? 0 : (round($data->fixedBugs / $totalBugs, 3) * 100) . '%'; + + } + + $row->PO = ''; + $row->POAvatar = ''; + if(($type == 'program' and !empty($data['programPM'])) or ($type == 'product' and !empty($data->PO))) + { + if($type == 'program') $PO = $data['programPM']; + if($type == 'product') $PO = $data->PO; + $row->PO = zget($users, $PO); + $row->POAvatar = zget($usersAvatar, $PO); + } + + return $row; + } } diff --git a/module/product/ui/all.html.php b/module/product/ui/all.html.php new file mode 100644 index 0000000000..705ace43f8 --- /dev/null +++ b/module/product/ui/all.html.php @@ -0,0 +1,161 @@ +product->all->dtable->fieldList); + +/* TODO: implements extend fields. */ +$extendFields = $this->product->getFlowExtendFields(); + +$data = array(); +$totalStories = 0; +$programs = array(); +foreach($productStructure as $proID => $program) +{ + if(isset($programLines[$proID])) + { + foreach($programLines[$proID] as $lineID => $lineName) + { + if(!isset($program[$lineID])) + { + $program[$lineID] = array(); + $program[$lineID]['product'] = ''; + $program[$lineID]['lineName'] = $lineName; + } + } + } + + if(isset($program['programName'])) + { + $pro = new stdClass(); + $pro->id = $program['id']; + $pro->name = $program['programName']; + $pro->parent = null; + + $programs[] = $pro; + } + + foreach($program as $lineID => $line) + { + /* Products of Product Line. */ + if(isset($line['products']) and is_array($line['products'])) + { + foreach($line['products'] as $productID => $product) + { + $item = new stdClass(); + + if(!empty($product->PO)) + { + $item->PO = zget($users, $product->PO); + $item->POAvatar = $usersAvatar[$product->PO]; + $item->POAccount = $product->PO; + } + $totalStories = $product->stories['finishClosed'] + $product->stories['unclosed']; + + $item->name = $product->name; /* TODO replace with */ + $item->id = $product->id; + $item->type = 'product'; + $item->draftStories = $product->stories['draft']; + $item->activeStories = $product->stories['active']; + $item->changingStories = $product->stories['changing']; + $item->reviewingStories = $product->stories['reviewing']; + $item->storyCompleteRate = ($totalStories == 0 ? 0 : round($product->stories['finishClosed'] / $totalStories, 3) * 100); + $item->unResolvedBugs = $product->unResolved; + $item->bugFixedRate = (($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100); + $item->plans = $product->plans; + $item->releases = $product->releases; + $item->parent = null; + $item->productLine = $product->line ? $line['lineName'] : ''; + $item->execution = rand(0, 10); + $item->feedback = rand(0, 100); + $item->testCaseCoverage = rand(0, 100); + $item->releasesOld = rand(0, 10); + /* TODO attach extend fields. */ + + $data[] = $item; + } + } + } +} + +$programMenuLink = createLink( + $this->app->rawModule, + $this->app->rawMethod, + array( + 'browseType' => $browseType, + 'orderBy' => $orderBy, + 'param' => $param, + 'recTotal' => $recTotal, + 'recPerPage' => $recPerPage, + 'pageID' => $pageID, + 'programID' => '%d' + ) +); + +featureBar +( + to::before + ( + programMenu + ( + setStyle(array('margin-right' => '20px')), + set + ( + array + ( + 'title' => $lang->program->all, + 'programs' => $programs, + 'activeKey' => !empty($programs) ? $programID : null, + 'closeLink' => sprintf($programMenuLink, 0), + 'onClickItem' => jsRaw("function(data){window.programMenuOnClick(data, '$programMenuLink');}") + ) + ) + ) + ), + hasPriv('product', 'batchEdit') ? item + ( + set::type('checkbox'), + set::text($lang->product->edit), + set::checked($this->cookie->editProject) + ) : NULL, + li(searchToggle(set::open($browseType == 'bySearch'))) +); + +toolbar +( + item(set(array + ( + 'text' => $lang->export, + 'icon' => 'export', + 'class' => 'ghost text-darker', + 'url' => createLink('product', 'export', $browseType, "status=$browseType&orderBy=$orderBy"), + ))), + div(setClass('nav-divider')), + $config->systemMode == 'ALM' ? item(set(array + ( + 'text' => $lang->product->editLine, + 'icon' => 'edit', + 'class' => 'ghost', + 'url' => createLink('product', 'manageLine', $browseType), + ))) : NULL, + item(set(array + ( + 'text' => $lang->product->create, + 'icon' => 'plus', + 'class' => 'primary', + 'url' => createLink('product', 'create') + ))) +); + + +jsVar('langSummary', $lang->product->pageSummary); + +dtable +( + set::cols($cols), + set::data($data), + set::footPager(usePager()), + set::nested(true), + set::footer(jsRaw('function(){return window.footerGenerator.call(this);}')) +); + +render(); diff --git a/module/product/ui/browse.html.php b/module/product/ui/browse.html.php new file mode 100644 index 0000000000..35a5c22f26 --- /dev/null +++ b/module/product/ui/browse.html.php @@ -0,0 +1,137 @@ +app->rawModule == 'projectstory'; +$projectHasProduct = $isProjectStory && !empty($project->hasProduct); +$projectIDParam = $isProjectStory ? "projectID=$projectID&" : ''; +$storyBrowseType = $this->session->storyBrowseType; + +/* More menus. */ +$featureBarMore = array(); +if(!\commonModel::isTutorialMode()) +{ + foreach($lang->product->moreSelects as $key => $value) + { + $active = $key == $storyBrowseType ? 'btn-active-text' : ''; + $featureBarMore[] = array( + 'text' => $value, + 'url' => createLink($this->app->rawModule, $this->app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$key¶m=0&storyType=$storyType"), + 'class' => $active + ); + } +} + +/* Create Button of toolbar. */ +$createBtnLink = ''; +$createBtnTitle = ''; +if(hasPriv($storyType, 'create')) +{ + $createBtnLink = createLink('story', 'create', "product=$productID&branch=$branch&moduleID=$moduleID&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&storyType=$storyType"); + $createBtnTitle = $lang->story->create; +} +elseif(hasPriv($storyType, 'batchCreate')) +{ + $createBtnLink = empty($productID) ? '' : createLink('story', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID&storyID=0&project=$projectID&plan=0&storyType=$storyType"); + $createBtnTitle = $lang->story->batchCreate; +} + +/* DataTable. */ +$setting = $this->datatable->getSetting('product'); +$cols = array_values($setting); +foreach($cols as $key => $col) +{ + $col->name = $col->id; + $col->width = 80; + $col->fixed = false; + if($col->id == 'title') + { + $col->flex = 1; + $col->type = 'link'; + $col->sortType = true; + $col->nestedToggle = true; + $col->width = 300; + $col->checkbox = true; + } + $cols[$key] = $col; +} + +$data = array(); +foreach($stories as $story) +{ + $story->taskCount = $storyTasks[$story->id]; + $data[] = $story; + if(!isset($story->children)) continue; + + /* Children. */ + foreach($story->children as $key => $child) + { + $child->taskCount = $storyTasks[$child->id]; + $data[] = $child; + } +} + +useData('storyBrowseType', $storyBrowseType); + +featureBar +( + set::moreMenuLinkCallback + ( + function($key, $value) use($projectIDParam, $productID, $branch, $storyType) + { + global $app; + return createLink($app->rawModule, $app->rawMethod, $projectIDParam . "productID=$productID&branch=$branch&browseType=$key¶m=0&storyType=$storyType"); + } + ), + li(searchToggle()) +); + +toolbar +( + item(set(array + ( + 'text' => $lang->project->report, + 'icon' => 'bar-chart', + 'class' => 'secondary' + ))), + item(set(array + ( + 'text' => $lang->export, + 'icon' => 'export', + 'class' => 'secondary', + 'url' => createLink('product', 'export', $browseType, "status=$browseType&orderBy=$orderBy"), + ))), + item(set(array + ( + 'text' => $lang->import, + 'icon' => 'import', + 'class' => 'secondary', + 'url' => createLink('product', 'manageLine', $browseType), + ))), + item(set(array + ( + 'text' => $createBtnTitle, + 'icon' => 'plus', + 'class' => $from == 'project' ? 'secondary' : 'primary', + 'url' => $createBtnLink + ))) +); + +js +(<<buildForm($fields); +$form->buildFormAction(); + +$content = block(); +$content->from = $form; + +$page = page('create'); +$page->right->content = $content; +$page->x(); diff --git a/module/product/ui/data.php b/module/product/ui/data.php new file mode 100644 index 0000000000..b898fdb3bb --- /dev/null +++ b/module/product/ui/data.php @@ -0,0 +1,28 @@ +id = '6'; +$program6->parent = '0'; +$program6->name = '企业管理'; + +$program7 = new stdClass(); +$program7->id = '7'; +$program7->parent = '6'; +$program7->name = '企业系统管理'; + +$program8 = new stdClass(); +$program8->id = '8'; +$program8->parent = '6'; +$program8->name = '测试项目'; + +$program15 = new stdClass(); +$program15->id = '15'; +$program15->parent = '0'; +$program15->name = '测试项目集一'; + +$program16 = new stdClass(); +$program16->id = '16'; +$program16->parent = '15'; +$program16->name = 'scrum'; + +$programs = array($program6, $program7, $program8, $program15, $program16); diff --git a/module/product/ui/edit.html.php b/module/product/ui/edit.html.php new file mode 100644 index 0000000000..abec40ebca --- /dev/null +++ b/module/product/ui/edit.html.php @@ -0,0 +1,13 @@ +program); + +$form = form(); +$form->buildForm($fields); +$form->buildFormAction(); + +$content = block(); +$content->from = $form; + +$page = page('create'); +$page->right->content = $content; +$page->x(); diff --git a/module/program/config.php b/module/program/config.php index 410532db8d..f31c85bb61 100644 --- a/module/program/config.php +++ b/module/program/config.php @@ -43,11 +43,245 @@ $config->program->search['params']['name'] = array('operator' => 'incl $config->program->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '') + $lang->program->statusList); $config->program->search['params']['desc'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); $config->program->search['params']['PM'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); -$config->program->search['params']['openedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); -$config->program->search['params']['begin'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); -$config->program->search['params']['end'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->program->search['params']['openedDate'] = array('operator' => '=', 'control' => 'date', 'values' => ''); +$config->program->search['params']['begin'] = array('operator' => '=', 'control' => 'date', 'values' => ''); +$config->program->search['params']['end'] = array('operator' => '=', 'control' => 'date', 'values' => ''); $config->program->search['params']['openedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); -$config->program->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); -$config->program->search['params']['realBegan'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); -$config->program->search['params']['realEnd'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); -$config->program->search['params']['closedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->program->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'date', 'values' => ''); +$config->program->search['params']['realBegan'] = array('operator' => '=', 'control' => 'date', 'values' => ''); +$config->program->search['params']['realEnd'] = array('operator' => '=', 'control' => 'date', 'values' => ''); +$config->program->search['params']['closedDate'] = array('operator' => '=', 'control' => 'date', 'values' => ''); + +/* Data table field config. */ +global $lang; +$config->program->dtable = new stdclass(); + +$config->program->dtable->fieldList['name']['name'] = 'name'; +$config->program->dtable->fieldList['name']['title'] = $lang->nameAB; +$config->program->dtable->fieldList['name']['width'] = 356; +$config->program->dtable->fieldList['name']['type'] = 'link'; +$config->program->dtable->fieldList['name']['flex'] = 1; +$config->program->dtable->fieldList['name']['nestedToggle'] = true; +$config->program->dtable->fieldList['name']['checkbox'] = true; +$config->program->dtable->fieldList['name']['iconRender'] = true; +$config->program->dtable->fieldList['name']['sortType'] = false; + +$config->program->dtable->fieldList['status']['name'] = 'status'; +$config->program->dtable->fieldList['status']['title'] = $lang->program->status; +$config->program->dtable->fieldList['status']['minWidth'] = 60; +$config->program->dtable->fieldList['status']['type'] = 'status'; +$config->program->dtable->fieldList['status']['sortType'] = true; +$config->program->dtable->fieldList['status']['statusMap'] = $lang->program->statusList; + +$config->program->dtable->fieldList['PM']['name'] = 'PM'; +$config->program->dtable->fieldList['PM']['title'] = $lang->program->PM; +$config->program->dtable->fieldList['PM']['minWidth'] = 100; +$config->program->dtable->fieldList['PM']['type'] = 'avatarBtn'; +$config->program->dtable->fieldList['PM']['sortType'] = true; + +$config->program->dtable->fieldList['budget']['name'] = 'budget'; +$config->program->dtable->fieldList['budget']['title'] = $lang->program->budget; +$config->program->dtable->fieldList['budget']['minWidth'] = 70; +$config->program->dtable->fieldList['budget']['type'] = 'format'; +$config->program->dtable->fieldList['budget']['sortType'] = true; + +$config->program->dtable->fieldList['begin']['name'] = 'begin'; +$config->program->dtable->fieldList['begin']['title'] = $lang->program->begin; +$config->program->dtable->fieldList['begin']['minWidth'] = 90; +$config->program->dtable->fieldList['begin']['type'] = 'datetime'; +$config->program->dtable->fieldList['begin']['sortType'] = true; + +$config->program->dtable->fieldList['end']['name'] = 'end'; +$config->program->dtable->fieldList['end']['title'] = $lang->program->end; +$config->program->dtable->fieldList['end']['minWidth'] = 90; +$config->program->dtable->fieldList['end']['type'] = 'datetime'; +$config->program->dtable->fieldList['end']['sortType'] = true; + +$config->program->dtable->fieldList['progress']['name'] = 'progress'; +$config->program->dtable->fieldList['progress']['title'] = $lang->program->progressAB; +$config->program->dtable->fieldList['progress']['minWidth'] = 100; +$config->program->dtable->fieldList['progress']['type'] = 'circleProgress'; + +$config->program->dtable->fieldList['actions']['name'] = 'actions'; +$config->program->dtable->fieldList['actions']['title'] = $lang->actions; +$config->program->dtable->fieldList['actions']['width'] = 160; +$config->program->dtable->fieldList['actions']['type'] = 'actions'; +$config->program->dtable->fieldList['actions']['fixed'] = 'right'; +$config->program->dtable->fieldList['actions']['module'] = 'program'; + +global $app; +$app->loadLang('project'); +$config->program->actionsMap['normal'] = array('start', 'suspend', 'close', 'activate', 'edit', 'create', 'delete', 'team', 'group'); +$config->program->actionsMap['other'] = array('start', 'suspend', 'close', 'activate'); +$config->program->actionsMap['more'] = array('link', 'whitelist', 'delete'); +$config->program->actionsMap['hint']['create'] = $lang->program->children; +$config->program->actionsMap['hint']['delete'] = $lang->delete; +$config->program->actionsMap['hint']['team'] = $lang->project->team; +$config->program->actionsMap['hint']['group'] = $lang->project->group; +$config->program->actionsMap['text']['start'] = $lang->program->start; +$config->program->actionsMap['text']['suspend'] = $lang->program->suspend; +$config->program->actionsMap['text']['close'] = $lang->close; +$config->program->actionsMap['text']['activate'] = $lang->program->activate; +$config->program->actionsMap['text']['delete'] = $lang->delete; +$config->program->actionsMap['text']['link'] = $lang->project->manageProducts; +$config->program->actionsMap['text']['whitelist'] = $lang->project->whitelist; +$config->program->actionsMap['text']['delete'] = $lang->delete; + +/* DataTable fields of Product View. */ +$config->program->productView = new stdClass(); +$config->program->productView->dtable = new stdClass(); +$config->program->productView->dtable->fieldList = array(); + +$config->program->productView->dtable->fieldList['name']['name'] = 'name'; +$config->program->productView->dtable->fieldList['name']['title'] = $lang->nameAB; +$config->program->productView->dtable->fieldList['name']['width'] = 200; +$config->program->productView->dtable->fieldList['name']['type'] = 'link'; +$config->program->productView->dtable->fieldList['name']['flex'] = 1; +$config->program->productView->dtable->fieldList['name']['nestedToggle'] = true; +$config->program->productView->dtable->fieldList['name']['checkbox'] = true; +$config->program->productView->dtable->fieldList['name']['sortType'] = true; +$config->program->productView->dtable->fieldList['name']['iconRender'] = 'RAWJSRAWJS'; + +$config->program->productView->dtable->fieldList['PM']['name'] = 'PM'; +$config->program->productView->dtable->fieldList['PM']['title'] = $lang->program->PM; +$config->program->productView->dtable->fieldList['PM']['minWidth'] = 80; +$config->program->productView->dtable->fieldList['PM']['type'] = 'avatarBtn'; + +$config->program->productView->dtable->fieldList['feedback']['name'] = 'feedback'; +$config->program->productView->dtable->fieldList['feedback']['title'] = $lang->program->feedback; +$config->program->productView->dtable->fieldList['feedback']['width'] = 60; +$config->program->productView->dtable->fieldList['feedback']['type'] = 'format'; +$config->program->productView->dtable->fieldList['feedback']['sortType'] = true; + +$config->program->productView->dtable->fieldList['unclosedReqCount']['name'] = 'unclosedReqCount'; +$config->program->productView->dtable->fieldList['unclosedReqCount']['title'] = $lang->program->unclosedReqCount; +$config->program->productView->dtable->fieldList['unclosedReqCount']['minWidth'] = 100; +$config->program->productView->dtable->fieldList['unclosedReqCount']['type'] = 'format'; +$config->program->productView->dtable->fieldList['unclosedReqCount']['sortType'] = true; + +$config->program->productView->dtable->fieldList['closedReqRate']['name'] = 'closedReqRate'; +$config->program->productView->dtable->fieldList['closedReqRate']['title'] = $lang->program->closedReqRate; +$config->program->productView->dtable->fieldList['closedReqRate']['minWidth'] = 100; +$config->program->productView->dtable->fieldList['closedReqRate']['type'] = 'circleProgress'; +$config->program->productView->dtable->fieldList['closedReqRate']['sortType'] = true; + +$config->program->productView->dtable->fieldList['planCount']['name'] = 'plans'; +$config->program->productView->dtable->fieldList['planCount']['title'] = $lang->productplan->shortCommon; +$config->program->productView->dtable->fieldList['planCount']['width'] = 60; +$config->program->productView->dtable->fieldList['planCount']['type'] = 'format'; +$config->program->productView->dtable->fieldList['planCount']['sortType'] = true; + +$config->program->productView->dtable->fieldList['executionCount']['name'] = 'executionCount'; +$config->program->productView->dtable->fieldList['executionCount']['title'] = $lang->execution->common; +$config->program->productView->dtable->fieldList['executionCount']['width'] = 60; +$config->program->productView->dtable->fieldList['executionCount']['type'] = 'format'; +$config->program->productView->dtable->fieldList['executionCount']['sortType'] = true; + +$config->program->productView->dtable->fieldList['testCaseCoverage']['name'] = 'testCaseCoverage'; +$config->program->productView->dtable->fieldList['testCaseCoverage']['title'] = $lang->program->testCaseCoverage; +$config->program->productView->dtable->fieldList['testCaseCoverage']['minWidth'] = 100; +$config->program->productView->dtable->fieldList['testCaseCoverage']['type'] = 'circleProgress'; +$config->program->productView->dtable->fieldList['testCaseCoverage']['sortType'] = true; + +$config->program->productView->dtable->fieldList['bugActivatedCount']['name'] = 'unResolvedBugs'; +$config->program->productView->dtable->fieldList['bugActivatedCount']['title'] = $lang->program->bugActivatedCount; +$config->program->productView->dtable->fieldList['bugActivatedCount']['minWidth'] = 60; +$config->program->productView->dtable->fieldList['bugActivatedCount']['type'] = 'format'; +$config->program->productView->dtable->fieldList['bugActivatedCount']['sortType'] = true; + +$config->program->productView->dtable->fieldList['fixedRate']['name'] = 'fixedRate'; +$config->program->productView->dtable->fieldList['fixedRate']['title'] = $lang->program->fixedRate; +$config->program->productView->dtable->fieldList['fixedRate']['minWidth'] = 60; +$config->program->productView->dtable->fieldList['fixedRate']['type'] = 'circleProgress'; +$config->program->productView->dtable->fieldList['fixedRate']['sortType'] = true; + +$config->program->productView->dtable->fieldList['releaseCount']['name'] = 'releaseCount'; +$config->program->productView->dtable->fieldList['releaseCount']['title'] = $lang->release->common; +$config->program->productView->dtable->fieldList['releaseCount']['width'] = 80; +$config->program->productView->dtable->fieldList['releaseCount']['type'] = 'html'; +$config->program->productView->dtable->fieldList['releaseCount']['sortType'] = false; + +/* DataTable fields of Project View. */ +$config->program->projectView = new stdClass(); +$config->program->projectView->dtable = new stdClass(); +$config->program->projectView->dtable->fieldList = array(); + +$config->program->projectView->dtable->fieldList['name']['name'] = 'name'; +$config->program->projectView->dtable->fieldList['name']['title'] = $lang->nameAB; +$config->program->projectView->dtable->fieldList['name']['width'] = 200; +$config->program->projectView->dtable->fieldList['name']['type'] = 'link'; +$config->program->projectView->dtable->fieldList['name']['flex'] = 1; +$config->program->projectView->dtable->fieldList['name']['nestedToggle'] = true; +$config->program->projectView->dtable->fieldList['name']['checkbox'] = true; +$config->program->projectView->dtable->fieldList['name']['sortType'] = true; +$config->program->projectView->dtable->fieldList['name']['iconRender'] = 'RAWJSRAWJS'; + +$config->program->projectView->dtable->fieldList['status']['name'] = 'status'; +$config->program->projectView->dtable->fieldList['status']['title'] = $lang->program->status; +$config->program->projectView->dtable->fieldList['status']['minWidth'] = 60; +$config->program->projectView->dtable->fieldList['status']['type'] = 'status'; +$config->program->projectView->dtable->fieldList['status']['sortType'] = true; +$config->program->projectView->dtable->fieldList['status']['statusMap'] = $lang->program->statusList; + +$config->program->projectView->dtable->fieldList['PM']['name'] = 'PM'; +$config->program->projectView->dtable->fieldList['PM']['title'] = $lang->program->PM; +$config->program->projectView->dtable->fieldList['PM']['minWidth'] = 80; +$config->program->projectView->dtable->fieldList['PM']['type'] = 'avatarBtn'; +$config->program->projectView->dtable->fieldList['PM']['sortType'] = true; + +$config->program->projectView->dtable->fieldList['budget']['name'] = 'budget'; +$config->program->projectView->dtable->fieldList['budget']['title'] = $lang->program->budget; +$config->program->projectView->dtable->fieldList['budget']['width'] = 90; +$config->program->projectView->dtable->fieldList['budget']['type'] = 'format'; +$config->program->projectView->dtable->fieldList['budget']['sortType'] = true; + +$config->program->projectView->dtable->fieldList['invested']['name'] = 'invested'; +$config->program->projectView->dtable->fieldList['invested']['title'] = $lang->program->invested; +$config->program->projectView->dtable->fieldList['invested']['minWidth'] = 70; +$config->program->projectView->dtable->fieldList['invested']['type'] = 'format'; +$config->program->projectView->dtable->fieldList['invested']['sortType'] = true; + +$config->program->projectView->dtable->fieldList['begin']['name'] = 'begin'; +$config->program->projectView->dtable->fieldList['begin']['title'] = $lang->program->begin; +$config->program->projectView->dtable->fieldList['begin']['minWidth'] = 90; +$config->program->projectView->dtable->fieldList['begin']['type'] = 'datetime'; +$config->program->projectView->dtable->fieldList['begin']['sortType'] = true; + +$config->program->projectView->dtable->fieldList['end']['name'] = 'end'; +$config->program->projectView->dtable->fieldList['end']['title'] = $lang->program->end; +$config->program->projectView->dtable->fieldList['end']['minWidth'] = 90; +$config->program->projectView->dtable->fieldList['end']['type'] = 'datetime'; +$config->program->projectView->dtable->fieldList['end']['sortType'] = true; + +$config->program->projectView->dtable->fieldList['progress']['name'] = 'progress'; +$config->program->projectView->dtable->fieldList['progress']['title'] = $lang->program->progressAB; +$config->program->projectView->dtable->fieldList['progress']['minWidth'] = 100; +$config->program->projectView->dtable->fieldList['progress']['type'] = 'circleProgress'; + +$config->program->projectView->dtable->fieldList['actions']['name'] = 'actions'; +$config->program->projectView->dtable->fieldList['actions']['title'] = $lang->actions; +$config->program->projectView->dtable->fieldList['actions']['width'] = 160; +$config->program->projectView->dtable->fieldList['actions']['type'] = 'actions'; +$config->program->projectView->dtable->fieldList['actions']['fixed'] = 'right'; +$config->program->projectView->dtable->fieldList['actions']['actionsMap'] = array( + 'program_start' => array('icon' => 'icon-start', 'hint' => $lang->program->start), + 'program_suspend' => array('icon' => 'icon-pause', 'hint' => $lang->program->suspend), + 'program_close' => array('icon' => 'icon-off', 'hint' => $lang->program->close), + 'program_activate' => array('icon' => 'icon-active', 'hint' => $lang->program->activate), + 'program_other' => array('caret' => true, 'hint' => $lang->program->other, 'type' => 'dropdown', ), + 'program_edit' => array('icon' => 'icon-edit', 'hint' => $lang->program->edit), + 'program_create' => array('icon' => 'icon-split', 'hint' => $lang->program->create), + 'program_delete' => array('icon' => 'icon-trash', 'hint' => $lang->program->delete), + 'project_start' => array('icon' => 'icon-start', 'hint' => $lang->project->start), + 'project_suspend' => array('icon' => 'icon-pause', 'hint' => $lang->project->suspend), + 'project_close' => array('icon' => 'icon-off', 'hint' => $lang->project->close), + 'project_activate' => array('icon' => 'icon-active', 'hint' => $lang->project->activate), + 'project_other' => array('caret' => true, 'hint' => $lang->project->other, 'type' => 'dropdown', ), + 'project_edit' => array('icon' => 'icon-edit', 'hint' => $lang->project->edit), + 'project_team' => array('icon' => 'icon-groups', 'hint' => $lang->project->manageMembers), + 'project_group' => array('icon' => 'icon-lock', 'hint' => $lang->project->group), + 'project_more' => array('icon' => 'icon-ellipsis-v', 'hint' => $lang->project->moreActions, 'type' => 'dropdown', 'caret' => false), + 'project_link' => array('icon' => 'icon-link', 'hint' => $lang->project->manageProducts), + 'project_whitelist' => array('icon' => 'icon-shield-check', 'hint' => $lang->project->whitelist), + 'project_delete' => array('icon' => 'icon-trash', 'hint' => $lang->project->delete) +); diff --git a/module/program/control.php b/module/program/control.php index 302a431421..18afb11850 100644 --- a/module/program/control.php +++ b/module/program/control.php @@ -106,6 +106,7 @@ class program extends control $this->view->PMList = $PMList; $this->view->progressList = $this->program->getProgressList(); $this->view->hasProject = $hasProject; + $this->view->param = $param; $this->display(); } @@ -777,4 +778,160 @@ class program extends control $data = fixer::input('post')->get(); $this->loadModel('setting')->updateItem("{$this->app->user->account}.program.showAllProjects", $data->showAllProjects); } + + /** + * Project View list. + * copied from browse() + * + * @param string $status + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @param int $param + * @access public + * @return void + */ + public function projectView($status = 'unclosed', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 10, $pageID = 1, $param = 0) + { + if(common::hasPriv('program', 'create')) $this->lang->pageActions = html::a($this->createLink('program', 'create'), " " . $this->lang->program->create, '', "class='btn btn-primary create-program-btn'"); + + $this->session->set('programList', $this->app->getURI(true), 'program'); + $this->session->set('projectList', $this->app->getURI(true), 'program'); + $this->session->set('createProjectLocate', $this->app->getURI(true), 'program'); + + $this->app->loadClass('pager', true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + $programType = $this->cookie->programType ? $this->cookie->programType : 'bylist'; + + if($programType === 'bygrid') + { + $programs = $this->program->getProgramStats($status, 20, $orderBy); + } + else + { + if(strtolower($status) == 'bysearch') + { + $queryID = (int)$param; + $programs = $this->program->getListBySearch($orderBy, $queryID); + } + else + { + /* Get top programs and projects. */ + $topObjects = $this->program->getList($status == 'unclosed' ? 'doing,suspended,wait' : $status, $orderBy, $pager, 'top'); + if(!$topObjects) $topObjects = array(0); + $programs = $this->program->getList($status == 'closed' ? 'closed' : 'all', $orderBy, NULL, 'child', array_keys($topObjects)); + + /* Get summary. */ + $topCount = $indCount = 0; + foreach($programs as $program) + { + if($program->type == 'program' and $program->parent == 0) $topCount ++; + if($program->type == 'project' and $program->parent == 0) $indCount ++; + } + $summary = sprintf($this->lang->program->summary, $topCount, $indCount); + } + } + + /* Get PM id list. */ + $accounts = array(); + $hasProject = false; + foreach($programs as $program) + { + if(!empty($program->PM) and !in_array($program->PM, $accounts)) $accounts[] = $program->PM; + if($hasProject === false and $program->type != 'program') $hasProject = true; + } + $PMList = $this->loadModel('user')->getListByAccounts($accounts, 'account'); + + /* Build the search form. */ + $actionURL = $this->createLink('program', 'browse', "status=bySearch&orderBy={$orderBy}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}¶m=myQueryID"); + $this->config->program->search['actionURL'] = $actionURL; + $this->loadModel('search')->setSearchParams($this->config->program->search); + + $this->view->title = $this->lang->program->projectView; + $this->view->position[] = $this->lang->program->browse; + + $this->view->programs = $programs; + $this->view->status = $status; + $this->view->orderBy = $orderBy; + $this->view->summary = isset($summary) ? $summary : ''; + $this->view->pager = $pager; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->userIdPairs = $this->user->getPairs('noletter|showid'); + $this->view->usersAvatar = $this->user->getAvatarPairs(''); + $this->view->programType = $programType; + $this->view->PMList = $PMList; + $this->view->progressList = $this->program->getProgressList(); + $this->view->hasProject = $hasProject; + $this->view->param = $param; + $this->view->recTotal = $pager->recTotal; + + $this->render(); + } + + /** + * Product View list. + * copied from all() function of product module. + * + * @param string $browseType + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @param int $param + * @access public + * @return void + */ + public function productView($browseType = 'unclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Load module and set session. */ + $this->loadModel('product'); + $this->loadModel('user'); + $this->session->set('productView', $this->app->getURI(true), 'program'); + + $queryID = ($browseType == 'bySearch') ? (int)$param : 0; + + if($this->app->viewType == 'mhtml') + { + $productID = $this->product->saveState(0, $this->products); + $this->product->setMenu($productID); + } + + $this->app->loadClass('pager', true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + /* Process product structure. */ + if($this->config->systemMode == 'light' and $orderBy == 'program_asc') $orderBy = 'order_asc'; + $productStats = $this->product->getStats($orderBy, $pager, $browseType, '', 'story', '', $queryID); + $productStructure = $this->product->statisticProgram($productStats); + $productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll(); + $programLines = array(); + + foreach($productLines as $productLine) + { + if(!isset($programLines[$productLine->root])) $programLines[$productLine->root] = array(); + $programLines[$productLine->root][$productLine->id] = $productLine->name; + } + + $actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID"); + $this->product->buildProductSearchForm($param, $actionURL); + + $this->view->title = $this->lang->product->common; + $this->view->position[] = $this->lang->product->common; + $this->view->recTotal = $pager->recTotal; + $this->view->productStats = $productStats; + $this->view->productStructure = $productStructure; + $this->view->productLines = $productLines; + $this->view->programLines = $programLines; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->userIdPairs = $this->user->getPairs('noletter|showid'); + $this->view->usersAvatar = $this->user->getAvatarPairs(''); + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->pager = $pager; + $this->view->showBatchEdit = $this->cookie->showProductBatchEdit; + + $this->render(); + } } diff --git a/module/program/js/browse.js b/module/program/js/browse.js index 5168be2e21..f98e8c5ced 100644 --- a/module/program/js/browse.js +++ b/module/program/js/browse.js @@ -1,69 +1,94 @@ $(function() { + var orderList = orderBy.split('_'); + var orderField = orderList[0]; + var orderType = orderList[1]; + setTimeout(function() + { + $(document).find('.dtable-header div[data-col="' + orderField + '"] > a').addClass(orderType == 'asc' ? 'sort-up' : 'sort-down'); + }, 100); + $('input#editProject1').click(function() { var editProject = $(this).is(':checked') ? 1 : 0; $.cookie('editProject', editProject, {expires:config.cookieLife, path:config.webRoot}); - showEditCheckbox(editProject); + dtableWithZentao.render({checkable: editProject}); }); + if($.cookie('editProject') == 1) $('input#editProject1').prop('checked', 'true'); - if($('input#editProject1').prop('checked')) showEditCheckbox(true); - - $(document).on('click', ":checkbox[name^='projectIdList']", function() - { - var notCheckedLength = $(":checkbox[name^='projectIdList']:not(:checked)").length; - var checkedLength = $(":checkbox[name^='projectIdList']:checked").length; - - if(checkedLength > 0) $('#programForm').addClass('has-row-checked'); - if(notCheckedLength == 0) $('.table-footer #checkAll').prop('checked', true); - if(checkedLength == 0) + var isEditMode = $('input#editProject1').is(':checked'); + var projectIdList = []; + dtableWithZentao.render({ + checkable: isEditMode, + canRowCheckable(id) { - $('.table-footer #checkAll').prop('checked', false); - $('#programForm').removeClass('has-row-checked'); - } - - var summary = checkedProjects.replace('%s', checkedLength); - if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('items', 'item'); - var statistic = "
    " + summary + "
    "; - if(checkedLength > 0) - { - $('#programSummary').addClass('hidden'); - $('#projectsSummary').remove(); - $('.editCheckbox').after(statistic); - } - else - { - $('#programSummary').removeClass('hidden'); - $('#projectsSummary').addClass('hidden'); - } + const rowInfo = this.getRowInfo(id); + return rowInfo.data?.type === 'project'; + }, + footToolbar: { + items: [ + {size: 'sm', text: editLang, btnType: 'primary', className: 'edit-btn'}, + ], + }, + footPager: { + items: [ + {type: 'info', text: pagerLang.totalCountAB}, + {type: 'size-menu', text: pagerLang.pageSizeAB}, + {type: 'link', page: 'first', icon: 'icon-first-page', hint: pagerLang.firstPage}, + {type: 'link', page: 'prev', icon: 'icon-angle-left', hint: pagerLang.previousPage}, + {type: 'info', text: '{page}/{pageTotal}'}, + {type: 'link', page: 'next', icon: 'icon-angle-right', hint: pagerLang.nextPage}, + {type: 'link', page: 'last', icon: 'icon-last-page', hint: pagerLang.lastPage}, + ], + page: pageID, + recTotal: recTotal, + recPerPage: recPerPage, + linkCreator: pagerLink, + }, + footer() { + const statistic = () => { + const checkedCount = this.getChecks().length; + const text = isEditMode && checkedCount ? checkedProjects.replace('%s', checkedCount) : programSummary; + projectIdList = this.getChecks(); + return [{children: text, className: 'text-dark'}]; + }; + if (isEditMode) { + return [ + 'checkbox', + 'toolbar', + statistic, + 'flex', + 'pager', + ]; + } + return [ + statistic, + 'flex', + 'pager', + ]; + }, }); - $(document).on('click', ".table-footer #checkAll", function() + $(document).on('click', ".dtable-footer .edit-btn.toolbar-item", function() { - if($(this).prop('checked')) - { - $(":checkbox[name^='projectIdList']").prop('checked', true); - $('#programForm').addClass('has-row-checked'); - var checkedLength = $(":checkbox[name^='projectIdList']:checked").length; - var summary = checkedProjects.replace('%s', checkedLength); - if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('items', 'item'); - var statistic = "
    " + summary + "
    "; - $('#programSummary').addClass('hidden'); - $('#projectsSummary').remove(); - $('.editCheckbox').after(statistic); - $(this).next('label').addClass('hover'); - } - else - { - $(":checkbox[name^='projectIdList']").prop('checked', false); - $('#programForm').removeClass('has-row-checked'); - $('#programSummary').removeClass('hidden'); - $('#projectsSummary').addClass('hidden'); - $(this).next('label').removeClass('hover'); - } + var batchEditLink = createLink('project', 'batchEdit'); + var tempform = document.createElement("form"); + tempform.action = batchEditLink; + tempform.method = "post"; + tempform.style.display = "none"; + + var opt = document.createElement("input"); + opt.name = 'projectIdList'; + opt.value = projectIdList; + + tempform.appendChild(opt); + document.body.appendChild(tempform); + tempform.submit(); }); + if(status == 'bySearch') $('.dtable-footer').hide(); + /* Solve the problem that clicking the browser back button causes the checkbox to be selected by default. */ setTimeout(function() { diff --git a/module/program/js/create.ui.js b/module/program/js/create.ui.js new file mode 100644 index 0000000000..27d119ee0c --- /dev/null +++ b/module/program/js/create.ui.js @@ -0,0 +1,141 @@ +window.onParentChange = (event) => +{ + const parentID = $(event.target).val(); + const url = $.createLink('program', 'create', parentID ? ('parentProgramID=' + parentID) : ''); + loadPage(url, '#budgetRow>*, #acl'); +}; + +window.onBudgetChange = (event) => +{ + const $budget = $(event.target); + const currentBudget = $budget.val(); + const budgetLeft = $budget.data('budget-left'); + if(currentBudget > budgetLeft) + { + $('
    ').text(lang.budgetOverrun + $budget.data('currency-symbol') + budgetLeft).append($('
    ').text(lang.ignore).on('click', () => $('#budgetTip').remove())).appendTo($budget.closest('.form-group')); + } +}; + +window.onFutureChange = (event) => +{ + $('#budget,#budgetUnit').attr('disabled', $(event.target).prop('checked') ? 'disabled' : null); + $('#budgetTip').remove(); +}; + +window.outOfDateTip = function() +{ + console.warn('The method outOfDateTip is not implemented.'); +}; + +/** + * Compute delta of two days. + * + * @param string date1 + * @param string date2 + * @access public + * @return int + */ +function computeDaysDelta(date1, date2) +{ + date1 = zui.createDate(date1); + date2 = zui.createDate(date2); + const delta = (date2 - date1) / (1000 * 60 * 60 * 24) + 1; + + let weekEnds = 0; + for(i = 0; i < delta; i++) + { + if((weekend == 2 && date1.getDay() == 6) || date1.getDay() == 0) weekEnds ++; + date1 = date1.valueOf(); + date1 += 1000 * 60 * 60 * 24; + date1 = new Date(date1); + } + return delta - weekEnds; +} + +/** + * Compute work days. + * + * @param string currentID + * @access public + * @return void + */ +window.computeWorkDays = function(currentID) +{ + if(typeof currentID === 'object') currentID = $(currentID.target).val(); + let isBactchEdit = false; + let index; + if(currentID) + { + index = currentID.replace('begins[', ''); + index = index.replace('ends[', ''); + index = index.replace(']', ''); + if(!isNaN(index)) isBactchEdit = true; + } + + let beginDate; + let endDate; + if(isBactchEdit) + { + beginDate = $('#begins\\[' + index + '\\]').val(); + endDate = $('#ends\\[' + index + '\\]').val(); + } + else + { + beginDate = $('#begin').val(); + endDate = $('#end').val(); + + var begin = new Date(beginDate.replace(/-/g,"/")); + var end = new Date(endDate.replace(/-/g,"/")); + var time = end.getTime() - begin.getTime(); + var days = parseInt(time / (1000 * 60 * 60 * 24)) + 1; + if(days != $('input[name="delta"]:checked').val()) $('input[name="delta"]:checked').attr('checked', false); + if(endDate == LONG_TIME) $('#delta999').prop('checked', true); + } + + if(beginDate && endDate) + { + if(isBactchEdit) $('#dayses\\[' + index + '\\]').val(computeDaysDelta(beginDate, endDate)); + else $('#days').val(computeDaysDelta(beginDate, endDate)); + } + else if($('input[checked="true"]').val()) + { + computeEndDate(); + } + outOfDateTip(); +}; + +/** + * Compute the end date for project. + * + * @param int $delta + * @access public + * @return void + */ +window.computeEndDate = function(delta) +{ + delta = +$('input[name="delta"]:checked').val(); + let beginDate = $('#begin').val(); + if(!beginDate) return; + + if(delta === 999) + { + $('#end').val(LONG_TIME); + outOfDateTip(); + return false; + } + + beginDate = zui.createDate(beginDate); + if((delta === 7 || delta === 14) && (beginDate.getDay() === 1)) + { + delta = (weekend === 2) ? (delta - 2) : (delta - 1); + } + + const endDate = zui.formatDate(beginDate.getTime() + ((delta - 1) * zui.TIME_DAY), 'yyyy-MM-dd'); + $('#end').val(endDate); + computeWorkDays(); +}; + +window.onAclChange = () => +{ + $('#whitelistRow').toggleClass('hidden', $('#acl_open').prop('checked')); +}; diff --git a/module/program/js/projectview.ui.js b/module/program/js/projectview.ui.js new file mode 100644 index 0000000000..0d1a392a31 --- /dev/null +++ b/module/program/js/projectview.ui.js @@ -0,0 +1,29 @@ +window.footerGenerator = function() +{ + const count = this.layout.allRows.filter((x) => x.data.type === "product").length; + const statistic = summeryTpl.replace('%s', ' ' + count + ' '); + return [{children: statistic, className: "text-dark"}, "flex", "pager"]; +} + +window.renderCell = function(result, {col, row}) +{ + if(col.name === 'name') + { + if(row.data.postponed) result[result.length] = {html:'' + langPostponed + '', className:'flex items-end w-full', style:{flexDirection:"column"}}; + return result; + } + + if(col.name === 'budget') + { + result[0] = {html: '
    ' + row.data.budget + '
    ', className:'flex items-end w-full items-end', style:{flexDirection:"column"}}; + return result; + } + + if(col.name === 'invested') + { + result[0] = {html: '
    ' + row.data.invested + ' ' + langManDay + '
    ', className:'flex items-end w-full items-end', style:{flexDirection:"column"}}; + return result; + } + + return result; +} diff --git a/module/program/lang/de.php b/module/program/lang/de.php index eb7aa7496e..aa57f64c16 100644 --- a/module/program/lang/de.php +++ b/module/program/lang/de.php @@ -9,6 +9,7 @@ $lang->program->status = 'Status'; $lang->program->PM = 'Manager'; $lang->program->budget = 'Budget'; $lang->program->budgetUnit = 'Budget Unit'; +$lang->program->invested = 'Invested'; $lang->program->begin = 'Begin'; $lang->program->end = 'End'; $lang->program->realBegin = 'Actual Begin'; @@ -85,6 +86,7 @@ $lang->program->changePRJUnit = 'Update the budget unit of the ' . $la $lang->program->showNotCurrentProjects = "Display {$lang->projectCommon} information of non current program"; $lang->program->progress = 'Progress'; +$lang->program->progressAB = 'Progress'; $lang->program->children = 'Child'; $lang->program->allInvest = 'Input'; $lang->program->teamCount = 'Team'; @@ -119,6 +121,25 @@ $lang->program->beyondParentBudget = 'The remaining budget of the owned program $lang->program->checkedProjects = 'Seleted %s items'; $lang->program->budgetOverrun = "The program's budget exceeds the remaining budget of the parent program:"; +/* ToolBar. */ +$lang->program->createProduct = 'Create Product'; +$lang->program->createProject = 'Create Project'; + +/* DTable columns of product view page. */ +$lang->program->unclosedReqCount = 'Unclosed'; +$lang->program->closedReqRate = 'Closed Rate'; +$lang->program->testCaseCoverage = 'Coverage'; +$lang->program->bugActivatedCount = 'Activated'; +$lang->program->fixedRate = 'Fixed'; +$lang->program->feedback = 'Feedback'; + +$lang->program->tip = new stdclass(); +$lang->program->tip->closed = 'The program has been closed. Re-close is not available.'; +$lang->program->tip->notSuspend = 'The program has been closed. Suspend is not available.'; +$lang->program->tip->suspended = 'The program has been suspended. Re-suspended is not available.'; +$lang->program->tip->actived = 'The program has been activated. Re-activated is not available.'; +$lang->program->tip->notCreate = 'The program has been closed. Adding sub-programs is not available.'; + $lang->program->endList[31] = 'One month'; $lang->program->endList[93] = 'Trimester'; $lang->program->endList[186] = 'Half year'; @@ -151,6 +172,15 @@ $lang->program->featureBar['browse']['doing'] = 'Doing'; $lang->program->featureBar['browse']['suspended'] = 'Suspended'; $lang->program->featureBar['browse']['closed'] = 'Closed'; +$lang->program->featureBar['productview']['all'] = 'All'; +$lang->program->featureBar['productview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['productview']['end'] = 'End'; + +$lang->program->featureBar['projectview']['all'] = 'All'; +$lang->program->featureBar['projectview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['projectview']['wait'] = 'Waiting'; +$lang->program->featureBar['projectview']['doing'] = 'Doing'; +$lang->program->featureBar['projectview']['more'] = 'More'; $lang->program->featureBar['product']['all'] = 'Alle ' . $lang->productCommon; $lang->program->featureBar['product']['noclosed'] = 'Offen'; $lang->program->featureBar['product']['closed'] = 'Geschlossen'; @@ -176,4 +206,7 @@ $lang->program->kanban->normalReleases = 'Normal Releases'; $lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761'); -$lang->program->defaultProgram = 'Default program'; +$lang->program->defaultProgram = 'Default Program'; +$lang->program->projectView = 'Project View'; +$lang->program->productView = 'Product View'; +$lang->program->manDay = 'Man Day'; diff --git a/module/program/lang/en.php b/module/program/lang/en.php index 2b3cf44f0a..14a30f3313 100644 --- a/module/program/lang/en.php +++ b/module/program/lang/en.php @@ -9,6 +9,7 @@ $lang->program->status = 'Status'; $lang->program->PM = 'Manager'; $lang->program->budget = 'Budget'; $lang->program->budgetUnit = 'Budget Unit'; +$lang->program->invested = 'Invested'; $lang->program->begin = 'Begin'; $lang->program->end = 'End'; $lang->program->realBegin = 'Actual Begin'; @@ -85,6 +86,7 @@ $lang->program->changePRJUnit = 'Update the budget unit of the ' . $la $lang->program->showNotCurrentProjects = "Display {$lang->projectCommon} information of non current program"; $lang->program->progress = 'Progress'; +$lang->program->progressAB = 'Progress'; $lang->program->children = 'Add Child'; $lang->program->allInvest = 'Input'; $lang->program->teamCount = 'Team'; @@ -119,6 +121,25 @@ $lang->program->beyondParentBudget = 'The remaining budget of the owned program $lang->program->checkedProjects = 'Seleted %s items'; $lang->program->budgetOverrun = "The program's budget exceeds the remaining budget of the parent program:"; +/* ToolBar. */ +$lang->program->createProduct = 'Create Product'; +$lang->program->createProject = 'Create Project'; + +/* DTable columns of product view page. */ +$lang->program->unclosedReqCount = 'Unclosed'; +$lang->program->closedReqRate = 'Closed Rate'; +$lang->program->testCaseCoverage = 'Coverage'; +$lang->program->bugActivatedCount = 'Activated'; +$lang->program->fixedRate = 'Fixed'; +$lang->program->feedback = 'Feedback'; + +$lang->program->tip = new stdclass(); +$lang->program->tip->closed = 'The program has been closed. Re-close is not available.'; +$lang->program->tip->notSuspend = 'The program has been closed. Suspend is not available.'; +$lang->program->tip->suspended = 'The program has been suspended. Re-suspended is not available.'; +$lang->program->tip->actived = 'The program has been activated. Re-activated is not available.'; +$lang->program->tip->notCreate = 'The program has been closed. Adding sub-programs is not available.'; + $lang->program->endList[31] = 'One month'; $lang->program->endList[93] = 'Trimester'; $lang->program->endList[186] = 'Half year'; @@ -151,6 +172,15 @@ $lang->program->featureBar['browse']['doing'] = 'Doing'; $lang->program->featureBar['browse']['suspended'] = 'Suspended'; $lang->program->featureBar['browse']['closed'] = 'Closed'; +$lang->program->featureBar['productview']['all'] = 'All'; +$lang->program->featureBar['productview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['productview']['end'] = 'End'; + +$lang->program->featureBar['projectview']['all'] = 'All'; +$lang->program->featureBar['projectview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['projectview']['wait'] = 'Waiting'; +$lang->program->featureBar['projectview']['doing'] = 'Doing'; +$lang->program->featureBar['projectview']['more'] = 'More'; $lang->program->featureBar['product']['all'] = 'All'; $lang->program->featureBar['product']['noclosed'] = 'Open'; $lang->program->featureBar['product']['closed'] = 'Closed'; @@ -176,4 +206,7 @@ $lang->program->kanban->normalReleases = 'Normal Releases'; $lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761'); -$lang->program->defaultProgram = 'Default program'; +$lang->program->defaultProgram = 'Default Program'; +$lang->program->projectView = 'Project View'; +$lang->program->productView = 'Product View'; +$lang->program->manDay = 'Man Day'; diff --git a/module/program/lang/fr.php b/module/program/lang/fr.php index 54978a97cd..19cb8c19c6 100644 --- a/module/program/lang/fr.php +++ b/module/program/lang/fr.php @@ -9,6 +9,7 @@ $lang->program->status = 'Status'; $lang->program->PM = 'Manager'; $lang->program->budget = 'Budget'; $lang->program->budgetUnit = 'Budget Unit'; +$lang->program->invested = 'Invested'; $lang->program->begin = 'Begin'; $lang->program->end = 'End'; $lang->program->realBegin = 'Actual Begin'; @@ -85,6 +86,7 @@ $lang->program->changePRJUnit = 'Update the budget unit of the ' . $la $lang->program->showNotCurrentProjects = "Display {$lang->projectCommon} information of non current program"; $lang->program->progress = 'Progress'; +$lang->program->progressAB = 'Progress'; $lang->program->children = 'Child'; $lang->program->allInvest = 'Input'; $lang->program->teamCount = 'Team'; @@ -119,6 +121,25 @@ $lang->program->beyondParentBudget = 'The remaining budget of the owned program $lang->program->checkedProjects = "Pour s électionner l'élément% s"; $lang->program->budgetOverrun = "Le budget du programme a dépassé le budget restant du programme parent:"; +/* ToolBar. */ +$lang->program->createProduct = 'Create Product'; +$lang->program->createProject = 'Create Project'; + +/* DTable columns of product view page. */ +$lang->program->unclosedReqCount = 'Unclosed'; +$lang->program->closedReqRate = 'Closed Rate'; +$lang->program->testCaseCoverage = 'Coverage'; +$lang->program->bugActivatedCount = 'Activated'; +$lang->program->fixedRate = 'Fixed'; +$lang->program->feedback = 'Feedback'; + +$lang->program->tip = new stdclass(); +$lang->program->tip->closed = 'The program has been closed. Re-close is not available.'; +$lang->program->tip->notSuspend = 'The program has been closed. Suspend is not available.'; +$lang->program->tip->suspended = 'The program has been suspended. Re-suspended is not available.'; +$lang->program->tip->actived = 'The program has been activated. Re-activated is not available.'; +$lang->program->tip->notCreate = 'The program has been closed. Adding sub-programs is not available.'; + $lang->program->endList[31] = 'One month'; $lang->program->endList[93] = 'Trimester'; $lang->program->endList[186] = 'Half year'; @@ -151,6 +172,15 @@ $lang->program->featureBar['browse']['doing'] = 'En Cours'; $lang->program->featureBar['browse']['suspended'] = 'Suspendues'; $lang->program->featureBar['browse']['closed'] = 'Fermées'; +$lang->program->featureBar['productview']['all'] = 'All'; +$lang->program->featureBar['productview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['productview']['end'] = 'End'; + +$lang->program->featureBar['projectview']['all'] = 'All'; +$lang->program->featureBar['projectview']['unclosed'] = 'Unclosed'; +$lang->program->featureBar['projectview']['wait'] = 'Waiting'; +$lang->program->featureBar['projectview']['doing'] = 'Doing'; +$lang->program->featureBar['projectview']['more'] = 'More'; $lang->program->featureBar['product']['all'] = 'Tous'; $lang->program->featureBar['product']['noclosed'] = 'Ouvertes'; $lang->program->featureBar['product']['closed'] = 'Fermé'; @@ -176,4 +206,7 @@ $lang->program->kanban->normalReleases = 'Normal Releases'; $lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761'); -$lang->program->defaultProgram = 'Default program'; +$lang->program->defaultProgram = 'Default Program'; +$lang->program->projectView = 'Project View'; +$lang->program->productView = 'Product View'; +$lang->program->manDay = 'Man Day'; diff --git a/module/program/lang/zh-cn.php b/module/program/lang/zh-cn.php index c08ab6811c..aa7d0c9ff2 100644 --- a/module/program/lang/zh-cn.php +++ b/module/program/lang/zh-cn.php @@ -9,6 +9,7 @@ $lang->program->status = '状态'; $lang->program->PM = '负责人'; $lang->program->budget = '预算'; $lang->program->budgetUnit = '预算单位'; +$lang->program->invested = '已投入'; $lang->program->begin = '计划开始'; $lang->program->end = '计划完成'; $lang->program->realBegin = '实际开始'; @@ -85,6 +86,10 @@ $lang->program->changePRJUnit = "更新{$lang->projectCommon}预算单 $lang->program->showNotCurrentProjects = "显示非当前项目集的{$lang->projectCommon}信息"; $lang->program->progress = "{$lang->projectCommon}进度"; +$lang->program->other = '其他'; + +$lang->program->progress = '项目进度'; +$lang->program->progressAB = '进度'; $lang->program->children = '添加子项目集'; $lang->program->allInvest = '项目集总投入'; $lang->program->teamCount = '总人数'; @@ -119,6 +124,25 @@ $lang->program->beyondParentBudget = '已超出所属项目集的剩余预算'; $lang->program->checkedProjects = '已选择%s项'; $lang->program->budgetOverrun = '项目集的预算超出了父项目集的剩余预算:'; +/* ToolBar. */ +$lang->program->createProduct = '添加产品'; +$lang->program->createProject = '添加项目'; + +/* DTable columns of product view page. */ +$lang->program->unclosedReqCount = '需求未关闭'; +$lang->program->closedReqRate = '需求完成率'; +$lang->program->testCaseCoverage = '用例覆盖率'; +$lang->program->bugActivatedCount = 'Bug激活'; +$lang->program->fixedRate = '修复率'; +$lang->program->feedback = '反馈'; + +$lang->program->tip = new stdclass(); +$lang->program->tip->closed = '该项目集已是关闭状态,无须关闭。'; +$lang->program->tip->notSuspend = '该项目集已关闭,不可进行挂起操作。'; +$lang->program->tip->suspended = '该项目集已是挂起状态,无须挂起。'; +$lang->program->tip->actived = '该项目集已是激活状态,无须激活。'; +$lang->program->tip->notCreate = '该项目集已关闭,不可进行添加子项目集的操作。'; + $lang->program->endList[31] = '一个月'; $lang->program->endList[93] = '三个月'; $lang->program->endList[186] = '半年'; @@ -162,6 +186,16 @@ $lang->program->featureBar['project']['doing'] = '进行中'; $lang->program->featureBar['project']['suspended'] = '已挂起'; $lang->program->featureBar['project']['closed'] = '已关闭'; +$lang->program->featureBar['productview']['all'] = '全部'; +$lang->program->featureBar['productview']['unclosed'] = '未关闭'; +$lang->program->featureBar['productview']['end'] = '结束'; + +$lang->program->featureBar['projectview']['all'] = '全部'; +$lang->program->featureBar['projectview']['unclosed'] = '未关闭'; +$lang->program->featureBar['projectview']['wait'] = '未开始'; +$lang->program->featureBar['projectview']['doing'] = '进行中'; +$lang->program->featureBar['projectview']['more'] = '更多'; + $lang->program->kanban = new stdclass(); $lang->program->kanban->common = '项目集看板'; $lang->program->kanban->typeList['my'] = '我参与的项目集'; @@ -177,3 +211,6 @@ $lang->program->kanban->normalReleases = '正常的发布'; $lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761'); $lang->program->defaultProgram = '默认项目集'; +$lang->program->projectView = '项目视角'; +$lang->program->productView = '产品视角'; +$lang->program->manDay = '人天'; diff --git a/module/program/model.php b/module/program/model.php index ebe092f12a..9bbedc982f 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -1700,4 +1700,206 @@ class programModel extends model return $programID; } + + /* + * Build row data. + * + * @param string $program + * @param array $PMList + * @param array $progressList + * @access public + * @return object + */ + public function buildRowData($program, $PMList, $progressList) + { + $row = new stdclass(); + + $manager = isset($PMList[$program->PM]) ? $PMList[$program->PM] : ''; + $programBudget = $this->project->getBudgetWithUnit($program->budget); + $link = $program->type == 'program' ? helper::createLink('program', 'product', "programID=$program->id") : helper::createLink('project', 'index', "projectID=$program->id"); + $name = html::a($link, $program->name, '', "title=$program->name"); + if($program->status != 'done' and $program->status != 'closed' and $program->status != 'suspended') + { + $delay = helper::diffDate(helper::today(), $program->end); + if($delay > 0) $name .= "{$this->lang->project->statusList['delay']}"; + } + + $row->id = $program->id; + $row->parent = $program->parent ? $program->parent : ''; + $row->asParent = $program->type == 'program'; + $row->type = $program->type; + $row->model = $program->model; + $row->name = $name; + $row->status = $program->status; + $row->PM = empty($manager) ? '' : $manager->realname; + $row->PMAvatar = empty($manager) ? '' : $manager->avatar; + $row->budget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future; + $row->begin = $program->begin; + $row->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end; + $row->progress = isset($progressList[$program->id]) ? round($progressList[$program->id]) : 0; + $row->actions = $this->buildActions($program); + + return $row; + } + + /** + * Build actions data. + * + * @param object $program + * @access public + * @return array + */ + public function buildActions($program) + { + $this->loadModel('project'); + + $actionsMap = array(); + $canStartProgram = common::hasPriv('program', 'start'); + $canSuspendProgram = common::hasPriv('program', 'suspend'); + $canCloseProgram = common::hasPriv('program', 'close'); + $canActivateProgram = common::hasPriv('program', 'activate'); + $canStartProject = common::hasPriv('project', 'start'); + $canSuspendProject = common::hasPriv('project', 'suspend'); + $canCloseProject = common::hasPriv('project', 'close'); + $canActivateProject = common::hasPriv('project', 'activate'); + + if($program->type == 'program' && strpos(",{$this->app->user->view->programs},", ",$program->id,") !== false) + { + $normalActions = array('start', 'close', 'activate'); + foreach($normalActions as $action) + { + if($action == 'start' and (!$canStartProgram or ($program->status != 'wait' and $program->status != 'suspended'))) continue; + if($action == 'close' and (!$canCloseProgram or $program->status != 'doing')) continue; + if($action == 'activate' and (!$canActivateProgram or $program->status != 'closed')) continue; + $item = new stdclass(); + $item->name = $action; + $item->hint = $this->lang->program->$action; + + $actionsMap[] = $item; + } + + if($canSuspendProgram or ($canClose && $program->status != 'doing') or ($canActivateProgram and $program->status != 'closed')) + { + $other = new stdclass(); + $other->name = 'other'; + $other->items = array(); + + $otherActions = array('suspend', 'close', 'activate'); + foreach($otherActions as $action) + { + if($action == 'close' and $program->status == 'doing') continue; + if(!common::hasPriv('program', $action)) continue; + + $item = new stdclass(); + $item->name = $action; + $item->text = $this->lang->program->$action; + if(!$this->isClickable($program, $action)) $item->disabled = true; + if($action == 'close' and $program->status == 'closed') $item->hint = $this->lang->program->tip->closed; + if($action == 'suspend' and $program->status == 'closed') $item->hint = $this->lang->program->tip->notSuspend; + if($action == 'suspend' and $program->status == 'suspended') $item->hint = $this->lang->program->tip->suspended; + if($action == 'activate' and $program->status == 'doing') $item->hint = $this->lang->program->tip->actived; + + $other->items[] = $item; + } + + $actionsMap[] = $other; + } + + $normalActions = array('edit', 'create', 'delete'); + foreach($normalActions as $action) + { + if(!common::hasPriv('program', $action)) continue; + $item = new stdclass(); + $item->name = $action; + $item->hint = $this->lang->program->$action; + if($action == 'create' and $program->status == 'closed') + { + $item->disabled = true; + $item->hint = $this->lang->program->tip->notCreate; + } + + $actionsMap[] = $item; + } + } + elseif($program->type == 'project') + { + $normalActions = array('start', 'close', 'activate'); + foreach($normalActions as $action) + { + if($action == 'start' and (!$canStartProject or ($program->status != 'wait' and $program->status != 'suspended'))) continue; + if($action == 'close' and (!$canCloseProject or $program->status != 'doing')) continue; + if($action == 'activate' and (!$canActivateProgram or $program->status != 'closed')) continue; + $item = new stdclass(); + $item->name = $action; + $item->hint = $this->lang->project->$action; + + $actionsMap[] = $item; + } + if($canSuspendProject or ($canCloseProject and $program->status != 'doing') or ($canActivateProject and $program->status != 'closed')) + { + $other = new stdclass(); + $other->name = 'other'; + $other->items = array(); + + $otherActions = array('suspend', 'close', 'activate'); + foreach($otherActions as $action) + { + if($action == 'close' and $program->status == 'doing') continue; + if(!common::hasPriv('project', $action)) continue; + + $item = new stdclass(); + $item->name = $action; + $item->text = $this->lang->project->$action; + if(!$this->project->isClickable($program, $action)) $item->disabled = true; + if($action == 'close' and $program->status == 'closed') $item->hint = $this->lang->project->tip->closed; + if($action == 'suspend' and $program->status == 'closed') $item->hint = $this->lang->project->tip->notSuspend; + if($action == 'suspend' and $program->status == 'suspended') $item->hint = $this->lang->project->tip->suspended; + if($action == 'activate' and $program->status == 'doing') $item->hint = $this->lang->project->tip->actived; + + $other->items[] = $item; + } + + $actionsMap[] = $other; + } + if(common::hasPriv('project', 'edit')) $actionsMap[] = 'edit'; + if(common::hasPriv('project', 'team')) $actionsMap[] = 'team'; + if(common::hasPriv('project', 'group')) + { + $item = new stdclass(); + $item->name = 'group'; + if($program->model == 'kanban') + { + $item->disabled = true; + $item->hint = $this->lang->project->tip->group; + } + $actionsMap[] = $item; + } + + if(common::hasPriv('project', 'manageProducts') || common::hasPriv('project', 'whitelist') || common::hasPriv('project', 'delete')) + { + $more = new stdclass(); + $more->name = 'more'; + $more->items = array(); + $moreActions = array('manageProducts', 'whitelist', 'delete'); + foreach($moreActions as $action) + { + if(!common::hasPriv('project', $action)) continue; + + $item = new stdclass(); + $item->name = $action == 'manageProducts' ? 'link' : $action; + $item->text = $this->lang->project->$action; + if($action == 'whitelist' and $program->acl == 'open') + { + $item->disabled = true; + $item->hint = $this->lang->project->tip->whitelist; + } + + $more->items[] = $item; + } + + $actionsMap[] = $more; + } + } + return $actionsMap; + } } diff --git a/module/program/ui/browse.html.php b/module/program/ui/browse.html.php new file mode 100644 index 0000000000..186e57fd3c --- /dev/null +++ b/module/program/ui/browse.html.php @@ -0,0 +1,65 @@ +program->dtable->fieldList); +$data = array_values($programs); + +foreach($data as $row) +{ + if (!property_exists($row, 'progress')) + { + if (isset($progressList[$row->id])) $row->progress = $progressList[$row->id]; + else $row->progress = ''; + } + + if (!property_exists($row, 'actions')) $row->actions = array(); +} + +featureBar +( + to::before(programMenu(set + ([ + 'title' => $lang->program->all, + 'programs' => $data, + 'activeKey' => '7', + 'closeLink' => '#' + ]))), + set::current($status), + set::linkParams("status={key}&orderBy=$orderBy"), + (hasPriv('project', 'batchEdit') && $programType != 'bygrid' && $hasProject === true) ? item + ( + set::type('checkbox'), + set::text($lang->project->edit), + set::checked($this->cookie->editProject) + ) : NULL, + li(searchToggle()) +); + +toolbar +( + hasPriv('project', 'create') ? item(set(array + ( + 'text' => $lang->project->create, + 'icon' => 'plus', + 'class' => 'btn secondary', + 'url' => createLink('project', 'createGuide', "programID=0&from=PGM"), + ))) : NULL, + hasPriv('program', 'create') ? item(set(array + ( + 'text' => $lang->program->create, + 'icon' => 'plus', + 'class' => 'btn primary', + 'url' => createLink('program', 'create') + ))) : NULL +); + +dtable +( + set::cols($cols), + set::data($data), + set::rowHeight(40), + set::footer(false) +); + +render(); diff --git a/module/program/ui/create.html.php b/module/program/ui/create.html.php new file mode 100644 index 0000000000..0c0932606b --- /dev/null +++ b/module/program/ui/create.html.php @@ -0,0 +1,149 @@ +id ?? 0; +$currency = $parentID ? $parentProgram->budgetUnit : $config->project->defaultCurrency; +$aclList = $parentProgram ? $lang->program->subAclList : $lang->program->aclList; +$budgetPlaceholder = $parentProgram ? $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $budgetLeft : ''; +$budgetAvaliable = !$parentID || $budgetLeft; + +jsVar('LONG_TIME', LONG_TIME); +jsVar('lang', ['budgetOverrun' => $lang->project->budgetOverrun, 'currencySymbol' => $lang->project->currencySymbol, 'ignore' => $lang->program->ignore]); +jsVar('weekend', $config->execution->weekend); + +set::title($parentID ? $lang->program->children : $lang->program->create); + +formPanel +( + on::change('#parent', 'onParentChange'), + on::change('#budget', 'onBudgetChange'), + on::change('#future', 'onFutureChange'), + on::change('#acl', 'onAclChange'), + formGroup + ( + set::width('1/2'), + set::name('parent'), + set::label($lang->program->parent), + set::disabled($parentID), + set::value($parentID), + set::items($parents), + ), + formGroup + ( + set::width('1/2'), + set::name('name'), + set::strong(true), + set::label($lang->program->name) + ), + formGroup + ( + set::width('1/4'), + set::name('PM'), + set::label($lang->program->PM), + set::items($pmUsers) + ), + formRow + ( + set::id('budgetRow'), + formGroup + ( + set::width('1/2'), + set::label($lang->program->budget), + inputGroup + ( + set::seg(true), + input + ( + set::name('budget'), + set::placeholder($budgetPlaceholder), + set::disabled(!$budgetAvaliable), + set('data-budget-left', $budgetLeft), + set('data-currency-symbol', $parentProgram ? zget($lang->project->currencySymbol, $parentProgram->budgetUnit) : NULL), + ), + select + ( + zui::width('1/3'), + set::name('budgetUnit'), + set::disabled($parentID || !$budgetAvaliable), + set::items($budgetUnitList), + set::value($currency) + ) + ) + ), + formHidden('budgetUnit', $currency), + formGroup + ( + set::name('future'), + set::value('1'), + set::disabled(!$budgetAvaliable), + set::control(['type' => 'checkbox', 'rootClass' => 'ml-4', 'text' => $lang->project->future, 'checked' => !$budgetAvaliable]) + ), + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->project->dateRange), + set::required(true), + inputGroup + ( + set::seg(true), + input + ( + set::type('date'), + set::name('begin'), + set::value(date('Y-m-d')), + set::placeholder($lang->project->begin), + set::required(true), + on::change('computeWorkDays') + ), + $lang->project->to, + input + ( + set::type('date'), + set::name('end'), + set::placeholder($lang->project->end), + set::required(true), + on::change('outOfDateTip') + ), + ) + ), + formGroup + ( + set::name('delta'), + set::class('pl-4'), + set::control(['type' => 'radioList', 'inline' => true, 'rootClass' => 'ml-4', 'items' => $lang->program->endList]), + on::change('computeEndDate') + ), + ), + /* TODO: printExtendFields() */ + formGroup + ( + set::name('desc'), + set::label($lang->program->desc), + set::control('editor') + ), + formHidden('status', 'wait'), + formGroup + ( + set::name('acl'), + set::label($lang->program->acl), + set::value('private'), + set::items($aclList), + set::control('radioList'), + ), + formRow + ( + set::id('whitelistRow'), + formGroup + ( + set::width('3/4'), + set::name('whitelist'), + set::label($lang->whitelist), + set::control('select') + ) + ) +); + +render(); diff --git a/module/program/ui/productview.html.php b/module/program/ui/productview.html.php new file mode 100644 index 0000000000..1a376fb7c5 --- /dev/null +++ b/module/program/ui/productview.html.php @@ -0,0 +1,230 @@ +program->productView->dtable->fieldList); + +$totalStories = 0; +$hasProduct = false; +$linesCount = 0; +$data = array(); +foreach($productStructure as $programID => $program) +{ + /* TODO attach program lines */ + if(isset($programLines[$programID])) + { + foreach($programLines[$programID] as $lineID => $lineName) + { + if(!isset($program[$lineID])) + { + $program[$lineID] = array(); + $program[$lineID]['product'] = ''; + $program[$lineID]['lineName'] = $lineName; + } + } + } + + /* ALM mode with more data. */ + if(isset($program['programName']) and $config->systemMode == 'ALM') + { + $item = new stdClass(); + + $item->programPM = ''; + if(!empty($program['programPM'])) + { + $programPM = $program['programPM']; + $userName = zget($users, $programPM); + + $userID = isset($userIdPairs[$programPM]) ? $userIdPairs[$programPM] : ''; + + $item->programPM = $userName; + $item->PM = $userName; + $item->PMAccount = $userName; + $item->PMAvatar = $usersAvatar[$programPM]; + } + + $totalStories = $program['finishClosedStories'] + $program['unclosedStories']; + + $item->name = $program['programName']; + $item->id = 'program-' . $programID; + $item->type = 'program'; + $item->level = 1; + $item->asParent = true; + $item->feedback = rand(0, 100); + $item->programName = $program['programName']; + $item->draftStories = $program['draftStories']; + $item->activeStories = $program['activeStories']; + $item->changingStories = $program['changingStories']; + $item->reviewingStories = $program['reviewingStories']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round($program['finishClosedStories'] / $totalStories, 3) * 100); + $item->unResolvedBugs = $program['unResolvedBugs']; + $item->fixedRate = (($program['unResolvedBugs'] + $program['fixedBugs']) == 0 ? 0 : round($program['fixedBugs'] / ($program['unResolvedBugs'] + $program['fixedBugs']), 3) * 100); + $item->plans = $program['plans']; + $item->releaseCount = $program['releases']; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverage = rand(0, 100); + $item->unclosedReqCount = rand(0, 100); + $item->executionCount = rand(0, 100); + /* TODO attach extend fields. */ + + $data[] = $item; + } + + foreach($program as $lineID => $line) + { + /* ALM mode with Product Line. */ + if(isset($line['lineName']) and isset($line['products']) and is_array($line['products']) and $config->systemMode == 'ALM') + { + $totalStories = (isset($line['finishClosedStories']) ? $line['finishClosedStories'] : 0) + (isset($line['unclosedStories']) ? $line['unclosedStories'] : 0); + $linesCount++; + + $item = new stdClass(); + $item->name = $line['lineName']; + $item->id = 'productLine-' . $lineID; + $item->type = 'productLine'; + $item->asParent = true; + $item->feedback = rand(0, 100); + $item->parent = 'program-' . $programID; + $item->programName = $line['lineName']; + $item->draftStories = $line['draftStories']; + $item->activeStories = $line['activeStories']; + $item->changingStories = $line['changingStories']; + $item->reviewingStories = $line['reviewingStories']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round((isset($line['finishClosedStories']) ? $line['finishClosedStories'] : 0) / $totalStories, 3) * 100); + $item->unResolvedBugs = $line['unResolvedBugs']; + $item->fixedRate = ((isset($line['fixedBugs']) and ($line['unResolvedBugs'] + $line['fixedBugs'] != 0)) ? round($line['fixedBugs'] / ($line['unResolvedBugs'] + $line['fixedBugs']), 3) * 100 : 0); + $item->plans = $line['plans']; + $item->releaseCount = isset($line['releases']) ? $line['releases'] : 0; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverage = rand(0, 100); + $item->unclosedReqCount = rand(0, 100); + $item->executionCount = rand(0, 100); + /* TODO attach extend fields. */ + + $data[] = $item; + } + + /* Products of Product Line. */ + if(isset($line['products']) and is_array($line['products'])) + { + foreach($line['products'] as $productID => $product) + { + $hasProduct = true; + + $item = new stdClass(); + + if(!empty($product->PO)) + { + $item->PM = zget($users, $product->PO); + $item->PMAvatar = $usersAvatar[$product->PO]; + $item->PMAccount = $product->PO; + } + $totalStories = $product->stories['finishClosed'] + $product->stories['unclosed']; + + $item->name = $product->name; /* TODO replace with */ + $item->id = $product->id; + $item->type = 'product'; + $item->programName = $product->name; /* TODO replace with */ + $item->feedback = rand(0, 100); + $item->draftStories = $product->stories['draft']; + $item->activeStories = $product->stories['active']; + $item->changingStories = $product->stories['changing']; + $item->reviewingStories = $product->stories['reviewing']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round($product->stories['finishClosed'] / $totalStories, 3) * 100); + $item->unResolvedBugs = $product->unResolved; + $item->fixedRate = (($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100); + $item->plans = $product->plans; + $item->parent = $product->line ? "productLine-$lineID" : ($product->program ? "program-$product->program" : ''); + $item->releaseCount = $product->releases; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverage = rand(0, 100); + $item->unclosedReqCount = rand(0, 100); + $item->executionCount = rand(0, 100); + /* TODO attach extend fields. */ + + $data[] = $item; + } + } + } +} + +$summary = sprintf($lang->product->lineSummary, $linesCount, count($productStats)); + +set::title($lang->program->productView); + +featureBar +( + set::current($browseType), + set::linkParams("status={key}&orderBy=$orderBy"), + (hasPriv('product', 'batchEdit') && $hasProduct === true) ? item + ( + set::type('checkbox'), + set::text($lang->project->edit), + set::checked($this->cookie->editProject) + ) : NULL, + li(searchToggle()) +); + +toolbar +( + item(set(array( + 'text' => $lang->program->export, + 'icon' => 'export', + 'class'=> 'ghost', + 'url' => createLink('program', 'exportTable') + ))), + div(setClass('nav-divider')), + item(set(array( + 'text' => $lang->program->edit, + 'icon' => 'edit', + 'class'=> 'ghost', + 'url' => createLink('program', 'exportTable') + ))), + item(set(array( + 'text' => $lang->program->createProduct, + 'icon' => 'plus', + 'class'=> 'btn secondary', + 'url' => createLink('program', 'exportTable') + ))), + item(set(array( + 'text' => $lang->program->create, + 'icon' => 'plus', + 'class'=> 'btn primary', + 'url' => createLink('program', 'create') + ))), +); + +js +( +<< 0) result[0] = {html: row.data.releaseCount + ' +' + changed + ''}; + if(changed < 0) result[0] = {html: row.data.releaseCount + ' ' + changed + ''}; + + return result; +} +RENDERCELL +); + +dtable +( + set::className('shadow rounded'), + set::cols($cols), + set::data($data), + set::footPager(usePager()), + set::nested(true), + set::onRenderCell(jsRaw('function(result, data){ return window.renderReleaseCountCell(result, data); }')), + set::footer(jsRaw('function(){return window.footerGenerator.call(this);}')) +); + +render(); diff --git a/module/program/ui/projectview.html.php b/module/program/ui/projectview.html.php new file mode 100644 index 0000000000..26a2647bf8 --- /dev/null +++ b/module/program/ui/projectview.html.php @@ -0,0 +1,95 @@ +program->projectView->dtable->fieldList); + +$data = array(); +foreach($programs as $program) +{ + if(empty($program->parent)) $program->parent = null; + + /* Delay status. */ + if($program->status != 'done' and $program->status != 'closed' and $program->status != 'suspended') + { + $delay = helper::diffDate(helper::today(), $program->end); + if($delay > 0) $program->postponed = true; + } + + /* PM. */ + if(!empty($program->PM)) + { + $userName = zget($users, $program->PM); + $program->PMAvatar = $usersAvatar[$program->PM]; + $program->PM = $userName; + } + + /* Calculate budget.*/ + $programBudget = $this->loadModel('project')->getBudgetWithUnit($program->budget); + $program->budget = $program->budget != 0 ? zget($lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $lang->project->future; + + /* Progress. */ + if(isset($progressList[$program->id])) $program->progress = round($progressList[$program->id]); + + $program->invested = 0; + + /* Actions. */ + $program->actions = array(); + $actions = $this->program->buildActions($program); + foreach($actions as $action) + { + if(is_object($action)) $action->name = $program->type . '_' . $action->name; + else $action = $program->type . '_' . $action; + + if(isset($action->items)) foreach($action->items as $idx => $item) $action->items[$idx]->name = $program->type . '_' . $item->name; + $program->actions[] = $action; + } + + $data[] = $program; +} + +jsVar('langManDay', $lang->program->manDay); +jsVar('langPostponed', $lang->project->statusList['delay']); +jsVar('summeryTpl', $summary); + +featureBar +( + set::current($status), + set::linkParams("status={key}&orderBy=$orderBy"), + (hasPriv('project', 'batchEdit') && $programType != 'bygrid' && $hasProject === true) ? item + ( + set::type('checkbox'), + set::text($lang->project->edit), + set::checked($this->cookie->editProject) + ) : NULL, + li(searchToggle()) +); + +toolbar +( + item(set + ([ + 'text' => $lang->program->createProject, + 'icon' => 'plus', + 'class'=> 'btn secondary', + 'url' => createLink('program', 'exportTable') + ])), + item(set + ([ + 'text' => $lang->program->create, + 'icon' => 'plus', + 'class'=> 'btn primary', + 'url' => createLink('program', 'create') + ])), +); + +dtable +( + set::cols($cols), + set::data($data), + set::nested(true), + set::onRenderCell(jsRaw('window.renderCell')), + set::footPager(usePager()), + set::footer(jsRaw('function(){return window.footerGenerator.call(this);}')) +); + +render(); diff --git a/module/project/config.php b/module/project/config.php index faaa28ea13..c40696bd5c 100644 --- a/module/project/config.php +++ b/module/project/config.php @@ -214,4 +214,81 @@ $config->project->includedPriv['repo'] = array('create', 'showSyncCommit', $config->project->includedPriv['testreport'] = array('create', 'view', 'delete', 'edit', 'export'); $config->project->includedPriv['auditplan'] = array('browse', 'create', 'edit', 'batchCreate', 'batchCheck', 'check', 'nc', 'result', 'assignTo'); $config->project->includedPriv['execution'] = array('create', 'start', 'delete', 'calendar', 'effortCalendar', 'effort', 'taskEffort', 'computeTaskEffort', 'deleterelation', 'maintainrelation', 'relation', 'gantt'); -if($config->edition != 'max') $config->project->includedPriv['stakeholder'] = array('browse', 'create', 'batchCreate', 'edit', 'delete', 'view', 'communicate', 'expect'); +if($config->edition != 'max') $config->project->includedPriv['stakeholder'] = array('browse', 'create', 'batchCreate', 'edit', 'delete', 'view', 'communicate', 'expect', 'expectation', 'deleteExpect', 'createExpect', 'editExpect', 'viewExpect'); + +$config->project->browseTable = new stdClass(); +$config->project->browseTable->cols = array(); + +$config->project->browseTable->cols['name']['name'] = 'name'; +$config->project->browseTable->cols['name']['title'] = $lang->project->name; +$config->project->browseTable->cols['name']['fixed'] = 'left'; +$config->project->browseTable->cols['name']['width'] = 408; +$config->project->browseTable->cols['name']['sortType'] = true; +$config->project->browseTable->cols['name']['type'] = 'link'; +$config->project->browseTable->cols['name']['linkTemplate'] = helper::createLink('project', 'index', 'projectID={id}'); + +$config->project->browseTable->cols['PM']['name'] = 'PM'; +$config->project->browseTable->cols['PM']['title'] = $lang->project->PM; +$config->project->browseTable->cols['PM']['minWidth'] = 104; +$config->project->browseTable->cols['PM']['type'] = 'avatarBtn'; +$config->project->browseTable->cols['PM']['flex'] = 1; +$config->project->browseTable->cols['PM']['border'] = 'right'; + +$config->project->browseTable->cols['storyCount']['name'] = 'storyCount'; +$config->project->browseTable->cols['storyCount']['title'] = $lang->project->storyCount; +$config->project->browseTable->cols['storyCount']['minWidth'] = 94; +$config->project->browseTable->cols['storyCount']['sortType'] = true; +$config->project->browseTable->cols['storyCount']['type'] = 'format'; +$config->project->browseTable->cols['storyCount']['align'] = 'right'; + +$config->project->browseTable->cols['executionCount']['name'] = 'executionCount'; +$config->project->browseTable->cols['executionCount']['title'] = $lang->project->executionCount; +$config->project->browseTable->cols['executionCount']['minWidth'] = 94; +$config->project->browseTable->cols['executionCount']['sortType'] = true; +$config->project->browseTable->cols['executionCount']['type'] = 'format'; +$config->project->browseTable->cols['executionCount']['border'] = 'right'; +$config->project->browseTable->cols['executionCount']['align'] = 'center'; + +$config->project->browseTable->cols['invested']['name'] = 'invested'; +$config->project->browseTable->cols['invested']['title'] = $lang->project->invested; +$config->project->browseTable->cols['invested']['minWidth'] = 94; +$config->project->browseTable->cols['invested']['sortType'] = true; +$config->project->browseTable->cols['invested']['type'] = 'format'; +$config->project->browseTable->cols['invested']['border'] = 'right'; +$config->project->browseTable->cols['invested']['align'] = 'center'; + +$config->project->browseTable->cols['begin']['name'] = 'begin'; +$config->project->browseTable->cols['begin']['title'] = $lang->project->begin; +$config->project->browseTable->cols['begin']['width'] = 96; +$config->project->browseTable->cols['begin']['sortType'] = true; + +$config->project->browseTable->cols['end']['name'] = 'end'; +$config->project->browseTable->cols['end']['title'] = $lang->project->end; +$config->project->browseTable->cols['end']['width'] = 96; +$config->project->browseTable->cols['end']['sortType'] = true; + +$config->project->browseTable->cols['progress']['name'] = 'progress'; +$config->project->browseTable->cols['progress']['title'] = $lang->project->progress; +$config->project->browseTable->cols['progress']['width'] = 92; +$config->project->browseTable->cols['progress']['type'] = 'circleProgress'; +$config->project->browseTable->cols['progress']['sortType'] = true; + +$config->project->browseTable->cols['actions']['name'] = 'actions'; +$config->project->browseTable->cols['actions']['title'] = $lang->actions; +$config->project->browseTable->cols['actions']['fixed'] = 'right'; +$config->project->browseTable->cols['actions']['width'] = 160; +$config->project->browseTable->cols['actions']['type'] = 'actions'; +$config->project->browseTable->cols['actions']['actionsMap'] = array( + 'start' => array('icon'=> 'icon-start', 'hint'=> $lang->project->start), + 'close' => array('icon'=> 'icon-off', 'hint'=> $lang->project->close, 'data-toggle' => 'modal', 'url' => helper::createLink('project', 'close', 'projectID={id}')), + 'pause' => array('icon'=> 'icon-pause', 'text'=> $lang->project->suspend), + 'active' => array('icon'=> 'icon-magic', 'text'=> $lang->project->activate), + 'edit' => array('icon'=> 'icon-edit', 'hint'=> $lang->project->edit), + 'group' => array('icon'=> 'icon-group', 'hint'=> $lang->project->teamMember), + 'perm' => array('icon'=> 'icon-lock', 'hint'=> $lang->project->group), + 'delete' => array('icon'=> 'icon-trash', 'hint'=> $lang->delete, 'text' => $lang->delete), + 'other' => array('type'=> 'dropdown', 'hint'=> $lang->project->other, 'caret' => true), + 'link' => array('icon'=> 'icon-link', 'text'=> $lang->project->manageProducts, 'name' => 'link'), + 'more' => array('icon'=> 'icon-ellipsis-v', 'hint'=> $lang->more, 'type' => 'dropdown', 'caret' => false), + 'whitelist' => array('icon'=> 'icon-shield-check', 'text'=> $lang->project->whitelist, 'name' => 'whitelist') +); diff --git a/module/project/control.php b/module/project/control.php index 7d80027c0c..434979e8a3 100755 --- a/module/project/control.php +++ b/module/project/control.php @@ -422,11 +422,12 @@ class project extends control $this->view->projectType = $projectType; $this->view->param = $param; $this->view->orderBy = $orderBy; - $this->view->recTotal = $recTotal; + $this->view->recTotal = $pager->recTotal; $this->view->recPerPage = $recPerPage; $this->view->pageID = $pageID; $this->view->showBatchEdit = $this->cookie->showProjectBatchEdit; $this->view->allProjectsNum = $this->loadModel('program')->getProjectStats($programID, 'all'); + $this->view->actionURL = $actionURL; $this->display(); } diff --git a/module/project/css/browse.ui.css b/module/project/css/browse.ui.css new file mode 100644 index 0000000000..e1a2736a10 --- /dev/null +++ b/module/project/css/browse.ui.css @@ -0,0 +1,3 @@ +textarea {width: 704px !important;} +input[name="realEnd"] {width: 150px;} +.modal-dialog {width: 890px !important;} diff --git a/module/project/css/create.ui.css b/module/project/css/create.ui.css new file mode 100644 index 0000000000..7120896858 --- /dev/null +++ b/module/project/css/create.ui.css @@ -0,0 +1 @@ +.panel-actions {display: flex; align-items: center;} diff --git a/module/project/js/browse.ui.js b/module/project/js/browse.ui.js new file mode 100644 index 0000000000..3b37620bb7 --- /dev/null +++ b/module/project/js/browse.ui.js @@ -0,0 +1,33 @@ +window.footerGenerator = function() +{ + const statistic = langSummary; + return [{children: statistic, className: "text-dark"}, "flex", "pager"]; +} + +window.programMenuOnClick = function(data, url) +{ + location.href = url.replace('%d', data.item.key); +} + +window.renderReleaseCountCell = function(result, {col, row}) +{ + if(col.name === 'name') + { + if(row.data.delay > 0) result[result.length] = {html:'' + langPostponed + '', className:'flex items-end w-full', style:{flexDirection:"column"}}; + return result; + } + + if(col.name === 'storyCount') + { + result[result.length] = {html:'SP'}; + return result; + } + + if(col.name === 'invested') + { + result[result.length] = {html:'' + langManDay + ''}; + return result; + } + + return result; +} diff --git a/module/project/lang/de.php b/module/project/lang/de.php index 1c110a527a..b0c53041bc 100644 --- a/module/project/lang/de.php +++ b/module/project/lang/de.php @@ -70,6 +70,12 @@ $lang->project->allProjects = "All {$lang->projectCommon}s"; $lang->project->ignore = 'Ignore'; $lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}"; $lang->project->selectProduct = "Select {$lang->productCommon}"; +$lang->project->manageRepo = 'Manage Repo'; +$lang->project->linkedRepo = 'Link Repo'; +$lang->project->unlinkedRepo = 'Unlink Repo'; +$lang->project->executionCount = 'Total Executions'; +$lang->project->storyCount = 'Story Points'; +$lang->project->invested = 'Invested'; /* Fields. */ $lang->project->common = $lang->projectCommon; @@ -228,6 +234,14 @@ $lang->project->checkedSummary = 'Seleted: %total%.'; $lang->project->checkedAllSummary = 'Seleted: %total%, Wait: %wait%, Doing: %doing%, Suspended: %suspended%, Closed: %closed%.'; $lang->project->tenThousand = 'Ten Thousand'; +$lang->project->tip = new stdclass(); +$lang->project->tip->closed = 'The project has been closed. Re-close is not available.'; +$lang->project->tip->notSuspend = 'The project has been closed. Suspend is not available.'; +$lang->project->tip->suspended = 'The project has been suspended. Re-suspend is not available.'; +$lang->project->tip->actived = 'The project has been activated. Re-activated is not available.'; +$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available."; +$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists."; + $lang->project->hundredMillion = 'Hundred Million'; $lang->project->unitList['CNY'] = 'RMB'; @@ -277,8 +291,9 @@ $lang->project->featureBar['browse']['all'] = 'All'; $lang->project->featureBar['browse']['undone'] = 'Unfinished'; $lang->project->featureBar['browse']['wait'] = 'Waiting'; $lang->project->featureBar['browse']['doing'] = 'Doing'; -$lang->project->featureBar['browse']['suspended'] = 'Suspended'; -$lang->project->featureBar['browse']['closed'] = 'Closed'; +$lang->project->featureBar['browse']['exceeded'] = 'Exceeded'; +$lang->project->featureBar['browse']['risky'] = 'Risky'; +$lang->project->featureBar['browse']['more'] = 'More'; $lang->project->featureBar['index']['all'] = 'All'; $lang->project->featureBar['index']['undone'] = 'Unfinished'; @@ -425,3 +440,9 @@ $lang->project->featureBar['dynamic']['thisWeek'] = 'This Week'; $lang->project->featureBar['dynamic']['lastWeek'] = 'Last Week'; $lang->project->featureBar['dynamic']['thisMonth'] = 'This Month'; $lang->project->featureBar['dynamic']['lastMonth'] = 'Last Month'; + +$lang->project->moreSelects = array(); +$lang->project->moreSelects['suspended'] = 'Suspended'; +$lang->project->moreSelects['closed'] = 'Closed'; + +$lang->project->manDay = 'Man Day'; diff --git a/module/project/lang/en.php b/module/project/lang/en.php index 1c110a527a..f74b059176 100644 --- a/module/project/lang/en.php +++ b/module/project/lang/en.php @@ -70,6 +70,12 @@ $lang->project->allProjects = "All {$lang->projectCommon}s"; $lang->project->ignore = 'Ignore'; $lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}"; $lang->project->selectProduct = "Select {$lang->productCommon}"; +$lang->project->manageRepo = 'Manage Repo'; +$lang->project->linkedRepo = 'Link Repo'; +$lang->project->unlinkedRepo = 'Unlink Repo'; +$lang->project->executionCount = 'Total Executions'; +$lang->project->storyCount = 'Story Points'; +$lang->project->invested = 'Invested'; /* Fields. */ $lang->project->common = $lang->projectCommon; @@ -178,7 +184,9 @@ $lang->project->product = $lang->productCommon; $lang->project->branch = 'Platform/Branch'; $lang->project->plan = 'Plan'; $lang->project->createKanban = 'Create Kanban'; -$lang->project->kanban = 'Project Kanban'; +$lang->project->kanban = 'Kanban'; +$lang->project->moreActions = 'More Actions'; +$lang->project->other = 'Other Actions'; /* Project Kanban. */ $lang->project->projectTypeList = array(); @@ -227,6 +235,14 @@ $lang->project->allSummary = "Total {$lang->projectCommon}s: project->checkedSummary = 'Seleted: %total%.'; $lang->project->checkedAllSummary = 'Seleted: %total%, Wait: %wait%, Doing: %doing%, Suspended: %suspended%, Closed: %closed%.'; +$lang->project->tip = new stdclass(); +$lang->project->tip->closed = 'The project has been closed. Re-close is not available.'; +$lang->project->tip->notSuspend = 'The project has been closed. Suspend is not available.'; +$lang->project->tip->suspended = 'The project has been suspended. Re-suspend is not available.'; +$lang->project->tip->actived = 'The project has been activated. Re-activated is not available.'; +$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available."; +$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists."; + $lang->project->tenThousand = 'Ten Thousand'; $lang->project->hundredMillion = 'Hundred Million'; @@ -277,8 +293,9 @@ $lang->project->featureBar['browse']['all'] = 'All'; $lang->project->featureBar['browse']['undone'] = 'Unfinished'; $lang->project->featureBar['browse']['wait'] = 'Waiting'; $lang->project->featureBar['browse']['doing'] = 'Doing'; -$lang->project->featureBar['browse']['suspended'] = 'Suspended'; -$lang->project->featureBar['browse']['closed'] = 'Closed'; +$lang->project->featureBar['browse']['exceeded'] = 'Exceeded'; +$lang->project->featureBar['browse']['risky'] = 'Risky'; +$lang->project->featureBar['browse']['more'] = 'More'; $lang->project->featureBar['index']['all'] = 'All'; $lang->project->featureBar['index']['undone'] = 'Unfinished'; @@ -425,3 +442,9 @@ $lang->project->featureBar['dynamic']['thisWeek'] = 'This Week'; $lang->project->featureBar['dynamic']['lastWeek'] = 'Last Week'; $lang->project->featureBar['dynamic']['thisMonth'] = 'This Month'; $lang->project->featureBar['dynamic']['lastMonth'] = 'Last Month'; + +$lang->project->moreSelects = array(); +$lang->project->moreSelects['suspended'] = 'Suspended'; +$lang->project->moreSelects['closed'] = 'Closed'; + +$lang->project->manDay = 'Man Day'; diff --git a/module/project/lang/fr.php b/module/project/lang/fr.php index 1c110a527a..a569842be7 100644 --- a/module/project/lang/fr.php +++ b/module/project/lang/fr.php @@ -70,6 +70,13 @@ $lang->project->allProjects = "All {$lang->projectCommon}s"; $lang->project->ignore = 'Ignore'; $lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}"; $lang->project->selectProduct = "Select {$lang->productCommon}"; +$lang->project->ignore = 'Ignorer'; +$lang->project->manageRepo = 'Manage Repo'; +$lang->project->linkedRepo = 'Link Repo'; +$lang->project->unlinkedRepo = 'Unlink Repo'; +$lang->project->executionCount = 'Total Executions'; +$lang->project->storyCount = 'Story Points'; +$lang->project->invested = 'Invested'; /* Fields. */ $lang->project->common = $lang->projectCommon; @@ -228,6 +235,14 @@ $lang->project->checkedSummary = 'Seleted: %total%.'; $lang->project->checkedAllSummary = 'Seleted: %total%, Wait: %wait%, Doing: %doing%, Suspended: %suspended%, Closed: %closed%.'; $lang->project->tenThousand = 'Ten Thousand'; +$lang->project->tip = new stdclass(); +$lang->project->tip->closed = 'The project has been closed. Re-close is not available.'; +$lang->project->tip->notSuspend = 'The project has been closed. Suspend is not available.'; +$lang->project->tip->suspended = 'The project has been suspended. Re-suspend is not available.'; +$lang->project->tip->actived = 'The project has been activated. Re-activated is not available.'; +$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available."; +$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists."; + $lang->project->hundredMillion = 'Hundred Million'; $lang->project->unitList['CNY'] = 'RMB'; @@ -425,3 +440,9 @@ $lang->project->featureBar['dynamic']['thisWeek'] = 'This Week'; $lang->project->featureBar['dynamic']['lastWeek'] = 'Last Week'; $lang->project->featureBar['dynamic']['thisMonth'] = 'This Month'; $lang->project->featureBar['dynamic']['lastMonth'] = 'Last Month'; + +$lang->project->moreSelects = array(); +$lang->project->moreSelects['suspended'] = 'Suspendues'; +$lang->project->moreSelects['closed'] = 'Fermées'; + +$lang->project->manDay = 'Man Day'; diff --git a/module/project/lang/zh-cn.php b/module/project/lang/zh-cn.php index 98bb8e8910..55d5612ff4 100644 --- a/module/project/lang/zh-cn.php +++ b/module/project/lang/zh-cn.php @@ -70,6 +70,12 @@ $lang->project->allProjects = "所有{$lang->projectCommon}"; $lang->project->ignore = '忽略'; $lang->project->disableExecution = "不启用{$lang->executionCommon}的{$lang->projectCommon}"; $lang->project->selectProduct = "选择{$lang->productCommon}"; +$lang->project->manageRepo = '关联代码库'; +$lang->project->linkedRepo = '已关联代码库'; +$lang->project->unlinkedRepo = '未关联代码库'; +$lang->project->executionCount = '执行数'; +$lang->project->storyCount = '需求规模'; +$lang->project->invested = '已投入'; /* Fields. */ $lang->project->common = "{$lang->projectCommon}"; @@ -179,6 +185,7 @@ $lang->project->branch = '平台/分支'; $lang->project->plan = '所属计划'; $lang->project->createKanban = '添加看板'; $lang->project->kanban = '项目看板'; +$lang->project->moreActions = '更多操作'; /* Project Kanban. */ $lang->project->projectTypeList = array(); @@ -227,6 +234,14 @@ $lang->project->allSummary = "本页共 %s 个{$lan $lang->project->checkedSummary = "选中 %total% 个{$lang->projectCommon}。"; $lang->project->checkedAllSummary = "选中 %total% 个{$lang->projectCommon},未开始 %wait%,进行中 %doing%,已挂起 %suspended%,已关闭 %closed% 。"; +$lang->project->tip = new stdclass(); +$lang->project->tip->closed = '该项目已是关闭状态,无须关闭。'; +$lang->project->tip->notSuspend = '该项目已关闭,不可进行挂起操作。'; +$lang->project->tip->suspended = '该项目已是挂起状态,无须挂起。'; +$lang->project->tip->actived = '该项目已是激活状态,无须激活。'; +$lang->project->tip->group = '该项目是看板项目,无法进行项目权限分组。'; +$lang->project->tip->whitelist = '该项目是公开项目,无须维护白名单。'; + $lang->project->tenThousand = '万'; $lang->project->hundredMillion = '亿'; @@ -277,8 +292,9 @@ $lang->project->featureBar['browse']['all'] = '全部'; $lang->project->featureBar['browse']['undone'] = '未完成'; $lang->project->featureBar['browse']['wait'] = '未开始'; $lang->project->featureBar['browse']['doing'] = '进行中'; -$lang->project->featureBar['browse']['suspended'] = '已挂起'; -$lang->project->featureBar['browse']['closed'] = '已关闭'; +$lang->project->featureBar['browse']['exceeded'] = '已逾期'; +$lang->project->featureBar['browse']['risky'] = '有风险'; +$lang->project->featureBar['browse']['more'] = '更多'; $lang->project->featureBar['index']['all'] = '全部'; $lang->project->featureBar['index']['undone'] = '未完成'; @@ -425,3 +441,17 @@ $lang->project->featureBar['dynamic']['thisWeek'] = '本周'; $lang->project->featureBar['dynamic']['lastWeek'] = '上周'; $lang->project->featureBar['dynamic']['thisMonth'] = '本月'; $lang->project->featureBar['dynamic']['lastMonth'] = '上月'; + +$lang->project->moreSelects = array(); +$lang->project->moreSelects['suspended'] = '已挂起'; +$lang->project->moreSelects['closed'] = '已关闭'; + +$lang->project->manDay = '人天'; +$lang->project->day = '天'; +$lang->project->newProduct = '新产品'; +$lang->project->associatePlan = '关联计划'; +$lang->project->editorPlaceholder = '可以在编辑器直接贴图。快捷键:Command C+V'; +$lang->project->tenThousandYuan = '万元'; +$lang->project->planDate = '计划日期'; +$lang->project->inputProjectName = '输入项目名称'; +$lang->project->inputProjectCode = '输入项目代号'; diff --git a/module/project/model.php b/module/project/model.php index 1c14cdb5ab..4951652c70 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -1218,6 +1218,32 @@ class projectModel extends model return $lastMenu; } + /** + * Get the program tree of project. + * Copied from getTreeMenu(). + * + * @param int $projectID + * @access public + * @return array + */ + public function getProgramTree($projectID = 0) + { + $programs = array(); + $stmt = $this->dbh->query($this->buildMenuQuery($projectID)); + + while($project = $stmt->fetch()) + { + $prog = new stdClass(); + $prog->id = $project->id; + $prog->name = $project->name; + $prog->parent = $project->parent; + + $programs[] = $prog; + } + + return $programs; + } + /** * Create the manage link. * @@ -2377,6 +2403,124 @@ class projectModel extends model } } + /** + * Print datatable cell for ZIN. + * + * @param object $col + * @param object $project + * @param array $users + * @param object $item + * @param int $programID + * @access public + * @return void + */ + public function printCellZin($col, $project, $users, &$item, $programID = 0) + { + if(!$col->show) return; + + $canOrder = common::hasPriv('project', 'updateOrder'); + $canBatchEdit = common::hasPriv('project', 'batchEdit'); + $account = $this->app->user->account; + $id = $col->id; + $projectLink = helper::createLink('project', 'index', "projectID=$project->id", '', '', $project->id); + + $title = ''; + $class = "c-$id" . (in_array($id, array('budget', 'teamCount', 'estimate', 'consume')) ? ' c-number' : ''); + + if($id == 'id') $class .= ' cell-id'; + + if($id == 'code') + { + $class .= ' c-name'; + $title = "title={$project->code}"; + } + elseif($id == 'name') + { + $class .= ' text-left'; + $title = "title='{$project->name}'"; + } + elseif($id == 'PM') + { + $class .= ' c-manager'; + } + + if($id == 'end') + { + $project->end = $project->end == LONG_TIME ? $this->lang->project->longTime : $project->end; + $class .= ' c-name'; + $title = "title='{$project->end}'"; + } + + if($id == 'budget') + { + $projectBudget = $this->getBudgetWithUnit($project->budget); + $budgetTitle = $project->budget != 0 ? zget($this->lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $this->lang->project->future; + + $title = "title='$budgetTitle'"; + } + + if($id == 'estimate') $title = "title='{$project->hours->totalEstimate} {$this->lang->execution->workHour}'"; + if($id == 'consume') $title = "title='{$project->hours->totalConsumed} {$this->lang->execution->workHour}'"; + if($id == 'surplus') $title = "title='{$project->hours->totalLeft} {$this->lang->execution->workHour}'"; + + /* TODO attach flow cells. */ + /* if($this->config->edition != 'open') $this->loadModel('flow')->printFlowCell('project', $project, $id); */ + switch($id) + { + case 'id': + $item->id = sprintf('%03d', $project->id); + break; + case 'name': + $item->name = $project->name; + $item->delay = isset($project->delay) ? $project->delay : 0; + break; + case 'code': + $item->code = $project->code; + break; + case 'PM': + $item->PM = $project->PM; + break; + case 'begin': + $item->begin = $project->begin; + break; + case 'end': + $item->end = $project->end; + break; + case 'status': + $item->status = zget($this->lang->project->statusList, $project->status); + break; + case 'hasProduct': + $item->hasProduct = zget($this->lang->project->projectTypeList, $project->hasProduct); + break; + case 'budget': + $item->budget = $budgetTitle; + break; + case 'teamCount': + $item->teamCount = $project->teamCount; + break; + case 'estimate': + $item->estimate = $project->hours->totalEstimate . $this->lang->execution->workHourUnit; + break; + case 'consume': + $item->consume = $project->hours->totalConsumed . $this->lang->execution->workHourUnit; + break; + case 'surplus': + $item->surplus = $project->hours->totalLeft . $this->lang->execution->workHourUnit; + break; + case 'progress': + $item->progress = $project->hours->progress; + break; + case 'actions': + $project->programID = $programID; + $this->buildOperateMenuZin($project, $item, 'browse'); + break; + } + + $item->storyCount = rand(100, 100000) / 10.0; + $item->executionCount = rand(10, 200); + $item->invested = rand(10, 100); + } + /** * Convert budget unit. * @@ -3062,6 +3206,21 @@ class projectModel extends model return $result; } + /** + * Build project action menu. + * + * @param object $project + * @param object $item + * @param string $type + * @access public + * @return string + */ + public function buildOperateMenuZin($project, &$item, $type = 'view') + { + $function = 'buildOperate' . ucfirst($type) . 'MenuZin'; + return $this->$function($project, $item); + } + /** * Build project action menu. * @@ -3106,6 +3265,52 @@ class projectModel extends model return $menu; } + /** + * Build project browse action menu. + * + * @param object $project + * @param object $item + * @access public + * @return string + */ + public function buildOperateBrowseMenuZin($project, &$item) + { + $item->actions = array(); + $moduleName = 'project'; + + if($project->status == 'wait' || $project->status == 'suspended') $item->actions[] = 'start'; + if($project->status == 'doing') $item->actions[] = 'close'; + if($project->status == 'closed') $item->actions[] = 'active'; + + if(common::hasPriv($moduleName, 'suspend') || (common::hasPriv($moduleName, 'close') && $project->status != 'doing') || (common::hasPriv($moduleName, 'activate') && $project->status != 'closed')) + { + $menu = 'pause'; + $comma = ','; + if($project->status != 'doing') $menu .= $comma . 'close'; + if($project->status != 'closed') $menu .= $comma . 'active'; + + $item->actions[] = 'other:' . $menu; + } + + $item->actions[] = 'edit'; + + if($this->config->vision != 'lite') + { + $item->actions[] = 'group'; + $item->actions[] = 'perm'; + + if(common::hasPriv($moduleName, 'manageProducts') || common::hasPriv($moduleName, 'whitelist') || common::hasPriv($moduleName, 'delete')) + { + $item->actions[] = 'more:link,whitelist,delete'; + } + return; + } + + $item->actions[] = 'group'; + $item->actions[] = 'whitelist'; + $item->actions[] = 'delete'; + } + /** * Build project browse action menu. * diff --git a/module/project/ui/browse.html.php b/module/project/ui/browse.html.php new file mode 100644 index 0000000000..82405d2210 --- /dev/null +++ b/module/project/ui/browse.html.php @@ -0,0 +1,125 @@ +project->browseTable->cols); +$programTree = $this->project->getProgramTree(0, array('projectmodel', 'createManageLink'), 0, 'list'); +$usersAvatar = $this->user->getAvatarPairs(''); + +$data = []; +$setting = $this->datatable->getSetting('project'); +$waitCount = 0; +$doingCount = 0; +$suspendedCount = 0; +$closedCount = 0; +foreach($projectStats as $project) +{ + if($project->status == 'wait') $waitCount++; + if($project->status == 'doing') $doingCount++; + if($project->status == 'suspended') $suspendedCount++; + if($project->status == 'closed') $closedCount++; + + $item = new stdClass(); + foreach($setting as $value) $this->project->printCellZin($value, $project, $users, $item, $programID); + + $item->PMAvatar = $usersAvatar[$item->PM]; + $item->PM = zget($users, $item->PM); + + $data[] = $item; +} + +$programMenuLink = createLink +( + $this->app->rawModule, + $this->app->rawMethod, + [ + 'programID' => '%d', + 'browseType' => $browseType, + 'param' => $param, + 'orderBy' => $orderBy, + 'recTotal' => $recTotal, + 'recPerPage' => $recPerPage, + 'pageID' => $pageID + ] +); + +$featureBarItemLink = createLink($this->app->rawModule, $this->app->rawMethod, array +( + 'programID' => $programID, + 'browseType' => '{key}', + 'param' => $param, + 'orderBy' => $orderBy, + 'recTotal' => $pager->recTotal, + 'recPerPage' => $recPerPage, + 'pageID' => $pageID +)); + +$summary = $browseType == 'all' + ? sprintf($lang->project->allSummary, count($projectStats), $waitCount, $doingCount, $suspendedCount, $closedCount) + : sprintf($lang->project->summary, count($projectStats)); +$summary = str_replace('', '', str_replace('', '', $summary)); + +jsVar('langPostponed', $this->lang->project->statusList['delay']); +jsVar('langManDay', $this->lang->project->manDay); + +featureBar +( + to::before + ( + programMenu + ( + setStyle(array('margin-right' => '20px')), + set + ( + [ + 'title' => $lang->program->all, + 'programs' => $programTree, + 'activeKey' => !empty($programs) ? $programID : null, + 'closeLink' => sprintf($programMenuLink, 0), + 'onClickItem' => jsRaw("function(data){window.programMenuOnClick(data, '$programMenuLink');}") + ] + ) + ) + ), + set::link($featureBarItemLink), + set::moreMenuLinkCallback(fn($key) => str_replace('{key}', $key, $featureBarItemLink)), + hasPriv('project', 'batchEdit') + ? item + ( + set::type('checkbox'), + set::text($lang->project->edit), + set::checked($this->cookie->showProjectBatchEdit) + ) + : NULL, + li(searchToggle(set::open($browseType == 'bysearch'))) +); + +toolbar +( + item(set( + [ + 'text' => $lang->export, + 'icon' => 'export', + 'class' => 'ghost text-darker', + 'url' => createLink('project', 'export', $browseType, "status=$browseType&orderBy=$orderBy", 'html'), + ])), + item(set( + [ + 'text' => $lang->project->create, + 'icon' => 'plus', + 'class' => 'btn primary', + 'url' => createLink('project', 'create', '') + ])), +); + +jsVar('langSummary', $summary); + +dtable +( + set::cols($cols), + set::data($data), + set::footPager(usePager()), + set::onRenderCell(jsRaw('function(result, data){ return window.renderReleaseCountCell(result, data); }')), + set::footer(jsRaw('window.footerGenerator')) +); + +render(); diff --git a/module/project/ui/close.html.php b/module/project/ui/close.html.php new file mode 100644 index 0000000000..26173c89c5 --- /dev/null +++ b/module/project/ui/close.html.php @@ -0,0 +1,31 @@ +id); +set::title($project->name); + +form +( + set::url(createLink('project', 'close', ['projectID' => $project->id])), + formGroup + ( + set::label($app->loadLang('program')->program->realEnd), + set::required(true), + set::name('realEnd'), + set::control('date'), + ), + formGroup + ( + set::label($lang->comment), + set::name('comment'), + set::control(['type' => 'textarea', 'rows' => 5]), + ), + set::submitBtnText($lang->project->close) +); + +h::hr(setClass('my-5')); + +historyRecord(); + +render('modalDialog'); diff --git a/module/project/ui/create.html.php b/module/project/ui/create.html.php new file mode 100644 index 0000000000..f213abafc6 --- /dev/null +++ b/module/project/ui/create.html.php @@ -0,0 +1,296 @@ +project->modelList as $key => $text) +{ + if(empty($key)) continue; + + $projectModelItems[] = array + ( + 'active' => ($key == $model), + 'url' => '', + 'text' => $text, + 'data-type' => 'ajax' + ); +} + +$currency = $parentProgram ? $parentProgram->budgetUnit : $config->project->defaultCurrency; + +$title = $this->view->title; +useData('title', null); + +formPanel +( + to::heading(div + ( + setClass('panel-title text-lg'), + $title, + dropdown + ( + btn + ( + set::id('project-model'), + setClass('secondary-outline h-5 px-2'), + zget($lang->project->modelList, $model, '') + ), + set::trigger('click'), + set::placement('bottom'), + set::menuProps(array('style' => array('color' => 'var(--color-fore)'))), + set::arrow(true), + set::items($projectModelItems) + ) + )), + to::headingActions + ( + div + ( + setClass('flex mr-5'), + icon('cog-outline') + ), + btn + ( + setClass('primary-pale'), + set::icon('copy'), + $lang->project->copy + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::name('parent'), + set::label($lang->project->parent), + set::items($programList) + ), + formGroup + ( + set::width('1/2'), + div + ( + setClass('pl-2 flex self-center'), + setStyle(['color' => 'var(--form-label-color)']), + icon('help') + ) + ) + ), + formGroup + ( + set::width('1/2'), + set::name('name'), + set::label($lang->project->name), + set::strong(true), + set::placeholder($lang->project->inputProjectName) + ), + (!isset($config->setCode) or $config->setCode == 1) ? formGroup + ( + set::width('1/2'), + set::name('code'), + set::label($lang->project->code), + set::strong(true), + set::placeholder($lang->project->inputProjectCode) + ) : NULL, + ($model == 'waterfall') ? NULL : formGroup + ( + set::width('1/2'), + set::name('multiple'), + set::label($lang->project->multiple), + set::control(array('type' => 'radioList', 'inline' => true)), + set::items($lang->project->multipleList), + set::value($multiple), + empty($copyProjectID) ? NULL : formHidden('multiple', $multiple) + ), + formGroup + ( + set::width('1/2'), + set::label($lang->project->type), + inputGroup + ( + set::seg(true), + btn + ( + setClass('primary-pale'), + $lang->project->projectTypeList[1] + ), + btn($lang->project->projectTypeList[0]) + ), + /* TODO change value with button click event */ + formHidden('hasProduct', 1) + ), + formGroup + ( + set::width('1/4'), + set::name('PM'), + set::label($lang->project->PM), + set::items($pmUsers) + ), + formRow + ( + formGroup + ( + set::width('1/4'), + set::name('budget'), + set::label($lang->project->budget), + set::control(array + ( + 'type' => 'inputControl', + 'prefix' => zget($lang->project->currencySymbol, $currency), + 'prefixWidth' => 'icon', + 'suffix' => $lang->project->tenThousandYuan, + 'suffixWidth' => 60, + )), + $parentProgram ? NULL : formHidden('budgetUnit', $config->project->defaultCurrency) + ), + formGroup + ( + set::width('1/4'), + set::name('future'), + set::control(array('type' => 'checkList', 'inline' => true)), + set::items(array('1' => $lang->project->future)) + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->project->planDate), + set::required(true), + inputGroup + ( + input + ( + set::name('begin'), + set::type('date'), + set::value(date('Y-m-d')), + set::placeholder($lang->project->begin), + set::required(true), + /* TODO associate event */ + on::change('computeWorkDays') + ), + $lang->project->to, + input + ( + set::name('end'), + set::type('date'), + set::placeholder($lang->project->end), + set::required(true), + /* TODO associate event */ + on::change('computEndDate(this.value)') + ), + ) + ), + formGroup + ( + set::width('1/4'), + inputGroup + ( + $lang->execution->days, + setClass('has-suffix'), + input + ( + set::name('days'), + set::required(true), + ), + div + ( + setClass('input-control-suffix z-50'), + $lang->project->day + ) + ) + ), + formGroup + ( + set::width('1/4'), + set::name('delta'), + set::control(array('type' => 'checkList', 'inline' => true)), + set::items(array('999' => $lang->project->endList['999'])) + ), + ), + /* TODO handle !empty($products) */ + $products ? NULL : + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->project->manageProducts), + inputGroup + ( + div + ( + setClass('grow'), + select + ( + set::name('products[0]'), + set::items($allProducts), + set::multiple(false) + ) + ), + div + ( + setClass('flex items-center pl-2'), + checkbox + ( + set::name('newProduct'), + set::text($lang->project->newProduct) + ) + ) + ) + ), + formGroup + ( + set::width('1/2'), + inputGroup + ( + $lang->project->associatePlan, + select + ( + set::name('plans[][]'), + set::items(NULL), + set::multiple(false) + ) + ) + ) + ), + formGroup + ( + set::name('desc'), + set::label($lang->project->desc), + set::control('editor'), + set::placeholder($lang->project->editorPlaceholder) + ), + /* TODO printExtendFields() */ + formGroup + ( + set::width('1/2'), + set::name('acl'), + set::label($lang->project->acl), + set::control('radioList'), + set::items($lang->project->aclList), + set::value('open') + ), + /* TODO add events */ + formGroup + ( + set::width('1/2'), + set::name('whitelist[]'), + set::label($lang->whitelist), + set::items($users), + set::control(['type' => 'select', 'multiple' => false]) + ), + formGroup + ( + set::width('1/2'), + set::name('auth'), + set::label($lang->project->auth), + set::control('radioList'), + set::items($lang->project->authList), + set::value('extend') + ), +); + +useData('title', $title); + +render(); diff --git a/module/search/control.php b/module/search/control.php index bb0e45f202..dc055a0a23 100644 --- a/module/search/control.php +++ b/module/search/control.php @@ -11,6 +11,8 @@ */ class search extends control { + public $search; + /** * Determine whether to display the effort object. * @@ -64,7 +66,18 @@ class search extends control $this->view->queryID = $queryID; $this->view->style = empty($style) ? 'full' : $style; $this->view->onMenuBar = empty($onMenuBar) ? 'no' : $onMenuBar; - $this->display(); + $this->view->formSession = $_SESSION[$module . 'Form']; + $this->view->fields = $fields; + + if($module == 'program') + { + $this->view->options = $this->search->setOptions($fields, $this->view->fieldParams, $this->view->queries); + $this->render(); + } + else + { + $this->display(); + } } /** @@ -114,6 +127,11 @@ class search extends control $data = fixer::input('post')->get(); $shortcut = empty($data->onMenuBar) ? 0 : 1; + if($this->viewType == 'json') + { + echo 'success'; + return; + } return print(js::closeModal('parent.parent', '', "function(){parent.parent.loadQueries($queryID, $shortcut, '{$data->title}')}")); } diff --git a/module/search/js/buildform.ui.js b/module/search/js/buildform.ui.js new file mode 100644 index 0000000000..61f5cf1e24 --- /dev/null +++ b/module/search/js/buildform.ui.js @@ -0,0 +1,15 @@ +window.onDeleteQuery = function(event, queryID) +{ + event.stopPropagation(); + + var deleteQueryURL = onDeleteQueryURL; + fetch(deleteQueryURL.replace('myQueryID', queryID), {method:'POST'}) + .then((response) => { + if (!response.ok) throw new Error('HTTP error! Status: ' + response.status); + return response.text(); + }) + .then((text) => { + if(text === 'success') event.target.closest('div').remove(); + else throw new Error('Failed: ' + text); + }); +} diff --git a/module/search/lang/de.php b/module/search/lang/de.php index bc55ae01a2..f3e0db5304 100644 --- a/module/search/lang/de.php +++ b/module/search/lang/de.php @@ -31,6 +31,7 @@ $lang->search->onMenuBar = 'In Menü anzeigen'; $lang->search->custom = 'Eigene'; $lang->search->setCommon = 'Set as public query criteria'; $lang->search->saveCondition = 'Save search options'; +$lang->search->setCondName = 'Please enter a save condition name'; $lang->search->account = 'Konto'; $lang->search->module = 'Module'; diff --git a/module/search/lang/en.php b/module/search/lang/en.php index dc173518b0..5a399f389f 100644 --- a/module/search/lang/en.php +++ b/module/search/lang/en.php @@ -31,6 +31,7 @@ $lang->search->onMenuBar = 'Show in Menu'; $lang->search->custom = 'Custom'; $lang->search->setCommon = 'Set as public query criteria'; $lang->search->saveCondition = 'Save search options'; +$lang->search->setCondName = 'Please enter a save condition name'; $lang->search->account = 'Account'; $lang->search->module = 'Module'; diff --git a/module/search/lang/fr.php b/module/search/lang/fr.php index fb0b3d8249..bddb00312e 100644 --- a/module/search/lang/fr.php +++ b/module/search/lang/fr.php @@ -31,6 +31,7 @@ $lang->search->onMenuBar = 'Montrer dans le Menu'; $lang->search->custom = 'Personnalisation'; $lang->search->setCommon = 'Set as public query criteria'; $lang->search->saveCondition = 'Save search options'; +$lang->search->setCondName = 'Please enter a save condition name'; $lang->search->account = 'Compte'; $lang->search->module = 'Module'; diff --git a/module/search/lang/vi.php b/module/search/lang/vi.php index 5d6cf08fd5..a1dfccc252 100644 --- a/module/search/lang/vi.php +++ b/module/search/lang/vi.php @@ -10,6 +10,10 @@ * @link http://www.zentao.net */ $lang->search->common = 'Tìm kiếm'; +$lang->search->id = 'ID'; +$lang->search->editedDate = 'Edited Date'; +$lang->search->key = 'Key'; +$lang->search->value = 'Value'; $lang->search->reset = 'Thiết lập lại'; $lang->search->saveQuery = 'Lưu truy vấn'; $lang->search->myQuery = 'My truy vấn'; @@ -25,6 +29,9 @@ $lang->search->me = 'Của bạn'; $lang->search->noQuery = 'Không có truy vấn được lưu nào!'; $lang->search->onMenuBar = 'Hiện trong Menu'; $lang->search->custom = 'Tùy biến'; +$lang->search->setCommon = 'Set as public query criteria'; +$lang->search->saveCondition = 'Save search options'; +$lang->search->setCondName = 'Please enter a save condition name'; $lang->search->account = 'Tài khoản'; $lang->search->module = 'Module'; @@ -52,23 +59,24 @@ $lang->search->null = 'Null'; $lang->userquery = new stdclass(); $lang->userquery->title = 'Title'; -$lang->searchObjects['todo'] = 'Việc làm'; -$lang->searchObjects['effort'] = 'Chấm công'; +$lang->searchObjects['todo'] = 'Việc làm'; +$lang->searchObjects['effort'] = 'Chấm công'; $lang->searchObjects['testsuite'] = 'Test Suite'; $lang->search->objectType = 'Loại đối tượng'; $lang->search->objectID = 'ID đối tượng'; -$lang->search->content = 'Nội dung'; +$lang->search->content = 'Nội dung'; $lang->search->addedDate = 'Ngày thêm'; -$lang->search->index = 'Full Text Search'; +$lang->search->index = 'Full Text Search'; $lang->search->buildIndex = 'Rebuild Index'; -$lang->search->preview = 'Preview'; +$lang->search->preview = 'Preview'; -$lang->search->result = 'Kết quả tìm kiếm'; +$lang->search->result = 'Kết quả tìm kiếm'; $lang->search->buildSuccessfully = 'Tìm kiếm khởi tạo chỉ mục.'; -$lang->search->executeInfo = '%s kết quả tìm kiếm trong %s giây'; +$lang->search->executeInfo = '%s kết quả tìm kiếm trong %s giây'; $lang->search->buildResult = "Create index %s and created %s records."; +$lang->search->queryTips = "Separate ids with comma"; $lang->search->modules['all'] = 'Tất cả'; $lang->search->modules['task'] = 'Nhiệm vụ'; @@ -89,10 +97,12 @@ $lang->search->modules['program'] = 'Program'; $lang->search->modules['project'] = 'Project'; $lang->search->modules['execution'] = $lang->executionCommon; $lang->search->modules['story'] = 'Story'; +$lang->search->modules['requirement'] = $lang->URCommon; $lang->search->objectTypeList['story'] = $lang->SRCommon; $lang->search->objectTypeList['requirement'] = $lang->URCommon; $lang->search->objectTypeList['stage'] = 'stage'; $lang->search->objectTypeList['sprint'] = $lang->executionCommon; +$lang->search->objectTypeList['kanban'] = 'kanban'; $lang->search->objectTypeList['commonIssue'] = 'Issue'; $lang->search->objectTypeList['stakeholderIssue'] = 'Stakeholder Issue'; diff --git a/module/search/lang/zh-cn.php b/module/search/lang/zh-cn.php index 993e130fea..7e3bd4082f 100644 --- a/module/search/lang/zh-cn.php +++ b/module/search/lang/zh-cn.php @@ -31,6 +31,7 @@ $lang->search->onMenuBar = '显示在菜单栏'; $lang->search->custom = '自定义'; $lang->search->setCommon = '设为公共查询条件'; $lang->search->saveCondition = '保存搜索条件'; +$lang->search->setCondName = '请输入保存条件名称'; $lang->search->account = '用户名'; $lang->search->module = '模块'; diff --git a/module/search/lang/zh-tw.php b/module/search/lang/zh-tw.php index b0bcb3687f..37ecfd546f 100644 --- a/module/search/lang/zh-tw.php +++ b/module/search/lang/zh-tw.php @@ -29,6 +29,9 @@ $lang->search->me = '自己'; $lang->search->noQuery = '還沒有保存查詢!'; $lang->search->onMenuBar = '顯示在菜單欄'; $lang->search->custom = '自定義'; +$lang->search->setCommon = '設為公共查詢條件'; +$lang->search->saveCondition = '保存搜索條件'; +$lang->search->setCondName = '請輸入保存條件名稱'; $lang->search->account = '用戶名'; $lang->search->module = '模組'; @@ -73,6 +76,7 @@ $lang->search->result = '搜索結果'; $lang->search->buildSuccessfully = '初始化搜索索引成功'; $lang->search->executeInfo = '為您找到相關結果%s個,耗時%s秒'; $lang->search->buildResult = "創建 %s 索引, 已創建 %s 條記錄;"; +$lang->search->queryTips = "多個id可用英文逗號分隔"; $lang->search->modules['all'] = '全部'; $lang->search->modules['task'] = '任務'; @@ -92,11 +96,13 @@ $lang->search->modules['productplan'] = '計劃'; $lang->search->modules['program'] = '項目集'; $lang->search->modules['project'] = '項目'; $lang->search->modules['execution'] = $lang->executionCommon; -$lang->search->modules['story'] = '需求'; +$lang->search->modules['story'] = $lang->SRCommon; +$lang->search->modules['requirement'] = $lang->URCommon; $lang->search->objectTypeList['story'] = $lang->SRCommon; $lang->search->objectTypeList['requirement'] = $lang->URCommon; $lang->search->objectTypeList['stage'] = '階段'; $lang->search->objectTypeList['sprint'] = $lang->executionCommon; +$lang->search->objectTypeList['kanban'] = '看板'; $lang->search->objectTypeList['commonIssue'] = '問題'; $lang->search->objectTypeList['stakeholderIssue'] = '干係人問題'; diff --git a/module/search/model.php b/module/search/model.php index 4ecf897ed2..0db5f4d4d2 100644 --- a/module/search/model.php +++ b/module/search/model.php @@ -1409,4 +1409,243 @@ class searchModel extends model return $object; } + + /** + * Set search form options. + * + * @param array $fields + * @param array $fieldParams + * @param array $queries + * @access public + * @return object + */ + public function setOptions($fields, $fieldParams, $queries = array()) + { + $options = new stdclass(); + $options->operators = array(); + $options->fields = array(); + $options->savedQueryTitle = $this->lang->search->savedQuery; + $options->andOr = array(); + $options->groupName = array($this->lang->search->group1, $this->lang->search->group2); + $options->searchBtnText = $this->lang->search->common; + $options->resetBtnText = $this->lang->search->reset; + $options->saveSearchBtnText = $this->lang->search->saveCondition; + foreach($this->lang->search->andor as $value => $title) + { + $andOr = new stdclass(); + $andOr->value = $value; + $andOr->title = $title; + + $options->andOr[] = $andOr; + } + + foreach($this->lang->search->operators as $value => $title) + { + $operator = new stdclass(); + $operator->value = $value; + $operator->title = $title; + + $options->operators[] = $operator; + } + + foreach($fieldParams as $field => $param) + { + $data = new stdclass(); + $data->label = $fields[$field]; + $data->name = $field; + $data->control = $param['control']; + $data->operator = $param['operator']; + + if($field == 'id') $data->placeholder = $this->lang->search->queryTips; + if(!empty($param['values']) and is_array($param['values'])) $data->values = $param['values']; + + $options->fields[] = $data; + } + + $savedQuery = array(); + foreach($queries as $query) + { + if(empty($query->id)) continue; + $savedQuery[] = $query; + } + + if(!empty($savedQuery)) $options->savedQuery = $savedQuery; + + $options->formConfig = new stdclass(); + $options->formConfig->method = 'post'; + $options->formConfig->action = helper::createLink('search', 'buildQuery'); + $options->formConfig->target = 'hiddenwin'; + + $options->saveSearch = new stdclass(); + $options->saveSearch->text = $this->lang->search->saveCondition; + + return $options; + } + + /** + * Build search form options. + * + * @param array $module + * @param array $fieldParams + * @param array $fieldsMap + * @param array $queries + * @access public + * @return object + */ + public function buildSearchFormOptions($module, $fieldParams, $fields, $queries) + { + $opts = new stdClass(); + $opts->formConfig = static::buildFormConfig(); + $opts->fields = static::buildFormFields($fieldParams, $fields); + $opts->operators = static::buildFormOperators($this->lang->search->operators); + $opts->andOr = static::buildFormAndOrs($this->lang->search->andor); + $opts->saveSearch = static::buildFormSaveSearch($module); + $opts->savedQuery = static::buildFormSavedQuery($queries, $this->app->user->account); + + return $opts; + } + + /** + * Form Configuration of buildForm action. + * + * @access public + * @return object + */ + public static function buildFormConfig() + { + $config = new stdClass(); + $config->action = helper::createLink('search', 'buildQuery'); + $config->method = 'post'; + + return $config; + } + + /** + * Fields options of buildForm action. + * + * @param array $fieldParams + * @param array $fieldsMap + * @access public + * @return array + */ + public static function buildFormFields($fieldParams, $fieldsMap) + { + $fields = array(); + + foreach($fieldParams as $name => $param) + { + $field = new stdClass(); + $field->label = isset($fieldsMap[$name]) ? $fieldsMap[$name] : ''; + $field->name = $name; + $field->control = $param['control']; + $field->operator = $param['operator']; + $field->defaultValue = ''; + $field->placeholder = ''; + $field->values = $param['values']; + + $fields[] = $field; + } + + return $fields; + } + + /** + * Operators of buildForm action. + * + * @param array $operators + * @access public + * @return array + */ + public static function buildFormOperators($operators) + { + $ops = array(); + + foreach($operators as $val => $title) + { + $op = new stdClass(); + $op->value = $val; + $op->title = $title; + + $ops[] = $op; + } + + return $ops; + } + + /** + * AndOr options of buildForm action. + * + * @param array $andOrs + * @access public + * @return array + */ + public static function buildFormAndOrs($andOrs) + { + $result = array(); + + foreach($andOrs as $val => $title) + { + $item = new stdClass(); + $item->value = $val; + $item->title = $title; + + $result[] = $item; + } + + return $result; + } + + /** + * Save Search button of buildForm action. + * + * @param array $module + * @access public + * @return object + */ + public static function buildFormSaveSearch($module) + { + global $lang; + + $result = new stdClass(); + $result->text = $lang->search->saveCondition; + $result->hasPriv = common::hasPriv('search', 'saveQuery'); + $result->config = array( + 'data-toggle' => 'modal', + 'data-type' => 'ajax', + 'data-data-type' => 'html', + 'data-url' => helper::createLink('search', 'saveQuery', array('module' => $module)), + ); + + return $result; + } + + /** + * Saved Queries list of buildForm action. + * + * @param array $queries + * @param array $account + * @access public + * @return array + */ + public static function buildFormSavedQuery($queries, $account) + { + $result = array(); + if(empty($queries)) return $result; + + $hasPriv = common::hasPriv('search', 'deleteQuery'); + foreach($queries as $query) + { + if(!is_object($query)) continue; + + $item = new stdClass(); + $item->id = $query->id; + $item->title = $query->title; + $item->account = $query->account; + $item->hasPriv = ($hasPriv && $account == $query->account); + + $result[] = $item; + } + + return $result; + } } diff --git a/module/search/ui/buildform.html.php b/module/search/ui/buildform.html.php new file mode 100644 index 0000000000..657b8e5293 --- /dev/null +++ b/module/search/ui/buildform.html.php @@ -0,0 +1,28 @@ +search->buildSearchFormOptions($module, $fieldParams, $fields, $queries); + +$opts->groupName = array($lang->search->group1, $lang->search->group2); +$opts->savedQueryTitle = $lang->search->savedQuery; +$opts->applyQueryURL = $actionURL; +$opts->deleteQueryURL = createLink('search', 'deleteQuery', 'queryID=myQueryID'); +$opts->formSession = $formSession; +$opts->module = $module; +$opts->actionURL = $actionURL; +$opts->groupItems = $groupItems; +$opts->onDeleteQuery = jsRaw('window.onDeleteQuery'); + +if(empty($opts->savedQuery)) unset($opts->savedQuery); + +zui::searchform(set($opts), set::_to('#searchFormPanel'), set::className('shadow')); + +jsVar('onDeleteQueryURL', $opts->deleteQueryURL); +jsVar('options', isset($options) ? $options : null); +jsVar('canSaveQuery', !empty($_SESSION[$module . 'Query'])); +jsVar('formSession', $_SESSION[$module . 'Form']); +jsVar('onMenuBar', $onMenuBar); + +js($pageJS); + +render('fragment'); diff --git a/module/search/ui/savequery.html.php b/module/search/ui/savequery.html.php new file mode 100644 index 0000000000..00164b1f1f --- /dev/null +++ b/module/search/ui/savequery.html.php @@ -0,0 +1,50 @@ +search->setCondName) + ), + checkbox + ( + set::id('common'), + set::name('common'), + set::value(1), + set::class('w-3/12'), + $lang->search->setCommon + ), + checkbox + ( + set::id('onMenuBar'), + set::name('onMenuBar'), + set::class('w-3/12'), + $lang->search->onMenuBar + ), + btn( + setClass('w-1/12 primary'), + set::type('submit'), + set('data-type', 'submit'), + $lang->save + ), + input + ( + set::type('hidden'), + set::name('module'), + set::value($module) + ) + ) +); + +render('modalDialog'); diff --git a/module/task/control.php b/module/task/control.php index 43b52f9852..e53bf8d65e 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -1009,7 +1009,9 @@ class task extends control $this->view->modulePath = $this->tree->getParents($task->module); $this->view->linkMRTitles = $this->loadModel('mr')->getLinkedMRPairs($taskID, 'task'); $this->view->linkCommits = $this->loadModel('repo')->getCommitsByObject($taskID, 'task'); - $this->display(); + $this->view->methodName = $this->methodName; + // $this->display(); + $this->render(); } /** diff --git a/module/task/ui/assignto.html.php b/module/task/ui/assignto.html.php new file mode 100644 index 0000000000..f5f2b71cf7 --- /dev/null +++ b/module/task/ui/assignto.html.php @@ -0,0 +1,52 @@ + $value) +{ + $items[] = ['text' => $value, 'value' => $key]; +} + +set::itemID($task->id); +set::title($task->name); + +form +( + formGroup + ( + set::label($lang->assignedToAB), + set::name('assignedTo'), + set::control(['type' => 'select', 'items' => $items]), + ), + formGroup + ( + set::label($lang->task->left), + div + ( + setClass('input-control has-suffix'), + input + ( + set::type('number'), + set::min(0), + set::name('left'), + set::id('left'), + ), + h::label + ( + setClass('input-control-suffix'), + $lang->workingHour + ) + ) + ), + formGroup + ( + set::label($lang->comment), + set::name('comment'), + set::control(['type' => 'textarea']), + ), + set::actions(['save']) +); + +render('modalDialog'); diff --git a/module/task/ui/create.html.php b/module/task/ui/create.html.php new file mode 100644 index 0000000000..276dd95d70 --- /dev/null +++ b/module/task/ui/create.html.php @@ -0,0 +1,259 @@ + $menuItem->text, + 'url' => \commonModel::createMenuLink($menuItem, $app->tab), + 'active' => $menuItem->order === 1, + ); +} + +page( + h::style(<<{$app->tab}->common), + set('icon', $app->tab), + set('url', \helper::createLink($app->tab, 'browse')), + ), + pageNavbar + ( + setId('navbar'), + set('items', $navItems) + ), + pageToolbar + ( + set('create', array('href' => '#globalCreateMenu')), + set('switcher', array('href' => '#switcherMenu', 'text' => '研发管理界面')), + block('avatar', avatar(set('name', $app->user->account), set('avatar', $app->user->avatar), set('trigger', '#userMenu'))) + ) + ), + div + ( + setStyle(array('width' => '1000px', 'margin' => '0 auto', 'background' => '#fff')), + div + ( + setClass('px-8 py-6'), + h2 + ( + setStyle(array('font-size' => '1.2rem', 'font-weight' => 'bold')), + $lang->task->create + ), + ), + div + ( + setStyle(array('padding-left' => '3rem', 'padding-bottom' => '1rem')), + formGrid + ( + formGroup + ( + set('label', array('required' => true, 'text' => $lang->task->execution)), + select( + setClass('w-360'), + set('name', 'execution'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k == $execution->id);}, $executions, array_keys($executions))) + ) + ), + formGroup + ( + set('label', array('required' => true, 'text' => $lang->task->type)), + select + ( + setClass('w-360'), + set('name', 'type'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === $task->type);}, $lang->task->typeList, array_keys($lang->task->typeList))) + ) + ), + formGroup + ( + set('label', array('text' => $lang->task->module)), + formRow + ( + setClass('items-center'), + select + ( + setClass('w-360'), + set('name', 'module'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === $task->module);}, $moduleOptionMenu, array_keys($moduleOptionMenu))) + ), + checkbox + ( + set('name', 'showAllModule'), + set(array('text' => $lang->task->allModule)) + ) + ), + ), + formGroup + ( + set('label', array('text' => $lang->task->story)), + select( + setClass('w-740'), + set('name', 'story'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === $task->story);}, $stories, array_keys($stories))) + ) + ), + formGroup + ( + set('name', 'name'), + set('label', array('text' => $lang->task->name, 'required' => true)), + formInput(setClass('w-740')), + ), + formGroup + ( + set('name', 'pri'), + set('label', array('text' => $lang->task->pri)), + setClass('w-360'), + select + ( + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === $task->pri);}, $lang->task->priList, array_keys($lang->task->priList))) + ) + ), + formRow + ( + setClass('items-center'), + formGroup + ( + set('label', array('text' => $lang->task->assignedTo)), + select + ( + set('name', 'assignedTo[]'), + setClass('w-360'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === $task->assignedTo);}, $members, array_keys($members))) + ) + ), + formGroup + ( + set('label', array('text' => $lang->task->estimateAB, 'auto' => true)), + inputGroup + ( + set('items', array( + array('type' => 'input', 'class' => 'w-60', 'name' => 'estimate'), + array('type' => 'addon', 'text' => 'H'), + )) + ) + ), + formGroup + ( + checkbox + ( + set(array('text' => $lang->task->multiple)), + set('name', 'multiple') + ) + ) + ), + + formGroup + ( + set('label', array('text' => $lang->task->desc)), + textarea + ( + set('name', 'desc'), + setClass('form-control w-740'), + set(array( + 'placeholder' => '可以在编辑器直接贴图。快捷键:Command C+V', + 'rows' => '5' + )) + ) + ), + formGroup + ( + set('label', array('text' => $lang->files)), + formRow + ( + setClass('items-center'), + h::label + ( + set('for', 'file'), + setClass('btn text-primary canvas'), + icon('plus'), + span($lang->file->addFile) + ), + h::file + ( + setId('file'), + setStyle('display', 'none'), + set('name', 'files'), + ), + span('(不超过50M)') + ) + ), + formGroup + ( + set('label', array('text' => $lang->task->datePlan)), + formRow + ( + setClass('items-center'), + h::date + ( + setClass('form-control w-166'), + set('name', 'estStarted') + ), + span('至'), + h::date + ( + setClass('form-control w-166'), + set('name', 'deadline') + ) + ) + ), + formGroup + ( + set('label', array('text' => $lang->story->mailto)), + select + ( + setClass('w-360'), + set('name', 'mailto[]'), + set('items', array_map(function($v, $k) {return array('text' => $v, 'value' => $k, 'selected' => $k === str_replace(' ', '', $task->mailto));}, $users, array_keys($users))) + ) + ), + formGroup + ( + set('label', array('text' => $lang->task->afterSubmit)), + setClass('items-center'), + setStyle(array('align-items' => 'center')), + formRow + ( + array_map(function($v, $k) {return radio( + set('name', 'after'), + set(array('text' => $v, 'value' => $k, 'checked' => $k === (empty($task->id) ? 'continueAdding' : 'toTaskList'))) + );}, $lang->task->afterChoices, array_keys($lang->task->afterChoices)) + ) + ), + formGroup + ( + formRow + ( + setClass('justify-center'), + btn + ( + set('type', 'submit'), + setClass('primary w-106'), + $lang->save + ), + btn + ( + set('url', 'javascript:history.go(-1)'), + setClass('w-106'), + $lang->goback + ) + ) + ) + ) + ) + ) +); diff --git a/module/task/ui/view.html.php b/module/task/ui/view.html.php new file mode 100644 index 0000000000..7856331cc9 --- /dev/null +++ b/module/task/ui/view.html.php @@ -0,0 +1,11 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/js/zui3/@zentao/icons/ZentaoIcon.ttf b/www/js/zui3/@zentao/icons/ZentaoIcon.ttf new file mode 100644 index 0000000000..a006de2ecc Binary files /dev/null and b/www/js/zui3/@zentao/icons/ZentaoIcon.ttf differ diff --git a/www/js/zui3/@zentao/icons/ZentaoIcon.woff b/www/js/zui3/@zentao/icons/ZentaoIcon.woff new file mode 100644 index 0000000000..202c17aff9 Binary files /dev/null and b/www/js/zui3/@zentao/icons/ZentaoIcon.woff differ diff --git a/www/js/zui3/@zentao/icons/icons.json b/www/js/zui3/@zentao/icons/icons.json new file mode 100644 index 0000000000..a3bb9ff517 --- /dev/null +++ b/www/js/zui3/@zentao/icons/icons.json @@ -0,0 +1 @@ +{"zentao":{"code":"e901"},"zentao-alt":{"code":"e900"},"help":{"code":"e968"},"import":{"code":"e904"},"download":{"code":"e904"},"export":{"code":"e905"},"lightbulb":{"code":"e91c"},"close":{"code":"e936"},"check":{"code":"e5ca"},"plus":{"code":"e925"},"minus":{"code":"e926"},"expand-alt":{"code":"e6f1"},"collapse-alt":{"code":"e6f2"},"fullscreen":{"code":"e96b"},"star-empty":{"code":"e94a"},"star":{"code":"e94b"},"exclamation-sign":{"code":"e930"},"info-sign":{"code":"e9d5"},"flag":{"code":"e937"},"check-circle":{"code":"e92f"},"check-sign":{"code":"e938"},"chart-pie":{"code":"e95b"},"history":{"code":"e95f"},"pencil":{"code":"e254"},"search":{"code":"e928"},"restart":{"code":"e95e"},"cog":{"code":"e93b"},"chart-line":{"code":"e95c"},"chart-bar":{"code":"e95d"},"bar-chart":{"code":"e95d"},"exchange":{"code":"e927"},"severity":{"code":"e973"},"book":{"code":"f02d"},"treemap-alt":{"code":"e971"},"severity-solid":{"code":"e902"},"chat-line":{"code":"e998"},"stack":{"code":"e943"},"cube":{"code":"e967"},"minus-sign":{"code":"e939"},"bars-sign":{"code":"e93a"},"chat":{"code":"e940"},"message":{"code":"e940"},"more":{"code":"e744"},"certificate":{"code":"f0a3"},"bell":{"code":"e7f5"},"columns":{"code":"f0db"},"envelope-o":{"code":"e92a"},"unfold-all":{"code":"e931"},"fold-all":{"code":"e932"},"bars":{"code":"e948"},"cards-view":{"code":"e949"},"ellipsis-v":{"code":"e5d4"},"spinner-indicator":{"code":"e982"},"up-circle":{"code":"e92b"},"right-circle":{"code":"e92c"},"down-circle":{"code":"e92d"},"left-circle":{"code":"e92e"},"angle-double-right":{"code":"f101"},"angle-down":{"code":"e313"},"angle-left":{"code":"e314"},"angle-right":{"code":"e315"},"angle-top":{"code":"e316"},"first-page":{"code":"e5dc"},"last-page":{"code":"e5dd"},"caret-down":{"code":"f0d7"},"caret-up":{"code":"f0d8"},"caret-left":{"code":"f0d9"},"caret-right":{"code":"f0da"},"sort":{"code":"f0dc"},"sort-down":{"code":"f0dd"},"sort-up":{"code":"f0de"},"arrow-up":{"code":"e923"},"arrow-down":{"code":"e924"},"arrow-left":{"code":"e952"},"arrow-right":{"code":"e93e"},"chevron-left":{"code":"e934"},"chevron-right":{"code":"e935"},"chevron-double-up":{"code":"e959"},"chevron-double-down":{"code":"e95a"},"folder-account":{"code":"e942"},"folder-move":{"code":"e960"},"folder-plus":{"code":"e961"},"folder-upload":{"code":"e962"},"folder-star":{"code":"e963"},"folder-edit":{"code":"e964"},"folder-download":{"code":"e965"},"folder-outline":{"code":"e966"},"folder":{"code":"e944"},"folder-o":{"code":"e945"},"folder-open-o":{"code":"e946"},"folder-open":{"code":"e947"},"color":{"code":"e93c"},"paper-clip":{"code":"e93d"},"text":{"code":"e929"},"share":{"code":"f064"},"format-list-bulleted":{"code":"e9a8"},"format-bold":{"code":"e953"},"format-header-pound":{"code":"e954"},"format-italic":{"code":"e955"},"format-list-numbers":{"code":"e969"},"format-quote-close":{"code":"e96a"},"image":{"code":"e96c"},"table-large":{"code":"e96d"},"aiux":{"code":"e99e"},"qc":{"code":"e986"},"qc-q":{"code":"e985"},"qc-c":{"code":"e987"},"sonarqube":{"code":"e9ba"},"college":{"code":"e9c8"},"ztool":{"code":"e9c1"},"contacts":{"code":"e9c3"},"chats":{"code":"e9c4"},"menu-my":{"code":"e97a"},"home":{"code":"e97a"},"program":{"code":"e9aa"},"lightbulb-alt":{"code":"e98f"},"product":{"code":"e98f"},"rocket":{"code":"e99c"},"project":{"code":"e99c"},"run":{"code":"e9a9"},"test":{"code":"e956"},"infinite":{"code":"e9a3"},"devops":{"code":"e9a3"},"ops":{"code":"e903"},"doc":{"code":"e99b"},"menu-doc":{"code":"e99b"},"statistic":{"code":"e999"},"menu-backend":{"code":"e993"},"assets":{"code":"e9ae"},"diamond":{"code":"e9ae"},"feedback":{"code":"e991"},"flow":{"code":"e994"},"oa":{"code":"e9a1"},"more-circle":{"code":"e988"},"controls":{"code":"e995"},"account":{"code":"e992"},"about":{"code":"e996"},"info":{"code":"e996"},"cog-outline":{"code":"e997"},"backend":{"code":"e997"},"exit":{"code":"e99a"},"theme":{"code":"e9a0"},"globe":{"code":"f0ac"},"lang":{"code":"f0ac"},"table-sort":{"code":"e9e1"},"blame":{"code":"e9e0"},"draft-edit":{"code":"e9dd"},"sub-review-user":{"code":"e9db"},"sub-review":{"code":"e9df"},"ztf":{"code":"e9dc"},"save":{"code":"e9d8"},"list-box":{"code":"e9b4"},"usecase":{"code":"e99d"},"code":{"code":"e990"},"summary":{"code":"e9ad"},"more-alt":{"code":"e9a7"},"customer":{"code":"e9d9"},"ticket":{"code":"e9e1"},"gantt-alt":{"code":"e9e2"},"appose":{"code":"e9e2"},"inline":{"code":"e9e3"},"tree":{"code":"e9c9"},"list":{"code":"e9cb"},"gantt":{"code":"e9cc"},"group-view":{"code":"e9cd"},"inherit-space":{"code":"e9c2"},"card-archive":{"code":"e9b8"},"col-archive":{"code":"e9b9"},"col-add-right":{"code":"e9bb"},"col-add-left":{"code":"e9bc"},"col-split":{"code":"e9bd"},"waterfall":{"code":"e9a4"},"manual":{"code":"e98d"},"kanban":{"code":"e983"},"lane":{"code":"e9b1"},"back":{"code":"e9d3"},"back-circle":{"code":"e9da"},"shield":{"code":"e9ca"},"meh":{"code":"e9ce"},"frown":{"code":"e9cf"},"smile":{"code":"e9d0"},"unlock-solid":{"code":"e9d1"},"lock-solid":{"code":"e9d2"},"ver":{"code":"e9c6"},"publish":{"code":"e9c7"},"send":{"code":"e9c7"},"tag":{"code":"e9be"},"tag-lock":{"code":"e9bf"},"code-fork":{"code":"f126"},"branch-lock":{"code":"e9c0"},"groups":{"code":"e9af"},"thumbs-up":{"code":"f087"},"thumbs-down":{"code":"f088"},"thumbs-up-solid":{"code":"e9d6"},"thumbs-down-solid":{"code":"e9d7"},"hash":{"code":"e9ab"},"version":{"code":"e9ab"},"p-square":{"code":"e97b"},"video-play":{"code":"e97f"},"plus-solid-circle":{"code":"e974"},"minuse-solid-circle":{"code":"e9b6"},"s":{"code":"e975"},"c":{"code":"e976"},"t":{"code":"e977"},"guide":{"code":"e978"},"todo":{"code":"e979"},"side-left":{"code":"e9b3"},"side-right":{"code":"e9b2"},"fullscreen-exit":{"code":"e972"},"alert":{"code":"e99f"},"undo":{"code":"e93f"},"redo":{"code":"e9d4"},"swap":{"code":"e9b0"},"chat-solid":{"code":"e9b5"},"clock":{"code":"e97c"},"cost":{"code":"e97d"},"pencil-alt":{"code":"e984"},"size-height":{"code":"e9c5"},"file-log":{"code":"e9de"},"rich-text":{"code":"e913"},"markdown":{"code":"e916"},"excel":{"code":"e933"},"text-link":{"code":"e94d"},"ppt":{"code":"e957"},"word":{"code":"e958"},"doc-lib":{"code":"e96f"},"file":{"code":"f016"},"file-empty":{"code":"f016"},"file-text":{"code":"f0f6"},"file-alt":{"code":"f15b"},"file-text-alt":{"code":"f15c"},"file-pdf":{"code":"f1c1"},"file-word":{"code":"f1c2"},"file-excel":{"code":"f1c3"},"file-powerpoint":{"code":"f1c4"},"file-image":{"code":"f1c5"},"file-archive":{"code":"f1c6"},"file-audio":{"code":"f1c7"},"file-video":{"code":"f1c8"},"file-code":{"code":"f1c9"},"menu-collapse":{"code":"e980"},"menu-expand":{"code":"e981"},"group":{"code":"e97e"},"menu-users":{"code":"e97e"},"persons":{"code":"e97e"},"team":{"code":"e97e"},"estimate":{"code":"e9ac"},"sprint":{"code":"e9a2"},"shield-check":{"code":"e9a5"},"ok":{"code":"e9a6"},"printer":{"code":"e906"},"bullhorn":{"code":"e910"},"person":{"code":"e941"},"fields":{"code":"e989"},"trigger":{"code":"e98a"},"layout":{"code":"e98b"},"audit":{"code":"e98c"},"cancel":{"code":"e951"},"ban-circle":{"code":"e951"},"eye":{"code":"e94e"},"eye-off":{"code":"e96e"},"unlock":{"code":"e94f"},"lock":{"code":"e950"},"private":{"code":"e950"},"move":{"code":"e94c"},"hand-right":{"code":"e907"},"checked":{"code":"e908"},"off":{"code":"e909"},"start":{"code":"e90a"},"play":{"code":"e90a"},"time":{"code":"e90b"},"edit":{"code":"e90c"},"trash":{"code":"e90d"},"link":{"code":"e90e"},"unlink":{"code":"e90f"},"bug":{"code":"e911"},"list-alt":{"code":"e912"},"change":{"code":"e970"},"alter":{"code":"e970"},"glasses":{"code":"e914"},"review":{"code":"e914"},"sitemap":{"code":"e915"},"testcase":{"code":"e915"},"pluses":{"code":"e917"},"report-list":{"code":"e918"},"magic":{"code":"e919"},"active":{"code":"e919"},"treemap":{"code":"e91a"},"confirm":{"code":"e91b"},"split":{"code":"e98e"},"delay":{"code":"e91d"},"calendar":{"code":"e91d"},"pause":{"code":"e91e"},"ban":{"code":"e91f"},"plus-bold":{"code":"e920"},"copy":{"code":"e921"},"refresh":{"code":"e922"},"diff":{"code":"e9b7"},"scrum":{"code": "e9a2"}} diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js new file mode 100644 index 0000000000..b7a78691fc --- /dev/null +++ b/www/js/zui3/zin.js @@ -0,0 +1,484 @@ +(function(){ + let DEBUG = true; + const currentCode = window.name.substring(4); + const isInAppTab = parent.window !== window; + const fetchTasks = new Map(); + let currentAppUrl = ''; + + $.apps = $.extend( + { + currentCode: currentCode, + updateApp: function(code, url, title) + { + const state = typeof code === 'object' ? code : {url: url, title: title}; + const oldState = window.history.state; + + if(title) document.title = title; + + if(oldState && oldState.url === url) return; + + window.history.pushState(state, title, url); + if(DEBUG) console.log('[APP]', 'update:', {code, url, title}); + }, + reloadApp: function(code, url) + { + loadPage(url); + } + }, parent.window.$.apps); + + const renderMap = + { + html: updatePageWithHtml, + body: (data) => $('body').html(data), + title: (data) => document.title = data, + 'main': (data) => $('#main').html(data), + 'featureBar': (data) => $('#featureBar').html(data), + 'pageCSS': (data) => $('#pageCSS').html(data), + 'configJS': (data) => $('#configJS')[0].text = data, + 'pageJS': (data) => $('#pageJS').replaceWith(data), + activeFeature: (data) => activeNav(data, '#featureBar'), + activeMenu: activeNav, + table: updateTable, + zinErrors: showZinErrors + }; + + function showZinErrors(data) + { + if(DEBUG && Array.isArray(data) && data.length) console.log('[ZIN] errors:', data); + } + + function updatePageWithHtml(data) + { + const html = []; + const skipTags = new Set(['SCRIPT', 'META']); + $(data).each(function(idx, node) + { + const nodeName = node.nodeName; + if(nodeName === '#text') html.push(node.textContent); + else if(nodeName === 'SCRIPT' && node.innerText.startsWith('window.config={')) html.push(node.outerHTML); + else if(nodeName === 'TITLE') document.title = node.innerText; + else if(skipTags.has(nodeName)) return; + else html.push(node.outerHTML); + }); + $('body').html(html.join('')); + window.zin = {config: window.config}; + if(DEBUG) console.log('[ZIN] ', window.zin); + if(DEBUG) zui.Messager.show({content: 'ZIN: load an old page.', close: false}); + } + + function activeNav(activeID, nav) + { + const $nav = $(nav || '#navbar'); + const $active = $nav.find('.nav-item>a.active'); + if($active.data('id') === activeID) return; + $active.removeClass('active'); + $nav.find('.nav-item>a[data-id="' + activeID + '"]').addClass('active'); + } + + function updateTable(data) + { + const props = data.props; + const $table = $('#' + props.id).parent(); + if(!$table.length) return; + const dtable = zui.DTable.get($table[0]); + Object.keys(props).forEach(prop => + { + const value = props[prop]; + if(typeof value === 'string' && value.startsWith('RAWJS<')) delete props[prop]; + }); + if(DEBUG) console.log('[APP] ', 'update table:', {data, props}); + dtable.render(props); + } + + function renderPartial(info) + { + if(window.config.onRenderPage && window.config.onRenderPage(info)) return; + + const render = renderMap[info.name]; + if(render) return render(info.data); + + /* Common render */ + const selector = parseSelector(info.selector); + if(!selector) return console.warn('[APP] ', 'cannot render partial content with data', info); + + const $target = $(selector.select); + if(!$target.length) return console.warn('[APP] ', 'cannot find target element with selector', selector); + if(selector.first) $target = $target.first(); + if(selector.type === 'json') + { + const props = info.data.props; + if(typeof props === 'object') + { + const targetData = $target.data(); + const zuiComName = Object.keys(targetData).find(prop => prop.startsWith('zui.')); + if(zuiComName) + { + const zuiCom = targetData[zuiComName]; + if(typeof zuiCom === 'object' && typeof zuiCom.render === 'function') + { + Object.keys(props).forEach(prop => + { + const value = props[prop]; + if(typeof value === 'string' && value.startsWith('RAWJS<')) delete props[prop]; + }); + zuiCom.render(props); + } + } + } + return; + } + + if(selector.inner) $target.html(info.data); + else $target.replaceWith(info.data); + } + + function renderPage(list) + { + if(DEBUG) console.log('[APP] ', 'render:', list); + list.forEach(renderPartial); + $.apps.updateApp(currentCode, currentAppUrl, document.title); + } + + function toggleLoading(target, isLoading) + { + const $target = $(target); + const position = $target.css('position'); + if(!['relative', 'absolute', 'fixed'].includes(position)) $target.css('position', 'relative'); + if(!$target.hasClass('load-indicator')) + { + $target.addClass('load-indicator'); + setTimeout(toggleLoading.bind(null, target, isLoading), 100); + return; + } + if(isLoading === undefined) isLoading = !$target.hasClass('loading'); + $target.toggleClass('loading', isLoading); + } + + /** + * Request data from remote server + * @param {Object} options + * @param {string} options.id + * @param {string} options.url + * @param {string} options.selectors + * @param {string} [options.target] + * @param {{selector: string, type: string}} [options.zinOptions] + * @param {function} [options.success] + * @param {function} [options.error] + * @param {function} [options.complete] + * @param {function} [onFinish] + */ + function requestContent(options, onFinish) + { + const target = options.target || '#main'; + const selectors = Array.isArray(options.selectors) ? options.selectors : options.selectors.split(','); + const url = options.url; + return $.ajax( + { + url: url, + headers: {'X-ZIN-Options': JSON.stringify($.extend({selector: selectors, type: 'list'}, options.zinOptions)), 'X-ZIN-App': currentCode}, + beforeSend: () => toggleLoading(target, true), + success: (data) => + { + try{data = JSON.parse(data);}catch(e){data = [{name: 'html', data: data}];} + if(options.updateUrl !== false) currentAppUrl = url; + data.forEach((item, idx) => item.selector = selectors[idx]); + renderPage(data); + $(document).trigger('pagerender.app'); + if(options.success) options.success(data); + if(onFinish) onFinish(null, data); + }, + error: (xhr, type, error) => + { + if(type === 'abort') return console.log('[ZIN] ', 'Abord fetch data from ' + url, {xhr, type, error});; + if(DEBUG) console.error('[ZIN] ', 'Fetch data failed from ' + url, {xhr, type, error}); + zui.Messager.show('ZIN: Fetch data failed from ' + url); + if(options.error) options.error(data); + if(onFinish) onFinish(error); + }, + complete: () => + { + toggleLoading(target, false); + if(options.complete) options.complete(); + $(document).trigger('pageload.app'); + } + }); + } + + function fetchContent(url, selectors, options) + { + if(typeof url === 'object') + { + options = url; + url = options.url; + selectors = options.selectors; + } + if(typeof options === 'string') options = {id: options}; + else if(typeof options === 'function') options = {success: options}; + + selectors = Array.isArray(selectors) ? selectors.join(',') : selectors; + const id = options.id || selectors; + options = $.extend({}, options, {url: url, selectors: selectors, id: id}); + + const task = fetchTasks.get(id) || {url: url, selectors: selectors, options: options}; + if(task.xhr) + { + if(task.url === url) return; + task.xhr.abort(); + task.xhr = null; + } + fetchTasks.set(id, task); + if(task.timerID) clearTimeout(task.timerID); + task.timerID = setTimeout(() => + { + task.timerID = 0; + task.xhr = requestContent(options, () => + { + task.xhr = null; + fetchTasks.delete(id); + }); + }, options.delayTime || 0); + } + + function loadTable(url, id) + { + url = url || currentAppUrl; + id = id || $('.dtable').attr('id') || 'dtable'; + if(!id) return; + + fetchContent(url, 'table/#' + id + ':type=json&data=props,#featureBar>*', {id: '#' + id, target: '#' + id}); + } + + function loadPage(url, selector, id) + { + url = url || currentAppUrl; + if (!selector && url.includes(' ')) { + const parts = url.split(' ', 2); + url = parts[0]; + selector = parts[1]; + } + if(DEBUG) console.log('[APP] ', 'load:', url); + id = id || selector || 'page'; + if(!selector) + { + selector = ($('#main').length ? '#main>*,#pageCSS>*,#pageJS,#configJS>*,title>*,activeMenu()' : 'body>*,title>*'); + if(DEBUG) selector += ',zinErrors()'; + } + fetchContent(url, selector, id); + } + + function loadCurrentPage(selector) + { + return loadPage(currentAppUrl, selector); + } + + function openPage(url, appCode) + { + if(DEBUG) console.log('[APP] ', 'open:', url); + if(!window.config.zin) + { + location.href = $.createLink('index', 'app', 'url=' + btoa(url)); + return; + } + $.apps.reloadApp(appCode || currentAppUrl, url); + } + + function onRenderPage(callback) + { + window.config.onRenderPage = callback; + } + + /** + * Parse wg selector + * @param {string} selector + * @return {object|null} + */ + function parseSelector(selector) + { + selector = selector.trim(); + let len = selector.length; + + if(len < 1) return null; + + const result = {class: [], id: '', tag: '', inner: false, name: '', first: false, selector: selector}; + if(selector.includes('/')) + { + const parts = selector.split('/', 2); + result.name = parts[0]; + selector = parts[1]; + len = selector.length; + } + selector = selector.replace('> *', '>*'); + if(selector.endsWith('>*')) + { + result.inner = true; + selector = selector.substring(0, selector.length - 2); + len = selector.length; + } + + let type = 'tag'; + let current = ''; + let updateResult = function(result, current, type) + { + if(!current.length) return; + + if(type === 'class') + { + result[type].push(current); + } + else if(type === 'option') + { + current.split('&').forEach(function(option) + { + const parts = option.split('='); + result[parts[0]] = parts[1] || true; + }); + } + else + { + result[type] = current; + } + }; + + for(let i = 0; i < len; i++) + { + let c = selector[i]; + let t = ''; + + if(c === '#' && type !== 'option') + { + t = 'id'; + } + else if(c === '.' && type !== 'option') + { + t = 'class'; + } + else if(c === '(' && type !== 'option' && selector.endsWith(')')) + { + let command = selector.substring(i + 1, selector.length - 1); + if(!command) command = current; + result.command = command; + break; + } + else if(c === ':') + { + t = 'option'; + } + + if(!t) + { + current += c; + } + else + { + updateResult(result, current, type); + current = ''; + type = t; + } + } + updateResult(result, current, type); + + if(!result.name.length) + { + if(result.id.length) result.name = result.id; + else if(result.tag) result.name = result.tag; + else result.name = selector; + } + result.select = [result.tag, result.id.length ? '#' + result.id : '', result.class.length ? '.' + result.class.join('.') : ''].join(''); + + return result; + } + + $.extend(window, {fetchContent: fetchContent, loadTable: loadTable, loadPage: loadPage, loadCurrentPage: loadCurrentPage, parseSelector: parseSelector, onRenderPage: onRenderPage, toggleLoading: toggleLoading}); + + /* Transfer click event to parent */ + $(document).on('click', (e) => + { + if(isInAppTab) window.parent.$('body').trigger('click'); + + const $a = $(e.target).closest('a'); + if(!$a.length || $a.attr('target') === '_blank') return; + if($a.data('toggle') || $a.hasClass('not-in-app')) return e.preventDefault(); + + const url = $a.attr('href'); + if(!url || url.startsWith('javascript') || url.startsWith('#')) return; + + const loadTarget = $a.data('load'); + if(loadTarget === 'table') loadTable(url); + else openPage(url); + e.preventDefault(); + }).on('zui.locate', (e, data) => + { + if(!data) return; + if(typeof data === 'string') data = {url: data}; + loadPage(data.url, data.selector); + }); + + if(!isInAppTab) + { + $(window).on('popstate', function(event) + { + const state = event.state; + if(DEBUG) console.log('[APP]', 'popstate:', state); + openPage(state.url); + }); + } + + $(() => + { + if(window.defaultAppUrl) loadPage(window.defaultAppUrl); + + DEBUG = window.config.debug; + + /* Compatible with old version */ + if(DEBUG && typeof window.zin !== 'object' && isInAppTab) + { + console.log('[ZUI3]', 'Compatible with old version'); + window.jQuery = $; + const empty = () => {}; + window.adjustMenuWidth = empty; + window.startCron = empty; + $.zui = $.extend(function(){console.warn('[ZUI3]', 'The $.zui() is not supported.');}, zui); + $.initSidebar = empty; + parent.window.$.apps.openedApps = $.apps.openedApps = $.apps.openedMap; + parent.window.$.apps.updateUrl = $.apps.updateUrl = empty; + const ajaxOld = $.ajax; + window.createLink = $.createLink; + window.parseLink = $.parseLink; + $.ajax = function(url, settings) + { + ajaxOld.call(this, url, settings); + const deffered = {}; + const ajaxWarn = function(name) + { + console.warn('[ZUI3]', 'The $.ajax().' + name + '() is not supported.'); + return deffered; + }; + $.extend(deffered, {done: ajaxWarn.bind(deffered, 'done'), fail: ajaxWarn.bind(deffered, 'fail'), always: ajaxWarn.bind(deffered, 'always')}); + return deffered; + }; + $.extend($.fn, + { + sortable: function() + { + console.warn('[ZUI3]', 'The $().sortable() is not supported.'); + return this; + }, + scroll: function() + { + console.warn('[ZUI3]', 'The $().scroll() is not supported.'); + return this; + }, + resize: function() + { + console.warn('[ZUI3]', 'The $().resize() is not supported.'); + return this; + }, + table: function() + { + console.warn('[ZUI3]', 'The $().table() is not supported.'); + return this; + }, + }); + } + }); +}()); diff --git a/www/js/zui3/zintool.js b/www/js/zui3/zintool.js new file mode 100644 index 0000000000..0e4c9e428e --- /dev/null +++ b/www/js/zui3/zintool.js @@ -0,0 +1,602 @@ +/** + * @typedef {'list'|'form'|'detail'} ZinPageLayout + */ + +/** + * @typedef {Object} ZinItemProps + * @property {string} type + * @property {string} text + * @property {string} icon + */ + +/** + * @typedef {Object} ZinFeatureBar + * @property {ZinItemProps[]} [items] + * @property {string} [current] + * @property {string} [linkParams] + */ + +/** + * @typedef {Object} ZinDtableProps + * @property {Object[]} [cols] + * @property {Object[]} [data] + * @property {string[]} [plugins] + * @property {boolean} [footPager] + * @property {{items: Object[]}} [footToolbar] + * @property {string[]} [footer] + */ + +/** + * @typedef {Object} ZinPageInfo + * @property {string} url + * @property {string} title + * @property {ZinPageLayout} layout + * @property {string} moduleName + * @property {string} methodName + * @property {ZinFeatureBar} featureBar + * @property {ZinItemProps[]} toolbar + * @property {ZinDtableProps} dtable + * @property {boolean} tableCustomCols + * @property {{type: string}} sidebar + */ + +function getIconName(iconClass) +{ + const names = iconClass.split(' '); + const excludeSet = new Set(['sm', 'lg', '2x', '3x', '4x', 'xs', 'xl']); + for(const name of names) + { + if(!name.length || !name.startsWith('icon-') || name.startsWith('icon-common-')) continue; + const icon = name.replace('icon-', ''); + if(excludeSet.has(icon)) continue; + return icon; + } + return ''; +} + +function convertClassName(className, exclude = 'dropdown-toggle') +{ + const excludeSet = new Set(exclude.split(' ')); + return className.split(' ').reduce((list, name) => + { + if(!name.length || excludeSet.has(name)) return list; + if(name.endsWith('-primary')) list.push('primary'); + else if(name.endsWith('-secondary')) list.push('secondary'); + else if(name.endsWith('-warning')) list.push('warning'); + else if(name.endsWith('-success')) list.push('success'); + else if(name.endsWith('-danger')) list.push('danger'); + else if(name === 'btn-link') list.push('ghost'); + else list.push(name); + return list; + }, []).join(' '); +} + +function getZinItemProps($item, props) +{ + if($item.hasClass('dropdown-menu')) return; + if($item.is('.btn-group,.dropdown')) + { + const items = []; + $item.children().each(function() + { + if($(this).hasClass('dropdown-menu')) return; + items.push(getZinItemProps($(this))); + }); + return {type: 'btnGroup', items, ...props}; + } + const $icon = $item.find('.icon,i'); + const item = { + icon: $icon.length ? getIconName($icon.attr('class')) : undefined, + text: $item.text().trim(), + class: convertClassName($item.attr('class'), 'btn'), + ...props + }; + if($item.data('toggle') === 'dropdown') + { + item.type = 'dropdown'; + item.items = []; + const $menu = $item.next('.dropdown-menu'); + if($menu.length) + { + const $listGroup = $menu.children('.list-group'); + if($listGroup.length) + { + $listGroup.children('a').each(function() + { + item.items.push($(this).text().trim()); + }); + } + else + { + $menu.children('li').each(function() + { + item.items.push($(this).text().trim()); + }); + } + } + } + return item; +} + +/** + * Get page info for zin + * @param {Window} win + * @returns {ZinPageInfo} + */ +function getPageInfo(win) +{ + const {document, config, $} = win; + const info = + { + url: win.location.href, + title: document.title.replace(' - 禅道', ''), + moduleName: config.currentModule, + methodName: config.currentMethod, + }; + + const $featureBar = $('#mainMenu .btn-toolbar.pull-left,#mainMenu .btn-toolBar.pull-left'); + if($featureBar.length) + { + const featureBar = {items: []}; + $featureBar.children().each(function() + { + const $this = $(this); + const id = $this.attr('id') || ''; + if($this.is('.querybox-toggle')) + { + featureBar.items.push({type: 'searchToggle'}); + return; + } + + if($this.is('.checkbox-primary')) + { + featureBar.items.push({type: 'checkbox', text: $this.find('label').text().trim() || $this.text().trim()}); + return; + } + if($this.is('a.btn')) + { + if($this.hasClass('btn-active-text')) featureBar.current = id ? id.replace('Tab', '') : ($this.find('.text').text().trim() || $this.text().trim()); + return; + } + }); + info.featureBar = featureBar; + } + + const $toolbar = $('#mainMenu .btn-toolbar.pull-right'); + if($toolbar.length) + { + const toolbar = []; + $toolbar.children().each(function() + { + toolbar.push(getZinItemProps($(this))); + }); + if(toolbar.length) info.toolbar = toolbar; + } + + const $table = $('#mainContent .table').first(); + if($table.length) + { + if($('#mainContent .datatable').length) + { + return alert('zin: Please switch the table to simple table mode'); + } + const colTypesMap = + { + name: 'link', + pri: 'pri', + id: 'id', + status: 'status', + actions: 'actions', + progress: 'circleProgress', + assignedTo: 'avatarBtn', + }; + const getColName = ($cell) => ($cell.attr('class').toLowerCase().split(' ').find(x => x.startsWith('c-')) || '').replace('c-', ''); + /** + * @type {ZinDtableProps} + */ + const setting = {cols: [], data: [], plugins: [], footer: []}; + let flexed = false; + $table.find('thead>tr:first>th').each(function() + { + const $this = $(this); + const data = $this.data(); + const title = $this.attr('title') || $this.text().trim(); + const name = getColName($this) || title; + if(!flexed && data.flex) flexed = true; + const col = + { + title, + name, + width: data.width.endsWith('px') ? Number.parseInt(data.width, 10) : 200, + flex: data.width === 'auto' ? 1 : 0, + fixed: data.flex ? false : (flexed ? 'right' : 'left'), + type: colTypesMap[name], + sortType: !!$this.find('a.sort-up,a.sort-down,a.header').length + }; + setting.cols.push(col); + }); + + $table.find('tbody>tr').each(function(idx) + { + const $this = $(this); + const rowData = $this.data(); + $this.children('td').each(function() + { + $td = $(this); + const name = getColName($td); + if(name && rowData[name] === undefined) + { + rowData[name] = $td.text().trim(); + if(name === 'progress' && rowData[name]) rowData[name] = rowData[name].replace('%', 0); + } + }); + if(rowData.id === undefined) rowData.id = idx; + rowData.id = String(rowData.id); + setting.data.push(rowData); + }); + + const tableJs = $('#mainContent [data-ride="table"]').data('zui.table'); + if(tableJs) + { + if(tableJs.options.checkable) setting.plugins.push('checkable'); + if(tableJs.options.sortable) setting.plugins.push('sortable'); + if(tableJs.options.nested || $table.find('tbody>tr.table-parent,tbody>tr.has-child').length) setting.plugins.push('nested'); + } + else + { + if($table.find('td .checkbox-primary').length) setting.plugins.push('checkable'); + if($table.hasClass('has-sort-head')) setting.plugins.push('sortable'); + if($table.find('tbody>tr.table-parent,tbody>tr.has-child').length) setting.plugins.push('nested'); + } + if(setting.plugins.includes('checkable')) + { + const idCol = setting.cols.find(x => x.name === 'id'); + if(idCol) idCol.checkbox = true; + } + if(setting.plugins.includes('nested') && !setting.cols.find(x => x.nestedToggle)) + { + const nameCol = setting.cols.find(x => x.name === 'name'); + if(nameCol) nameCol.nestedToggle = true; + } + + const $footer = $('#mainContent .table-footer'); + if($footer.length) + { + if(setting.plugins.includes('checkable')) setting.footer.push('checkbox', 'divider'); + + const $actions = $footer.find('.table-actions,.btn-toolbar'); + if($actions.length) + { + const actions = []; + $actions.children().each(function() + { + actions.push(getZinItemProps($(this))); + }); + if(actions.length) setting.footer.push('toolbar'); + setting.footToolbar = {items: actions.filter(Boolean)}; + setting.footer.push('toolbar'); + } + + const $statistic = $footer.find('.table-statistic'); + if($statistic.length) setting.footer.push($statistic.text().trim()); + + const $pager = $footer.find('.pager'); + if($pager.length) + { + setting.footer.push('flex', 'pager'); + setting.footPager = true; + } + } + + info.dtable = setting; + info.layout = 'list'; + info.sidebar = $('#sidebar').length ? {type: 'moduleTree'} : undefined; + + if($('#tableCustomBtn').length) info.tableCustomCols = true; + } + + return info; +} + +/** + * Indent string lines + * @param {string[]|string} lines + * @param {number} [indent=0] + * @returns {string[]|string} + */ +function indentLines(lines, indent = 0) +{ + const isArray = Array.isArray(lines); + if(!isArray) lines = lines.split('\n'); + const indentStr = ' '.repeat(indent * 4); + lines = lines.map(x => x.includes('\n') ? indentLines(x, indent) : (indentStr + x)); + return isArray ? lines : lines.join('\n'); +} + +/** + * Generate item statement + * @param {ZinItemProps} name + * @param {any} value + * @param {number} [indent=0] + * @returns {string} + */ +function genSetStatement(name, value, indent = 0) +{ + return indentLines(`set::${name}(${JSON.stringify(value)})`, indent); +} + +/** + * Gen value to php statement + * @param {any} value + * @param {number} indent + * @returns {string} + */ +function genValueStatement(value, indent = 0, join = '\n') +{ + if(value === undefined) return; + if(value === null) return indentLines('NULL', indent); + if(Array.isArray(value)) + { + return indentLines(`array(${value.map(val => genValueStatement(val, indent, join)).join(', ')})`, indent); + } + if(typeof value === 'object') + { + return genArrayStatement(value, null, indent, '', '', join); + } + return indentLines(JSON.stringify(value), indent); +} + +/** + * Generate php array statement + * @param {Reacord} array Php array object + * @param {string|string[]} props Prop names list + * @param {number} [indent=0] + * @returns {string} + */ +function genArrayStatement(array, props = null, indent = 0, prefix = '', suffix = '', join = '\n') +{ + if(typeof props === 'string') props = props.split(','); + else if(props === null) props = Object.keys(array); + const propLines = props.reduce((lines, prop) => + { + const value = genValueStatement(array[prop], 0, join); + if(typeof value === 'string' && value.length) + { + lines.push(`'${prop}' => ${value}`); + } + return lines; + }, []); + if(!propLines.length) return [indentLines('array()', indent)]; + return indentLines( + [ + `${prefix}array`, + '(', + indentLines(propLines.join(`,${join === '' ? ' ' : join}`), join === '' ? 0 : (1 + indent)), + `)${suffix}` + ], indent).join(join); +} + +/** + * Generate item statement + * @param {ZinItemProps} item + * @param {number} [indent=0] + * @returns {string} + */ +function genItemStatement(item, indent = 0) +{ + if(item.type === 'searchToggle') return indentLines('li(searchToggle())', indent); + return genArrayStatement(item, null, indent, 'item(set(', '))'); +} + +/** + * Generate php variable statement + * @param {string} name + * @param {any} value + * @param {number} indent + * @param {string} join + */ +function genVarStatement(name, value, indent = 0, join = '') +{ + return indentLines(`$${name} = ${genValueStatement(value, indent, join)};`, indent); +} + +/** + * Get page template + * @param {ZinPageInfo} info + * @returns {string} + */ +function getPageTemplate(info) +{ + /** @type {string[]} */ + const lines = []; + + const {featureBar, toolbar, dtable} = info; + const variables = []; + const widgets = []; + if(featureBar && featureBar.current) + { + lines.push + ( + '/* zin: Set variable $browseType to store the current active item in feature bar */', + `${genVarStatement('browseType', featureBar.current)} // the variable may already defined in control method`, + '' + ); + } + + if(dtable) + { + lines.push('/* zin: Set variables to define columns and rows data for dtable */'); + lines.push(genVarStatement('dtableCols', dtable.cols)); + lines.push(genVarStatement('dtableRows', dtable.data)); + variables.push('dtableCols', 'dtableRows'); + + if(dtable.footToolbar) + { + variables.push('dtableToolbar'); + lines.push(genVarStatement('dtableToolbar', dtable.footToolbar)); + } + } + + lines.push('\n\n/* ====== Define the page structure with zin widgets ====== */\n'); + + if(featureBar) + { + widgets.push('featureBar'); + lines.push + ( + '/* zin: Define the feature bar on main menu */', + 'featureBar', + '(', + indentLines([ + featureBar.current ? 'set::current($browseType)' : null, + featureBar.linkParams ? `set::linkParams(${JSON.stringify(featureBar.linkParams)}),` : null, + ...featureBar.items.map(item => genItemStatement(item)) + ].filter(x => typeof x === 'string'), 1).join(',\n'), + ');', + '' + ); + } + + if(toolbar && toolbar.length) + { + lines.push + ( + '/* zin: Define the toolbar on main menu */', + 'toolbar', + '(', + indentLines(toolbar.map(item => genItemStatement(item)).filter(x => typeof x === 'string'), 1).join(',\n'), + ');', + '' + ); + } + + if(info.sidebar) + { + widgets.push('sidebar'); + lines.push + ( + '/* zin: Define the sidebar in main content */', + '/* sidebar', + '(', + genSetStatement('type', info.sidebar.type, 1), + '); */ // Sidebar is not work yet', + '' + ); + } + + if(dtable) + { + widgets.push('dtable'); + lines.push + ( + '/* zin: Define the dtable in main content */', + 'dtable', + '(', + indentLines( + [ + "set::className('shadow rounded')", + 'set::cols($dtableCols)', + 'set::data($dtableRows)', + dtable.plugins ? `set::plugins(array(${dtable.plugins.map(x => JSON.stringify(x)).join(', ')}))` : null, + (dtable.plugins && dtable.plugins.includes('checkable')) ? 'set::checkable(true)' : null, + (dtable.plugins && dtable.plugins.includes('nested')) ? 'set::nested(true)' : null, + dtable.footToolbar ? 'set::toolbar($dtableToolbar)' : null, + dtable.footPager ? 'set::footPager(usePager())' : null, + dtable.footer ? `set::footer(array(${dtable.footer.map(x => JSON.stringify(x)).join(', ')}))` : null, + ].filter(x => typeof x === 'string'), 1).join(',\n'), + ');', + '' + ); + } + + lines.push + ( + '\n/* ====== Render page ====== */\n', + 'render();' + ); + + lines.unshift( + ' `$${x}`).join(', ')}.` : null, + featureBar.items && featureBar.items.length ? ` + Check the ${featureBar.items.length.length} items difinition in featureBar widget.` : null, + toolbar && toolbar.length ? ` + Check the ${toolbar.length} items difinition in toolbar widget.` : null, + ` + Check the origin code in module/${info.moduleName}/view/${info.methodName}.html.php, and ensure that all features have been implemented.`, + ` + Check the origin js code in module/${info.moduleName}/js/common.js and module/${info.moduleName}/js/${info.methodName}.js`, + ` + Check the origin css code in module/${info.moduleName}/css/common.css and module/${info.moduleName}/css/${info.methodName}.css`, + ' + Remove the comments which starts with "zin:"', + ' + Test according to the new design draft and the original implementation', + ' */', + '', + 'namespace zin;', + '', + '/* ====== Preparing and processing page data ====== */', + '', + ); + + return lines.filter(x => typeof x === 'string').join('\n'); +} + +function zin(win) +{ + win = win || window; + + if(!win.config) return $.zui.messager.danger('zin: Current page is not supported yet, may be it rendered by zin already!'); + + const pageInfo = getPageInfo(win); + if(!pageInfo) return $.zui.messager.danger('zin: Current page is not supported temporarily.'); + + const template = getPageTemplate(pageInfo); + console.log('> pageInfo', pageInfo); + console.log('> template', template); + + const $dialog = bootbox.dialog( + { + title: 'zin 视图模版', + message: `
    module/${pageInfo.moduleName}/ui/${pageInfo.methodName}.html.php
    `, + size: 'large', + buttons: + { + copy: + { + label: '复制到剪贴板', + className: 'btn-primary', + callback: () => + { + navigator.clipboard.writeText(template); + $.zui.messager.success(`zin 视图模版已复制到剪贴板,请创建文件 module/${pageInfo.moduleName}/ui/${pageInfo.methodName}.html.php 并粘贴`); + } + }, + close: + { + label: '关闭', + className: 'btn-default', + callback: () => {} + }, + } + }); + $dialog.find('.modal-dialog').width(1200).find('pre>code').text(template); +} + +$(function() +{ + if(!config) return; + if(config.currentModule === 'index' && config.currentMethod === 'index') + { + $('').prependTo('#globalBarLogo').on('click', () => + { + const app = $.apps.getLastApp(); + if(!app) return; + zin(app.$iframe[0].contentWindow); + }); + } +}); diff --git a/www/js/zui3/zui.zentao.css b/www/js/zui3/zui.zentao.css new file mode 100644 index 0000000000..e9c2618248 --- /dev/null +++ b/www/js/zui3/zui.zentao.css @@ -0,0 +1 @@ +/*! tailwindcss v3.3.1 | MIT License | https://tailwindcss.com*/*,:after,:before{border-color:rgb(var(--color-gray-200-rgb));border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:-apple-system,Noto Sans,Helvetica Neue,Helvetica,Nimbus Sans L,Arial,Liberation Sans,PingFang SC,Hiragino Sans GB,Noto Sans CJK SC,Source Han Sans SC,Source Han Sans CN,Microsoft YaHei,Wenquanyi Micro Hei,WenQuanYi Zen Hei,ST Heiti,SimHei,WenQuanYi Zen Hei Sharp,sans-serif;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:rgb(var(--color-gray-400-rgb));opacity:1}input::placeholder,textarea::placeholder{color:rgb(var(--color-gray-400-rgb));opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}:root{--color-gray-50:#fafafa;--color-gray-100:#f6f7f9;--color-gray-200:#eee;--color-gray-300:#d8dbde;--color-gray-400:#c4c4c4;--color-gray-500:#898b90;--color-gray-600:#53575b;--color-gray-700:#3d4349;--color-gray-800:#2e343a;--color-gray-900:#000;--color-gray-50-rgb:250,250,250;--color-gray-100-rgb:246,247,249;--color-gray-200-rgb:238,238,238;--color-gray-300-rgb:216,219,222;--color-gray-400-rgb:196,196,196;--color-gray-500-rgb:137,139,144;--color-gray-600-rgb:83,87,91;--color-gray-700-rgb:61,67,73;--color-gray-800-rgb:46,52,58;--color-gray-900-rgb:0,0,0;--color-slate-50:#fcfdfe;--color-slate-100:#f4f5f7;--color-slate-200:#edeef2;--color-slate-300:#e6eaf1;--color-slate-400:#e3e4e9;--color-slate-500:#9ea3b0;--color-slate-600:#838a9d;--color-slate-700:#5e626d;--color-slate-800:#313c52;--color-slate-900:#0b0f18;--color-slate-50-rgb:252,253,254;--color-slate-100-rgb:244,245,247;--color-slate-200-rgb:237,238,242;--color-slate-300-rgb:230,234,241;--color-slate-400-rgb:227,228,233;--color-slate-500-rgb:158,163,176;--color-slate-600-rgb:131,138,157;--color-slate-700-rgb:94,98,109;--color-slate-800-rgb:49,60,82;--color-slate-900-rgb:11,15,24;--color-primary-50:#e6f0ff;--color-primary-100:#d5e5ff;--color-primary-200:#a4c7ff;--color-primary-300:#66a2ff;--color-primary-400:#3785ff;--color-primary-500:#2e7fff;--color-primary-600:#1e6aeb;--color-primary-700:#2463c7;--color-primary-800:#1b54ad;--color-primary-900:#063072;--color-primary-50-rgb:230,240,255;--color-primary-100-rgb:213,229,255;--color-primary-200-rgb:164,199,255;--color-primary-300-rgb:102,162,255;--color-primary-400-rgb:55,133,255;--color-primary-500-rgb:46,127,255;--color-primary-600-rgb:30,106,235;--color-primary-700-rgb:36,99,199;--color-primary-800-rgb:27,84,173;--color-primary-900-rgb:6,48,114;--color-secondary-50:#e7f6ff;--color-secondary-100:#cdecff;--color-secondary-200:#9bd9ff;--color-secondary-300:#77cbff;--color-secondary-400:#60c2ff;--color-secondary-500:#37b2fe;--color-secondary-600:#18a6fd;--color-secondary-700:#1099ed;--color-secondary-800:#078ada;--color-secondary-900:#046bab;--color-secondary-50-rgb:231,246,255;--color-secondary-100-rgb:205,236,255;--color-secondary-200-rgb:155,217,255;--color-secondary-300-rgb:119,203,255;--color-secondary-400-rgb:96,194,255;--color-secondary-500-rgb:55,178,254;--color-secondary-600-rgb:24,166,253;--color-secondary-700-rgb:16,153,237;--color-secondary-800-rgb:7,138,218;--color-secondary-900-rgb:4,107,171;--color-success-50:#ecfff8;--color-success-100:#d0f6e8;--color-success-200:#b1ecd6;--color-success-300:#7adfba;--color-success-400:#48d1a0;--color-success-500:#22c98d;--color-success-600:#0dbb7d;--color-success-700:#0ca76f;--color-success-800:#0e8d60;--color-success-900:#186c4e;--color-success-50-rgb:236,255,248;--color-success-100-rgb:208,246,232;--color-success-200-rgb:177,236,214;--color-success-300-rgb:122,223,186;--color-success-400-rgb:72,209,160;--color-success-500-rgb:34,201,141;--color-success-600-rgb:13,187,125;--color-success-700-rgb:12,167,111;--color-success-800-rgb:14,141,96;--color-success-900-rgb:24,108,78;--color-warning-50:#fff4ea;--color-warning-100:#ffecdb;--color-warning-200:#ffd2a9;--color-warning-300:#ffbc7e;--color-warning-400:#ffaf65;--color-warning-500:#ff9f46;--color-warning-600:#f38f19;--color-warning-700:#ed8307;--color-warning-800:#d17100;--color-warning-900:#af5f01;--color-warning-50-rgb:255,244,234;--color-warning-100-rgb:255,236,219;--color-warning-200-rgb:255,210,169;--color-warning-300-rgb:255,188,126;--color-warning-400-rgb:255,175,101;--color-warning-500-rgb:255,159,70;--color-warning-600-rgb:243,143,25;--color-warning-700-rgb:237,131,7;--color-warning-800-rgb:209,113,0;--color-warning-900-rgb:175,95,1;--color-danger-50:#ffebeb;--color-danger-100:#ffd5d5;--color-danger-200:#ffb1b1;--color-danger-300:#ff9292;--color-danger-400:#ff7c7c;--color-danger-500:#fc5959;--color-danger-600:#fb2b2b;--color-danger-700:#d91b1b;--color-danger-800:#ba1313;--color-danger-900:#a20606;--color-danger-50-rgb:255,235,235;--color-danger-100-rgb:255,213,213;--color-danger-200-rgb:255,177,177;--color-danger-300-rgb:255,146,146;--color-danger-400-rgb:255,124,124;--color-danger-500-rgb:252,89,89;--color-danger-600-rgb:251,43,43;--color-danger-700-rgb:217,27,27;--color-danger-800-rgb:186,19,19;--color-danger-900-rgb:162,6,6;--color-important-50:#fff1f7;--color-important-100:#fbdeec;--color-important-200:#ffbadb;--color-important-300:#ff83be;--color-important-400:#eb599f;--color-important-500:#df4590;--color-important-600:#c92d79;--color-important-700:#a01c5d;--color-important-800:#880847;--color-important-900:#601439;--color-important-50-rgb:255,241,247;--color-important-100-rgb:251,222,236;--color-important-200-rgb:255,186,219;--color-important-300-rgb:255,131,190;--color-important-400-rgb:235,89,159;--color-important-500-rgb:223,69,144;--color-important-600-rgb:201,45,121;--color-important-700-rgb:160,28,93;--color-important-800-rgb:136,8,71;--color-important-900-rgb:96,20,57;--color-special-50:#efecfa;--color-special-100:#e4dff7;--color-special-200:#c4b6ff;--color-special-300:#a38cff;--color-special-400:#8a6ff5;--color-special-500:#8166ee;--color-special-600:#7055df;--color-special-700:#513baa;--color-special-800:#452da5;--color-special-900:#30216e;--color-special-50-rgb:239,236,250;--color-special-100-rgb:228,223,247;--color-special-200-rgb:196,182,255;--color-special-300-rgb:163,140,255;--color-special-400-rgb:138,111,245;--color-special-500-rgb:129,102,238;--color-special-600-rgb:112,85,223;--color-special-700-rgb:81,59,170;--color-special-800-rgb:69,45,165;--color-special-900-rgb:48,33,110;--color-inherit:inherit;--color-transparent:transparent;--color-current:currentColor;--color-black:#000;--color-white:#fff;--color-canvas:#fff;--color-inverse:#000;--color-surface:#f6f7f9;--color-fore:#313c52;--color-focus:#9bd9ff;--color-link:#1e6aeb;--color-link-hover:#2e7fff;--color-link-visited:#1b54ad;--color-border:#e3e4e9;--color-border-strong:#d8dbde;--color-border-light:#eee;--color-black-rgb:0,0,0;--color-white-rgb:255,255,255;--color-canvas-rgb:255,255,255;--color-inverse-rgb:0,0,0;--color-surface-rgb:246,247,249;--color-fore-rgb:49,60,82;--color-focus-rgb:155,217,255;--color-link-rgb:30,106,235;--color-link-hover-rgb:46,127,255;--color-link-visited-rgb:27,84,173;--color-border-rgb:227,228,233;--color-border-strong-rgb:216,219,222;--color-border-light-rgb:238,238,238;--radius-none:0px;--radius-sm:.0625rem;--radius:.125rem;--radius-md:.25rem;--radius-lg:.375rem;--radius-xl:.5rem;--radius-2xl:.75rem;--radius-3xl:1rem;--radius-full:9999px;--shadow-sm:0 1px 2px 0 rgba(0,0,0,.05);--shadow:0 1px 4px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--shadow-md:0 2px 8px -1px rgba(0,0,0,.1),0 1px 4px -2px rgba(0,0,0,.1);--shadow-lg:0 4px 16px -4px rgba(0,0,0,.1),0 2px 6px -4px rgba(0,0,0,.1);--shadow-xl:0 6px 32px -6px rgba(0,0,0,.15),0 4px 10px -6px rgba(0,0,0,.15);--shadow-2xl:0 25px 50px -12px rgba(0,0,0,.25);--shadow-inner:inset 0 2px 4px 0 rgba(0,0,0,.05);--shadow-none:none;--space:.25rem;--root-font-size:16px}body{--btn-bg:var(--color-slate-50)}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }html{font-size:var(--root-font-size)}body{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity));color:rgba(var(--color-fore-rgb),var(--tw-text-opacity));font-size:.8125rem;line-height:1.25rem}a{color:rgba(var(--color-link-rgb),var(--tw-text-opacity))}a,a:hover{--tw-text-opacity:1}a:hover{color:rgba(var(--color-link-hover-rgb),var(--tw-text-opacity))}a:focus-visible{outline-color:rgb(var(--color-focus-rgb));outline-offset:2px;outline-width:2px}:root{--zt-page-bg:var(--color-gray-100);--zt-header-bg:var(--color-primary-500);--zt-header-color:var(--color-canvas);--zt-page-form-max-width:1000px}body{background:var(--zt-page-bg)}#header{background:var(--zt-header-bg);color:var(--zt-header-color);height:3rem}#header>.container{height:100%;position:relative}#heading{align-items:center;bottom:0;display:flex;gap:.25rem;left:1rem;position:absolute;top:0}#heading>.toolbar{margin-left:-.75rem}#navbar{align-items:center;display:flex;height:100%;justify-content:center}#navbar>.nav{--nav-active-color:var(--color-current)}#navbar>.nav>.nav-item>a{height:3rem;padding-left:.75rem;padding-right:.75rem}#navbar>.nav>.nav-item>a:after{--tw-scale-x:.5;background-color:var(--color-current);bottom:0;content:"";height:.125rem;left:.75rem;opacity:0;position:absolute;right:.75rem;transition-duration:.15s;transition-property:transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}#navbar>.nav>.nav-item>.active:after,#navbar>.nav>.nav-item>a:after{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}#navbar>.nav>.nav-item>.active:after{--tw-scale-x:1;opacity:1}#toolbar{align-items:center;bottom:0;display:flex;gap:.25rem;position:absolute;right:1rem;top:0}#versionMenu .menu-item>a{padding-left:1.5rem;padding-right:1.5rem}#main{min-height:100vh}#header+#main{min-height:calc(100vh - 3rem)}#main>.container{padding-left:1rem;padding-right:1rem;position:relative}#mainMenu{align-items:center;display:flex;gap:1rem;justify-content:space-between;padding-bottom:.75rem;padding-top:.75rem}#featureBar{flex:1 1 auto}#featureBar .nav .btn>.icon{--tw-text-opacity:1;color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}#actionBar{gap:.5rem}#actionBar>.nav-divider{margin-left:-.25rem;margin-right:-.25rem}#mainContent{padding-top:1rem}#mainMenu+#mainContent{padding-top:0}#mainContent.row{align-items:stretch;display:flex;gap:1rem;justify-content:space-between}#mainContent.row>*{flex:1 1 auto;min-width:0}#mainContent>.panel-form{max-width:var(--zt-page-form-max-width)}.action-menu-item{position:relative}.action-menu-item .checked{position:absolute;right:10px;top:5px}:root{--breadcrumb-divider:"/";--breadcrumb-divider-color:var(--color-gray-500);--breadcrumb-color-active:var(--color-gray-500)}.breadcrumb{display:flex;gap:1.25rem}.breadcrumb>li{position:relative}.breadcrumb>li+li:before{color:var(--breadcrumb-divider-color);content:var(--breadcrumb-divider);display:block;left:-1.25rem;position:absolute;text-align:center;width:1.25rem}.breadcrumb>.active{color:var(--breadcrumb-color-active)}:root{--btn-radius:var(--radius);--btn-bg:var(--color-surface);--btn-border-color:var(--color-gray-300)}.btn{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:var(--btn-border-color);align-items:center;background-color:var(--btn-bg);border-radius:var(--btn-radius);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);display:inline-flex;gap:.375rem;height:2rem;justify-content:center;padding-left:.75rem;padding-right:.75rem;white-space:nowrap}.btn-default,.btn-default:hover{color:var(--color-inherit)}.btn-link{--tw-text-opacity:1;--tw-ring-color:var(--color-transparent);color:rgba(var(--color-link-rgb),var(--tw-text-opacity));text-decoration-line:underline;text-underline-offset:2px}.btn-link:visited{color:rgba(var(--color-link-visited-rgb),var(--tw-text-opacity))}.btn-link:hover{--tw-text-opacity:1;color:rgba(var(--color-link-hover-rgb),var(--tw-text-opacity))}.btn-link{--btn-bg:transparent}.btn.btn-caret{padding-left:.25rem;padding-right:.25rem}.checkbox,.radio{align-items:center;cursor:pointer;display:flex;gap:.375rem}.checkbox>input[type=checkbox],.radio>input[type=radio]{accent-color:rgb(var(--color-primary-500-rgb));border-radius:var(--radius-lg)}.checkbox>input[type=checkbox]:focus{outline:2px solid var(--form-control-focus)}.checkbox-primary,.radio-primary{display:flex;gap:.375rem;position:relative}.checkbox-primary>input[type=checkbox],.radio-primary>input[type=radio]{inset:0;opacity:0;position:absolute}.checkbox-primary>label,.radio-primary>label{cursor:pointer;padding-left:1.25rem;position:relative}.checkbox-primary>label:after,.checkbox-primary>label:before,.radio-primary>label:after,.radio-primary>label:before{content:" ";display:block;height:.75rem;left:0;position:absolute;top:.25rem;transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);width:.75rem}.checkbox-primary>label:before{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-gray-400-rgb),var(--tw-border-opacity));border-radius:var(--radius-sm);border-width:1px}.checkbox-primary>label:after{--tw-rotate:-45deg;--tw-border-opacity:1;border-bottom-color:rgba(var(--color-canvas-rgb),var(--tw-border-opacity));border-left-color:rgba(var(--color-canvas-rgb),var(--tw-border-opacity));border-width:0 0 2px 2px;height:.375rem;left:.125rem;opacity:0;top:.375rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));width:.5rem}.radio-primary>label:before{--tw-border-opacity:1;border-color:rgba(var(--color-gray-400-rgb),var(--tw-border-opacity));border-radius:var(--radius-full);border-width:1px}.radio-primary>label:after{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity));border-radius:var(--radius-full);height:.5rem;left:.125rem;opacity:0;top:.375rem;width:.5rem}.checkbox-primary>label:hover:before,.radio-primary>label:hover:before{--tw-border-opacity:1;border-color:rgba(var(--color-gray-400-rgb),var(--tw-border-opacity))}.checkbox-primary.focus>label:before,.checkbox-primary>input[type=checkbox]:focus+label:before,.radio-primary.focus>label:before,.radio-primary>input[type=radio]:focus+label:before{outline-color:rgb(var(--color-focus-rgb));outline-style:solid;outline-width:2px}.checkbox-primary.checked>label:before,.checkbox-primary>input[type=checkbox]:checked+label:before{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-primary-500-rgb),var(--tw-border-opacity))}.radio-primary.checked>label:before,.radio-primary>input[type=radio]:checked+label:before{--tw-border-opacity:1;border-color:rgba(var(--color-primary-500-rgb),var(--tw-border-opacity))}.checkbox-primary.checked>label:after,.checkbox-primary>input[type=checkbox]:checked+label:after,.radio-primary.checked>label:after,.radio-primary>input[type=radio]:checked+label:after{opacity:1}.checkbox-primary.checked.disabled>label:before,.checkbox-primary>input[type=checkbox]:checked:disabled+label:before,.radio-primary.checked.disabled>label:before,.radio-primary>input[type=radio]:checked:disabled+label:before{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-gray-400-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-gray-400-rgb),var(--tw-border-opacity))}.check-list{display:flex;flex-direction:column;gap:.75rem;padding-bottom:.375rem;padding-top:.375rem}.check-list-inline{align-items:center;display:flex;flex-direction:row;gap:1rem;height:2rem}:root{--form-control-radius:var(--radius);--form-control-border:var(--color-border-strong);--form-control-focus:var(--color-primary-500);--form-control-disabled:var(--color-surface)}.form-control{--tw-bg-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:var(--form-control-border);background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity));border-radius:var(--form-control-radius);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);display:block;height:2rem;outline-color:var(--color-transparent);outline-style:solid;outline-width:1px;padding:.25rem .5rem;transition-duration:.15s;transition-property:outline,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);width:100%}.form-control.focus,.form-control:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:rgba(var(--color-focus-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.6;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);outline-color:var(--form-control-focus)}.form-control.disabled,.form-control[disabled]{background-color:var(--form-control-disabled)}select{-webkit-appearance:none;background-image:url(data:image/gif;base64,R0lGODlhBwAEAIAAAMvQ2////yH5BAEAAAEALAAAAAAHAAQAAAIIhA+BGWoNWSgAOw==);background-position:right 8px top 50%;background-repeat:no-repeat;background-size:8px auto;padding-right:1rem}select.form-control[multiple]{background-image:none;height:auto}textarea.form-control{height:auto;min-height:32px}input[type=file].form-control{padding:.125rem}input[type=file].form-control::-webkit-file-upload-button{-webkit-appearance:none;appearance:none;border-radius:inherit;border-style:none;cursor:pointer;height:1.75rem;padding-left:.5rem;padding-right:.5rem}input[type=file].form-control:hover::-webkit-file-upload-button{background-color:rgba(var(--color-black-rgb),.1)}.has-error .form-control,.has-error.form-control{--tw-ring-color:rgba(var(--color-danger-500-rgb),.6)}.has-error .form-control.focus,.has-error .form-control:focus,.has-error.form-control.focus,.has-error.form-control:focus{outline-color:rgb(var(--color-danger-500-rgb))}.has-warning .form-control,.has-warning.form-control{--tw-ring-color:rgba(var(--color-warning-500-rgb),.6)}.has-warning .form-control.focus,.has-warning .form-control:focus,.has-warning.form-control.focus,.has-warning.form-control:focus{outline-color:rgb(var(--color-warning-500-rgb))}.has-success .form-control,.has-success.form-control{--tw-ring-color:rgba(var(--color-success-500-rgb),.6)}.has-success .form-control.focus,.has-success .form-control:focus,.has-success.form-control.focus,.has-success.form-control:focus{outline-color:rgb(var(--color-success-500-rgb))}:root{--input-group-addon-bg:var(--color-gray-100)}.input-group{align-items:stretch;display:flex}.input-group>.form-control,.input-group>.input-control{flex:1 1 auto;z-index:1}.input-group-addon{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:var(--form-control-border);align-items:center;background-color:var(--input-group-addon-bg);border-radius:var(--form-control-radius);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);display:flex;flex:none;height:2rem;padding-left:.5rem;padding-right:.5rem;z-index:0}.input-group>*+*{border-bottom-left-radius:var(--radius-none);border-top-left-radius:var(--radius-none)}.input-group>:not(:last-child){border-bottom-right-radius:var(--radius-none);border-top-right-radius:var(--radius-none)}.input-group .btn:focus-visible,.input-group .form-control:focus{z-index:2}:root{--form-tip-color:var(--color-slate-600);--form-label-color:var(--color-slate-700);--form-grid-label-width:6rem}.form>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.form-label{align-items:center;color:var(--form-label-color);display:flex;flex-direction:row;height:2rem;overflow:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap}.form-label.required:after{--tw-translate-y:.125rem;--tw-scale-x:1.25;--tw-scale-y:1.25;--tw-text-opacity:1;color:rgba(var(--color-danger-500-rgb),var(--tw-text-opacity));content:"*";display:inline-block;margin-left:.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.form-tip{color:var(--form-tip-color);margin-top:.25rem}.has-error .form-tip{--tw-text-opacity:1;color:rgba(var(--color-danger-500-rgb),var(--tw-text-opacity))}.has-warning .form-tip{--tw-text-opacity:1;color:rgba(var(--color-warning-500-rgb),var(--tw-text-opacity))}.has-success .form-tip{--tw-text-opacity:1;color:rgba(var(--color-success-500-rgb),var(--tw-text-opacity))}.form-grid>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.form-row{align-items:flex-start;display:flex;flex-direction:row}.form-grid .form-group{align-items:flex-start;display:flex;flex:1 1 auto;flex-direction:row;flex-wrap:wrap;min-height:32px;padding-left:var(--form-grid-label-width);position:relative}.form-grid .form-group.no-label{padding-left:0}.form-grid .form-group.no-label>.check-list-inline{padding-left:1rem;padding-right:1rem}.form-grid .form-label{justify-content:flex-end;left:0;padding-left:1rem;padding-right:.5rem;position:absolute;top:0;width:var(--form-grid-label-width)}.form-grid .form-label.required:after{margin-left:0;margin-right:.25rem;order:-9999}.form-grid .form-tip{width:100%}.form-grid .form-tip,.form-grid .input-control,.form-grid .input-group{flex:1 1 auto}.form fieldset>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.form fieldset{padding-bottom:1rem;padding-left:1rem}.form-grid fieldset>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.form legend{--tw-border-opacity:1;border-bottom-color:rgba(var(--color-primary-100-rgb),var(--tw-border-opacity));border-bottom-width:1px;display:flex;justify-content:flex-start;margin-left:-1rem;width:100%;width:calc(100% + 1rem)}.form-title{align-items:center;background-color:rgba(var(--color-primary-50-rgb),.5);display:flex;font-weight:700;height:1.75rem;padding-left:.75rem;padding-right:.75rem}:root{--input-control-fix-width-sm:2rem;--input-control-fix-width:4.375rem;--input-control-fix-width-lg:6.75rem}.input-control{--input-control-prefix:8px;--input-control-suffix:8px;position:relative}.input-control-prefix,.input-control-suffix{align-items:center;display:flex;height:2rem;left:0;opacity:.5;padding-left:.5rem;padding-right:.5rem;position:absolute;top:0;white-space:nowrap;width:var(--input-control-prefix)}.input-control-suffix{justify-content:flex-end;left:auto;right:0;width:var(--input-control-suffix)}.form-control:focus+.input-control-prefix,.form-control:focus+.input-control-suffix{opacity:1}.input-control>.form-control{padding-left:var(--input-control-prefix);padding-right:var(--input-control-suffix)}.has-prefix{--input-control-prefix:var(--input-control-fix-width)}.has-suffix{--input-control-suffix:var(--input-control-fix-width)}.has-prefix-sm{--input-control-prefix:var(--input-control-fix-width-sm)}.has-suffix-sm{--input-control-suffix:var(--input-control-fix-width-sm)}.has-prefix-lg{--input-control-prefix:var(--input-control-fix-width-lg)}.has-suffix-lg{--input-control-suffix:var(--input-control-fix-width-lg)}.has-prefix-icon{--input-control-prefix:32px}.has-suffix-icon{--input-control-suffix:32px}.input-control.has-prefix-icon>.input-control-prefix,.input-control.has-suffix-icon>.input-control-suffix{justify-content:center;width:2rem}:root{--label-bg:var(--color-gray-50);--label-border-color:var(--color-gray-500);--label-color:var(--color-gray-500);--label-radius:var(--radius)}.label{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:var(--label-border-color);align-items:center;background-color:var(--label-bg);border-radius:var(--label-radius);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);color:var(--label-color);display:inline-flex;font-size:.75rem;height:1.25rem;line-height:1rem;padding-left:.25rem;padding-right:.25rem;white-space:pre-line}.label.size-lg{font-size:.8125rem;height:1.5rem;line-height:1.25rem;padding-left:.5rem;padding-right:.5rem}.label.size-sm{height:1rem}.label-dot{aspect-ratio:1/1;border-radius:var(--radius-full);height:.5rem;padding-left:0;padding-right:0}:root{--menu-radius:var(--radius);--menu-bg:var(--color-canvas);--menu-hover-bg:var(--color-primary-500);--menu-hover-color:var(--color-canvas);--menu-active-bg:var(--color-primary-50);--menu-active-color:var(--color-primary-500);--menu-icon-opacity:.5;--menu-icon-margin:1.75rem;--menu-min-width:3rem;--menu-heading-color:var(--color-gray-500)}.menu{background:var(--menu-bg);min-width:var(--menu-min-width);padding:.25rem}.menu-item>a{align-items:center;border-radius:var(--radius);color:var(--color-inherit);cursor:pointer;display:flex;gap:.25rem;justify-content:space-between;margin:.25rem;overflow:hidden;padding:.125rem .5rem;position:relative;text-overflow:ellipsis;transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);white-space:nowrap}.menu-item>.active{background:var(--menu-active-bg);color:var(--menu-active-color)}.menu-item>a:hover{background:var(--menu-hover-bg);color:var(--menu-hover-color)}.menu-item>a>.text{flex:1 1 auto}.menu-divider{--tw-bg-opacity:1;background-color:rgba(var(--color-border-rgb),var(--tw-bg-opacity));height:1px;margin:.5rem}.menu-heading{align-items:center;color:var(--menu-heading-color);display:flex;font-size:.75rem;font-weight:700;height:1.5rem;line-height:1rem;padding-left:.5rem;padding-right:.5rem}.has-icons>.menu-item>a,.menu-item.has-icon>a{padding-left:var(--menu-icon-margin)}.has-icons>.menu-item>a>.icon:first-child,.menu-item.has-icon>a>.icon:first-child{align-items:center;display:flex;height:1.5rem;justify-content:center;left:0;opacity:var(--menu-icon-opacity);position:absolute;top:0;width:1.5rem}.has-nested-menu>.menu.menu-nested{--tw-shadow:var(--shadow-none);--tw-shadow-colored:var(--shadow-none);border-style:none;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);margin-left:1rem}.menu-nested .menu-toggle-icon{left:.25rem;position:absolute}.menu-nested.has-nested-items>.menu-item>a{padding-left:1rem}.menu-nested.has-nested-items.has-icons>.menu-item>a{padding-left:2.25rem}.menu-nested.has-nested-items.has-icons>.menu-item>a>.icon:first-child{left:.75rem}.menu-popup{--tw-shadow:var(--shadow-xl);--tw-shadow-colored:var(--shadow-xl);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.05;border-radius:var(--menu-radius);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:root{--alert-radius:var(--radius);--alert-bg:var(--color-surface)}.alert{align-items:center;background:var(--alert-bg);border-radius:var(--alert-radius);padding:.75rem 1rem}.alert,.alert-content{display:flex;gap:.75rem}.alert-content{flex:1 1 auto;flex-direction:column}.alert-close{flex:none;margin-bottom:-.5rem;margin-right:-.5rem;margin-top:-.5rem}.alert-link{color:var(--color-inherit);font-weight:700}.alert-link:hover{color:var(--color-inherit);text-decoration-line:underline}.alert-heading{font-weight:700;margin:0}.alert-actions{align-items:center;display:flex;gap:.5rem}:root{--messager-default-bg-color:var(--color-gray-800);--messager-radius:2rem}.messagers{align-items:flex-end;display:flex;flex-direction:column;inset:0;justify-content:flex-end;padding:1rem;pointer-events:none;position:absolute;z-index:50}.messagers-top-left,.messagers-top-right{justify-content:flex-start}.messagers-bottom-left,.messagers-top-left{align-items:flex-start}.messagers-bottom,.messagers-center,.messagers-top{align-items:center}.messagers-top,.messagers-top-left,.messagers-top-right{justify-content:flex-start}.messagers-center{justify-content:center}.messager{--tw-text-opacity:1;--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);background-color:rgba(var(--color-inverse-rgb),.8);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgba(var(--color-canvas-rgb),var(--tw-text-opacity));pointer-events:auto;transition-duration:.3s}.toolbar{align-items:center;display:flex;position:relative}.toolbar-divider{--tw-bg-opacity:1;background-color:rgba(var(--color-border-rgb),var(--tw-bg-opacity));height:1rem;margin-left:.5rem;margin-right:.5rem;width:1px}.toolbar-space{flex:1 1 auto;width:1rem}.toolbar>.dropdown{align-items:center;display:flex;position:relative}:root{--contextmenu-nested-hover-bg:var(--color-primary-100)}.contextmenu{display:none;z-index:50}.contextmenu.show{display:block}.contextmenu .has-nested-menu>.menu{background:var(--menu-bg);border:var(--menu-border);box-shadow:var(--menu-shadow);position:absolute}.contextmenu-toggle-icon{margin-left:.5rem}.contextmenu .has-nested-menu.show>a:not(:hover){background:var(--contextmenu-nested-hover-bg)}.dropdown-menu{--menu-min-width:7rem;display:none;z-index:30}.dropdown-menu.show{display:block}.btn.with-dropdown-show{--tw-shadow:var(--shadow-inner);--tw-shadow-colored:var(--shadow-inner);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}a.with-dropdown-show:before{opacity:1}.with-dropdown-show[data-dropdown-placement=top]>.caret{--tw-rotate:180deg}.with-dropdown-show[data-dropdown-placement=left]>.caret,.with-dropdown-show[data-dropdown-placement=top]>.caret{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.with-dropdown-show[data-dropdown-placement=left]>.caret{--tw-rotate:90deg}.with-dropdown-show[data-dropdown-placement=right]>.caret{--tw-rotate:-90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dropdown-submenu:hover>.menu{display:block;left:calc(100% - 6px);position:absolute}.btn-group{display:flex}.btn-group>.btn:focus-within,.btn-group>.btn:hover,.btn-group>.dropdown>.btn:focus-within,.btn-group>.dropdown>.btn:hover{z-index:1}.btn-group>.btn.disabled,.btn-group>.btn:disabled{z-index:-1}.btn-group>.btn:not(:first-child),.btn-group>.dropdown:not(:first-child)>.btn{border-bottom-left-radius:var(--radius-none);border-top-left-radius:var(--radius-none)}.btn-group>.btn:not(:last-child),.btn-group>.dropdown:not(:last-child)>.btn{border-bottom-right-radius:var(--radius-none);border-top-right-radius:var(--radius-none)}.btn.size-xs{height:1.25rem;padding-left:.25rem;padding-right:.25rem}.btn.size-sm,.btn.size-xs{font-size:.75rem;line-height:1rem}.btn.size-sm{height:1.5rem;padding-left:.5rem;padding-right:.5rem}.btn.size-lg{font-size:1rem;height:2.5rem;line-height:1.5rem;padding-left:1rem;padding-right:1rem}.btn.size-xl{font-size:1.125rem;height:3rem;line-height:1.75rem;padding-left:1.25rem;padding-right:1.25rem}.btn.square{aspect-ratio:1/1;gap:.125rem;padding-left:0;padding-right:0}.btn-group.size-xs .btn,.btn.btn-caret{padding-left:.25rem;padding-right:.25rem}.btn-group.size-xs .btn{height:1.25rem}.btn-group.size-sm .btn,.btn-group.size-xs .btn{font-size:.75rem;line-height:1rem}.btn-group.size-sm .btn{height:1.5rem;padding-left:.5rem;padding-right:.5rem}.btn-group.size-lg .btn{font-size:1rem;height:2.5rem;line-height:1.5rem;padding-left:1rem;padding-right:1rem}.btn-group.size-xl .btn{font-size:1.125rem;height:3rem;line-height:1.75rem;padding-left:1.25rem;padding-right:1.25rem}.btn-group.rounded-none .btn{border-radius:var(--radius-none)}.btn-group.rounded-sm .btn{border-radius:var(--radius-sm)}.btn-group.rounded .btn{border-radius:var(--radius)}.btn-group.rounded-md .btn{border-radius:var(--radius-md)}.btn-group.rounded-lg .btn{border-radius:var(--radius-lg)}.btn-group.rounded-xl .btn{border-radius:var(--radius-xl)}.btn-group.circle .btn{border-radius:var(--radius-full)}:root{--progress-radius:var(--radius);--progress-striped-size:40px;--progress-bg:var(--color-surface);--progress-bar-color:var(--color-primary-500)}.progress{background:var(--progress-bg);border-radius:var(--progress-radius);display:flex;height:1.25rem}.progress-bar{background:var(--progress-bar-color);height:100%}.progress-striped>.progress-bar{background-image:linear-gradient(45deg,rgba(var(--color-canvas-rgb),.15) 25%,transparent 25%,transparent 50%,rgba(var(--color-canvas-rgb),.15) 50%,rgba(var(--color-canvas-rgb),.15) 75%,transparent 75%,transparent);background-size:var(--progress-striped-size) var(--progress-striped-size)}.progress>.progress-bar:first-child{border-bottom-left-radius:inherit;border-top-left-radius:inherit}.progress>.progress-bar:last-child{border-bottom-right-radius:inherit;border-top-right-radius:inherit}.progress.active .progress-bar{animation:progress-bar-stripes 2s linear infinite}@keyframes progress-bar-stripes{0%{background-position:40px 0}to{background-position:0 0}}:root{--progress-circle-bg:var(--color-gray-300);--progress-circle-bar-color:var(--color-success-700)}.progress-circle>circle{fill:transparent}.progress-circle>text{text-anchor:middle}.progress-circle>circle:nth-child(2){stroke-linecap:round}.progress-circle{font-size:.7rem}::-webkit-scrollbar{height:var(--scrollbar-size);width:var(--scrollbar-size)}::-webkit-scrollbar-track{box-shadow:var(--scrollbar-shadow);-webkit-transition:background-color var(--scrollbar-duration);transition:background-color var(--scrollbar-duration)}::-webkit-scrollbar-track:hover,:hover::-webkit-scrollbar-track{background:var(--scrollbar-bg)}::-webkit-scrollbar-thumb{background:var(--scrollbar-bar-bg);border-radius:var(--scrollbar-radius);min-height:var(--scrollbar-size);-webkit-transition:var(--scrollbar-duration);transition:var(--scrollbar-duration);-webkit-transition-property:background-color;transition-property:background-color}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-hover-bg)}::-webkit-scrollbar-thumb:active{background:var(--scrollbar-drag-bg)}.scrollbar-hover::-webkit-scrollbar,.scrollbar-hover::-webkit-scrollbar-thumb,.scrollbar-hover::-webkit-scrollbar-track{visibility:hidden}.scrollbar-hover:hover::-webkit-scrollbar,.scrollbar-hover:hover::-webkit-scrollbar-thumb,.scrollbar-hover:hover::-webkit-scrollbar-track{visibility:visible}.switch{position:relative}.switch>input[type=checkbox]{display:block;height:100%;left:0;margin:0;opacity:0;position:absolute;top:0;width:100%}.switch label{display:block;font-weight:400;line-height:1.25rem;margin:0;padding:.375rem 0 .375rem 2.25rem}.switch label:after,.switch label:before{content:" ";display:block;height:1rem;left:0;pointer-events:none;position:absolute;top:.5rem;width:2rem}.switch label>:not([hidden])~:not([hidden]):after,.switch label>:not([hidden])~:not([hidden]):before{border-style:solid}.switch label:after,.switch label:before{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-200-rgb),var(--tw-bg-opacity));border-radius:var(--radius-xl);outline-color:rgb(var(--color-white-rgb));outline-width:1px}.switch label:after{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:var(--shadow);--tw-shadow-colored:var(--shadow);background-color:rgba(var(--color-white-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-white-rgb),var(--tw-border-opacity));border-radius:var(--radius-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:.75rem;left:.125rem;top:.625rem;transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);width:.75rem}.switch>input:checked+label:before{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-primary-500-rgb),var(--tw-border-opacity))}.switch>input:checked+label:after{--tw-border-opacity:1;border-color:rgba(var(--color-white-rgb),var(--tw-border-opacity));left:1.125rem}.switch.text-left>label{padding:.375rem 2.25rem .375rem 0}.switch.text-left>label:after,.switch.text-left>label:before{left:auto;right:0}.switch.text-left>label:after{right:1.125rem}.switch.text-left input:checked+label:after{left:auto;right:.125rem}.switch.disabled{pointer-events:none}.switch.disabled>label,.switch>input[disabled]+label{--tw-text-opacity:1;color:rgba(var(--color-gray-500-rgb),var(--tw-text-opacity));pointer-events:none}.switch>input[disabled]+label:before{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-300-rgb),var(--tw-bg-opacity))}.switch>input[disabled]+label:after{opacity:1}.switch input[disabled]:checked+label:before,.switch.disabled>input:checked+label:before{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-gray-300-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-gray-300-rgb),var(--tw-border-opacity))}.switch input[type=checkbox]:focus+label:before{--tw-border-opacity:1;--tw-shadow:var(--shadow);--tw-shadow-colored:var(--shadow);border-color:rgba(var(--color-primary-500-rgb),var(--tw-border-opacity));box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.upload>input[type=file]{display:none}.upload>.file-list{padding-bottom:.25rem;padding-top:.25rem}.upload>.file-list>.file-item,.upload>.file-list>.file-item>.file-info{align-items:center;display:flex;gap:.5rem}.upload>.file-list>.file-item{margin-bottom:.25rem;margin-top:.25rem}.upload>.file-list>.file-item>.file-info.hidden{display:none}.form{position:relative}.form .input-group:not(.input-group-segment)>*+*,.form .input-group:not(.input-group-segment)>:not(:last-child){border-radius:var(--form-control-radius)}.form .input-group:not(.input-group-segment) .input-group-addon{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.form-actions{justify-content:center}.form-actions .btn{min-width:96px}@font-face{font-family:ZentaoIcon;font-style:normal;font-weight:400;src:url(./@zentao/icons/ZentaoIcon.eot);src:url(./@zentao/icons/ZentaoIcon.woff) format("woff"),url(./@zentao/icons/ZentaoIcon.ttf) format("truetype"),url(./@zentao/icons/ZentaoIcon.svg#regular) format("svg")}.icon,[class*=" icon-"],[class^=icon-]{speak:none;display:inline-block;font-family:ZentaoIcon;font-size:14px;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none}.icon:before{display:inline-block;min-width:14px;text-align:center}.icon-lg:before{font-size:4/3em;vertical-align:-10%}.icon-2x{font-size:28px}.icon-3x{font-size:42px}.icon-4x{font-size:56px}.icon-5x{font-size:70px}.icon-zentao:before{content:"\e901"}.icon-zentao-alt:before{content:"\e900"}.icon-help:before{content:"\e968"}.icon-download:before,.icon-import:before{content:"\e904"}.icon-export:before{content:"\e905"}.icon-lightbulb:before{content:"\e91c"}.icon-close:before{content:"\e936"}.icon-check:before{content:"\e5ca"}.icon-plus:before{content:"\e925"}.icon-minus:before{content:"\e926"}.icon-expand-alt:before{content:"\e6f1"}.icon-collapse-alt:before{content:"\e6f2"}.icon-fullscreen:before{content:"\e96b"}.icon-star-empty:before{content:"\e94a"}.icon-star:before{content:"\e94b"}.icon-exclamation-sign:before{content:"\e930"}.icon-info-sign:before{content:"\e9d5"}.icon-flag:before{content:"\e937"}.icon-check-circle:before{content:"\e92f"}.icon-check-sign:before{content:"\e938"}.icon-chart-pie:before{content:"\e95b"}.icon-history:before{content:"\e95f"}.icon-pencil:before{content:"\e254"}.icon-search:before{content:"\e928"}.icon-restart:before{content:"\e95e"}.icon-cog:before{content:"\e93b"}.icon-chart-line:before{content:"\e95c"}.icon-bar-chart:before,.icon-chart-bar:before{content:"\e95d"}.icon-exchange:before{content:"\e927"}.icon-severity:before{content:"\e973"}.icon-book:before{content:"\f02d"}.icon-treemap-alt:before{content:"\e971"}.icon-severity-solid:before{content:"\e902"}.icon-chat-line:before{content:"\e998"}.icon-stack:before{content:"\e943"}.icon-cube:before{content:"\e967"}.icon-minus-sign:before{content:"\e939"}.icon-bars-sign:before{content:"\e93a"}.icon-chat:before,.icon-message:before{content:"\e940"}.icon-more:before{content:"\e744"}.icon-certificate:before{content:"\f0a3"}.icon-bell:before{content:"\e7f5"}.icon-columns:before{content:"\f0db"}.icon-envelope-o:before{content:"\e92a"}.icon-unfold-all:before{content:"\e931"}.icon-fold-all:before{content:"\e932"}.icon-bars:before{content:"\e948"}.icon-cards-view:before{content:"\e949"}.icon-ellipsis-v:before{content:"\e5d4"}.icon-spinner-indicator:before{content:"\e982"}.icon-up-circle:before{content:"\e92b"}.icon-right-circle:before{content:"\e92c"}.icon-down-circle:before{content:"\e92d"}.icon-left-circle:before{content:"\e92e"}.icon-angle-double-right:before{content:"\f101"}.icon-angle-down:before{content:"\e313"}.icon-angle-left:before{content:"\e314"}.icon-angle-right:before{content:"\e315"}.icon-angle-top:before{content:"\e316"}.icon-first-page:before{content:"\e5dc"}.icon-last-page:before{content:"\e5dd"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-arrow-up:before{content:"\e923"}.icon-arrow-down:before{content:"\e924"}.icon-arrow-left:before{content:"\e952"}.icon-arrow-right:before{content:"\e93e"}.icon-chevron-left:before{content:"\e934"}.icon-chevron-right:before{content:"\e935"}.icon-chevron-double-up:before{content:"\e959"}.icon-chevron-double-down:before{content:"\e95a"}.icon-folder-account:before{content:"\e942"}.icon-folder-move:before{content:"\e960"}.icon-folder-plus:before{content:"\e961"}.icon-folder-upload:before{content:"\e962"}.icon-folder-star:before{content:"\e963"}.icon-folder-edit:before{content:"\e964"}.icon-folder-download:before{content:"\e965"}.icon-folder-outline:before{content:"\e966"}.icon-folder:before{content:"\e944"}.icon-folder-o:before{content:"\e945"}.icon-folder-open-o:before{content:"\e946"}.icon-folder-open:before{content:"\e947"}.icon-color:before{content:"\e93c"}.icon-paper-clip:before{content:"\e93d"}.icon-text:before{content:"\e929"}.icon-share:before{content:"\f064"}.icon-format-list-bulleted:before{content:"\e9a8"}.icon-format-bold:before{content:"\e953"}.icon-format-header-pound:before{content:"\e954"}.icon-format-italic:before{content:"\e955"}.icon-format-list-numbers:before{content:"\e969"}.icon-format-quote-close:before{content:"\e96a"}.icon-image:before{content:"\e96c"}.icon-table-large:before{content:"\e96d"}.icon-aiux:before{content:"\e99e"}.icon-qc:before{content:"\e986"}.icon-qc-q:before{content:"\e985"}.icon-qc-c:before{content:"\e987"}.icon-sonarqube:before{content:"\e9ba"}.icon-college:before{content:"\e9c8"}.icon-ztool:before{content:"\e9c1"}.icon-contacts:before{content:"\e9c3"}.icon-chats:before{content:"\e9c4"}.icon-home:before,.icon-menu-my:before{content:"\e97a"}.icon-program:before{content:"\e9aa"}.icon-lightbulb-alt:before,.icon-product:before{content:"\e98f"}.icon-project:before,.icon-rocket:before{content:"\e99c"}.icon-run:before{content:"\e9a9"}.icon-test:before{content:"\e956"}.icon-devops:before,.icon-infinite:before{content:"\e9a3"}.icon-ops:before{content:"\e903"}.icon-doc:before,.icon-menu-doc:before{content:"\e99b"}.icon-statistic:before{content:"\e999"}.icon-menu-backend:before{content:"\e993"}.icon-assets:before,.icon-diamond:before{content:"\e9ae"}.icon-feedback:before{content:"\e991"}.icon-flow:before{content:"\e994"}.icon-oa:before{content:"\e9a1"}.icon-more-circle:before{content:"\e988"}.icon-controls:before{content:"\e995"}.icon-account:before{content:"\e992"}.icon-about:before,.icon-info:before{content:"\e996"}.icon-backend:before,.icon-cog-outline:before{content:"\e997"}.icon-exit:before{content:"\e99a"}.icon-theme:before{content:"\e9a0"}.icon-globe:before,.icon-lang:before{content:"\f0ac"}.icon-table-sort:before{content:"\e9e1"}.icon-blame:before{content:"\e9e0"}.icon-draft-edit:before{content:"\e9dd"}.icon-sub-review-user:before{content:"\e9db"}.icon-sub-review:before{content:"\e9df"}.icon-ztf:before{content:"\e9dc"}.icon-save:before{content:"\e9d8"}.icon-list-box:before{content:"\e9b4"}.icon-usecase:before{content:"\e99d"}.icon-code:before{content:"\e990"}.icon-summary:before{content:"\e9ad"}.icon-more-alt:before{content:"\e9a7"}.icon-customer:before{content:"\e9d9"}.icon-ticket:before{content:"\e9e1"}.icon-appose:before,.icon-gantt-alt:before{content:"\e9e2"}.icon-inline:before{content:"\e9e3"}.icon-tree:before{content:"\e9c9"}.icon-list:before{content:"\e9cb"}.icon-gantt:before{content:"\e9cc"}.icon-group-view:before{content:"\e9cd"}.icon-inherit-space:before{content:"\e9c2"}.icon-card-archive:before{content:"\e9b8"}.icon-col-archive:before{content:"\e9b9"}.icon-col-add-right:before{content:"\e9bb"}.icon-col-add-left:before{content:"\e9bc"}.icon-col-split:before{content:"\e9bd"}.icon-waterfall:before{content:"\e9a4"}.icon-manual:before{content:"\e98d"}.icon-kanban:before{content:"\e983"}.icon-lane:before{content:"\e9b1"}.icon-back:before{content:"\e9d3"}.icon-back-circle:before{content:"\e9da"}.icon-shield:before{content:"\e9ca"}.icon-meh:before{content:"\e9ce"}.icon-frown:before{content:"\e9cf"}.icon-smile:before{content:"\e9d0"}.icon-unlock-solid:before{content:"\e9d1"}.icon-lock-solid:before{content:"\e9d2"}.icon-ver:before{content:"\e9c6"}.icon-publish:before,.icon-send:before{content:"\e9c7"}.icon-tag:before{content:"\e9be"}.icon-tag-lock:before{content:"\e9bf"}.icon-code-fork:before{content:"\f126"}.icon-branch-lock:before{content:"\e9c0"}.icon-groups:before{content:"\e9af"}.icon-thumbs-up:before{content:"\f087"}.icon-thumbs-down:before{content:"\f088"}.icon-thumbs-up-solid:before{content:"\e9d6"}.icon-thumbs-down-solid:before{content:"\e9d7"}.icon-hash:before,.icon-version:before{content:"\e9ab"}.icon-p-square:before{content:"\e97b"}.icon-video-play:before{content:"\e97f"}.icon-plus-solid-circle:before{content:"\e974"}.icon-minuse-solid-circle:before{content:"\e9b6"}.icon-s:before{content:"\e975"}.icon-c:before{content:"\e976"}.icon-t:before{content:"\e977"}.icon-guide:before{content:"\e978"}.icon-todo:before{content:"\e979"}.icon-side-left:before{content:"\e9b3"}.icon-side-right:before{content:"\e9b2"}.icon-fullscreen-exit:before{content:"\e972"}.icon-alert:before{content:"\e99f"}.icon-undo:before{content:"\e93f"}.icon-redo:before{content:"\e9d4"}.icon-swap:before{content:"\e9b0"}.icon-chat-solid:before{content:"\e9b5"}.icon-clock:before{content:"\e97c"}.icon-cost:before{content:"\e97d"}.icon-pencil-alt:before{content:"\e984"}.icon-size-height:before{content:"\e9c5"}.icon-file-log:before{content:"\e9de"}.icon-rich-text:before{content:"\e913"}.icon-markdown:before{content:"\e916"}.icon-excel:before{content:"\e933"}.icon-text-link:before{content:"\e94d"}.icon-ppt:before{content:"\e957"}.icon-word:before{content:"\e958"}.icon-doc-lib:before{content:"\e96f"}.icon-file-empty:before,.icon-file:before{content:"\f016"}.icon-file-text:before{content:"\f0f6"}.icon-file-alt:before{content:"\f15b"}.icon-file-text-alt:before{content:"\f15c"}.icon-file-pdf:before{content:"\f1c1"}.icon-file-word:before{content:"\f1c2"}.icon-file-excel:before{content:"\f1c3"}.icon-file-powerpoint:before{content:"\f1c4"}.icon-file-image:before{content:"\f1c5"}.icon-file-archive:before{content:"\f1c6"}.icon-file-audio:before{content:"\f1c7"}.icon-file-video:before{content:"\f1c8"}.icon-file-code:before{content:"\f1c9"}.icon-menu-collapse:before{content:"\e980"}.icon-menu-expand:before{content:"\e981"}.icon-group:before,.icon-menu-users:before,.icon-persons:before,.icon-team:before{content:"\e97e"}.icon-estimate:before{content:"\e9ac"}.icon-sprint:before{content:"\e9a2"}.icon-shield-check:before{content:"\e9a5"}.icon-ok:before{content:"\e9a6"}.icon-printer:before{content:"\e906"}.icon-bullhorn:before{content:"\e910"}.icon-person:before{content:"\e941"}.icon-fields:before{content:"\e989"}.icon-trigger:before{content:"\e98a"}.icon-layout:before{content:"\e98b"}.icon-audit:before{content:"\e98c"}.icon-ban-circle:before,.icon-cancel:before{content:"\e951"}.icon-eye:before{content:"\e94e"}.icon-eye-off:before{content:"\e96e"}.icon-unlock:before{content:"\e94f"}.icon-lock:before,.icon-private:before{content:"\e950"}.icon-move:before{content:"\e94c"}.icon-hand-right:before{content:"\e907"}.icon-checked:before{content:"\e908"}.icon-off:before{content:"\e909"}.icon-play:before,.icon-start:before{content:"\e90a"}.icon-time:before{content:"\e90b"}.icon-edit:before{content:"\e90c"}.icon-trash:before{content:"\e90d"}.icon-link:before{content:"\e90e"}.icon-unlink:before{content:"\e90f"}.icon-bug:before{content:"\e911"}.icon-list-alt:before{content:"\e912"}.icon-alter:before,.icon-change:before{content:"\e970"}.icon-glasses:before,.icon-review:before{content:"\e914"}.icon-sitemap:before,.icon-testcase:before{content:"\e915"}.icon-pluses:before{content:"\e917"}.icon-report-list:before{content:"\e918"}.icon-active:before,.icon-magic:before{content:"\e919"}.icon-treemap:before{content:"\e91a"}.icon-confirm:before{content:"\e91b"}.icon-split:before{content:"\e98e"}.icon-calendar:before,.icon-delay:before{content:"\e91d"}.icon-pause:before{content:"\e91e"}.icon-ban:before{content:"\e91f"}.icon-plus-bold:before{content:"\e920"}.icon-copy:before{content:"\e921"}.icon-refresh:before{content:"\e922"}.icon-diff:before{content:"\e9b7"}.icon-scrum:before{content:"\e9a2"}.nav-feature{--nav-active-bg:rgba(var(--color-primary-800-rgb),.07)}.nav-feature .nav-checkbox>.checkbox,.nav-feature .nav-checkbox>.checkbox-primary,.nav-feature .nav-item>a{align-items:center;border-radius:var(--radius);height:2rem;padding-left:.625rem;padding-right:.625rem}.nav-feature .nav-item>a>.icon{--tw-text-opacity:1;color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}[class*=" pri-"],[class^=pri-]{align-items:center;border:1px solid var(--pri-color);border-radius:var(--radius-full);color:var(--pri-color);display:inline-flex;height:1rem;justify-content:center;width:1rem}.pri-1{border:1px solid var(--pri-1-color);color:var(--pri-1-color)}.pri-2{border:1px solid var(--pri-2-color);color:var(--pri-2-color)}.pri-3{border:1px solid var(--pri-3-color);color:var(--pri-3-color)}.pri-4{border:1px solid var(--pri-4-color);color:var(--pri-4-color)}:root{--pri-color:var(--color-gray-500);--pri-1-color:#ff4912;--pri-2-color:var(--color-warning-600);--pri-3-color:var(--color-secondary-600);--pri-4-color:var(--color-gray-500)}.status-active,.status-asked,.status-normal,.status-unconfirmed,.status-wait{color:#313c52}.status-active.status-issue,.status-checking,.status-commenting,.status-confirmed,.status-doing{color:#ff6f42}.status-blocked,.status-hangup,.status-pause,.status-suspended{color:#b89664}.status-clarify,.status-draft{color:#8166ee}.status-noreview,.status-reviewing,.status-wait.status-testcase{color:#18a6fd}.status-active.status-risk,.status-changed,.status-changing,.status-fail{color:#fb2b2b}.status-checked,.status-done,.status-pass,.status-replied,.status-resolved,.status-success{color:#0dbb7d}.status-cancel,.status-canceled,.status-investigate{color:#838a9d}.status-canceled,.status-closed,.status-testtask.status-done{color:#9ea3b0}:root{--avatar-radius:12.5%;--avatar-bg:var(--color-surface)}.avatar{align-items:center;aspect-ratio:1/1;background:var(--avatar-bg);border-radius:var(--avatar-radius);display:inline-flex;justify-content:center;overflow:hidden;width:2rem}.avatar>img{height:100%;margin:0;-o-object-fit:cover;object-fit:cover;width:100%}.avatar.size-xs{width:1.25rem}.avatar.size-sm,.avatar.size-xs{font-size:.75rem;line-height:1rem}.avatar.size-sm{width:1.5rem}.avatar.size-lg{font-size:1.5rem;line-height:2rem;width:3rem}.avatar.size-xl{font-size:2.25rem;line-height:2.5rem;width:5rem}.avatar-group{display:flex;gap:.625rem}.avatar-group>.avatar{box-shadow:0 0 0 1px var(--color-canvas)}.avatar-group>*+*{margin-left:-1rem}.avatar-group.size-xs>*+*{margin-left:-.75rem}.avatar-group.size-sm>*+*{margin-left:-.875rem}.avatar-group.size-lg>*+*{margin-left:-1.25rem}.avatar-group.size-xl>*+*{margin-left:-1.5rem}:root{--modal-radius:var(--radius);--modal-bg:rgba(0,0,0,.4);--modal-sm:18.75rem;--modal-base:37.5rem;--modal-lg:56.25rem}.modal{align-items:center;background:var(--modal-bg);display:none;inset:0;justify-content:center;overflow:hidden;position:fixed}.modal.show{display:flex}.modal-no-backdrop{background-color:var(--color-transparent);pointer-events:none}.modal-dialog{--tw-bg-opacity:1;--tw-shadow:var(--shadow-2xl);--tw-shadow-colored:var(--shadow-2xl);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.05;background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity));border-radius:var(--modal-radius);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);pointer-events:auto;position:relative;width:var(--modal-base)}.modal-content,.modal-dialog{max-height:100vh}.modal-content{display:flex;flex-direction:column;height:100%}.modal-header{align-items:center;display:flex;flex:none;flex-wrap:nowrap;gap:1rem;padding:1rem 1.25rem;position:relative}.modal-title{flex:1 1 auto;font-size:1rem;font-weight:700;line-height:1.5rem}.modal-actions{position:absolute;right:.75rem;top:.75rem}.modal-body{flex:1 1 auto;overflow:auto;padding:.75rem 1.25rem}.modal-footer{align-items:center;display:flex;flex:none;gap:.75rem;padding:1.25rem}.modal-dialog[data-size=full]{height:100vh;width:100vw}.modal-dialog[data-size=sm]{width:var(--modal-sm)}.modal-dialog[data-size=lg]{width:var(--modal-lg)}.modal-iframe{width:100%}.modal-loading-indicator{align-items:center;display:flex;height:100%;justify-content:center;width:100%}.modal-trans{opacity:0;transition-duration:.2s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.modal-trans.in{opacity:1}.modal-trans>.modal-dialog{--tw-scale-x:.95;--tw-scale-y:.95;opacity:0;transition-duration:.3s;transition-property:transform,opacity}.modal-trans.in>.modal-dialog,.modal-trans>.modal-dialog{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.modal-trans.in>.modal-dialog{--tw-scale-x:1;--tw-scale-y:1;opacity:1}:root{--nav-radius:var(--radius);--nav-active-color:var(--color-primary-500);--nav-active-bg:var(--color-inherit);--nav-heading-color:var(--color-gray-500)}.nav,.nav-item{align-items:center;display:flex;position:relative}.nav-item{gap:.75rem}.nav-item>a{align-items:center;color:var(--color-inherit);display:flex;gap:.25rem;height:2rem;justify-content:center;padding-left:1rem;padding-right:1rem}.nav-item>.active{background:var(--nav-active-bg);color:var(--nav-active-color);font-weight:700}.nav-item>.disabled{opacity:1}.nav-item>.disabled>*{opacity:var(--disabled-opacity)}.nav-divider{background-color:var(--color-current);height:1rem;margin-left:.5rem;margin-right:.5rem;opacity:.3;width:1px}.nav-heading{align-items:center;color:var(--nav-heading-color);display:flex;font-weight:700;gap:.25rem;height:2rem;justify-content:center;padding-left:1rem;padding-right:1rem}.nav-space{flex:1 1 auto;width:1rem}.nav-primary>.nav-item{position:relative}.nav-primary>.nav-item:hover{z-index:10}.nav-primary>.nav-item+.nav-item{margin-left:-1px}.nav-primary>.nav-item>a{border-radius:var(--radius-none);border-width:1px}.nav-primary>.nav-item:first-child>a,.nav-primary>.nav-item:has(.nav-heading)+.nav-item>a{border-bottom-left-radius:var(--nav-radius);border-top-left-radius:var(--nav-radius)}.nav-primary>.nav-item:last-child>a{border-bottom-right-radius:var(--nav-radius);border-top-right-radius:var(--nav-radius)}.nav-primary>.nav-item>.active{--tw-text-opacity:1;background:var(--nav-active-color);border-color:var(--nav-active-color);color:rgba(var(--color-canvas-rgb),var(--tw-text-opacity))}.nav-primary>.nav-divider{display:none}.nav-secondary>.nav-item>a{border-radius:var(--radius-none);position:relative}.nav-secondary>.nav-item>a:after{--tw-bg-opacity:1;--tw-content:"";background-color:rgba(var(--color-border-rgb),var(--tw-bg-opacity));bottom:-2px;content:var(--tw-content);display:block;height:2px;left:0;position:absolute;right:0}.nav-secondary>.nav-item>.active:after{background-color:var(--color-current)}.nav-secondary>.nav-divider{margin:0 0 0 -1px}.nav-tabs>.nav-item>a{border-bottom-left-radius:var(--radius-none);border-bottom-right-radius:var(--radius-none);position:relative}.nav-tabs>.nav-item>a:after{--tw-border-opacity:1;--tw-content:"";border-color:var(--color-transparent);border-bottom-color:rgba(var(--color-border-rgb),var(--tw-border-opacity));border-top-left-radius:inherit;border-top-right-radius:inherit;border-width:1px;content:var(--tw-content);display:block;inset:-1px;position:absolute}.nav-tabs>.nav-item>.active:after{--tw-border-opacity:1;border-color:rgba(var(--color-border-rgb),var(--tw-border-opacity));border-bottom-color:var(--color-transparent)}.nav-tabs>.nav-divider{margin:0 0 0 -1px}.nav-pills>.nav-item>a{border-radius:var(--radius-full)}.nav-pills>.nav-item>.active{--tw-text-opacity:1;background:var(--nav-active-color);border-color:var(--nav-active-color);color:rgba(var(--color-canvas-rgb),var(--tw-text-opacity))}.nav-stacked{flex-direction:column}.nav-stacked>.nav-item{width:100%}.nav-stacked>.nav-heading,.nav-stacked>.nav-item>a{justify-content:flex-start;width:100%}.nav-stacked>.nav-divider{height:1px;margin:.5rem 0;width:100%}.nav-primary.nav-stacked>.nav-item>a{height:2.5rem}.nav-primary.nav-stacked>.nav-item+.nav-item{margin-left:0;margin-top:-1px}.nav-primary.nav-stacked>.nav-item:first-child>a{border-bottom-left-radius:0;border-top-left-radius:var(--nav-radius);border-top-right-radius:var(--nav-radius)}.nav-primary.nav-stacked>.nav-item:last-child>a{border-bottom-left-radius:var(--nav-radius);border-bottom-right-radius:var(--nav-radius);border-top-right-radius:0}.nav-secondary.nav-stacked>.nav-item>a:after{--tw-bg-opacity:1;background-color:rgba(var(--color-border-rgb),var(--tw-bg-opacity));bottom:0;height:100%;left:auto;right:0;top:0;width:2px}.nav-secondary.nav-stacked>.nav-item>.active:after{background-color:var(--color-current)}.nav-secondary.nav-stacked>.nav-divider{margin:0}.nav-tabs.nav-stacked>.nav-item>a{border-bottom-left-radius:var(--nav-radius);border-bottom-right-radius:var(--radius-none);border-top-right-radius:var(--radius-none);position:relative}.nav-tabs.nav-stacked>.nav-item>a:after{--tw-border-opacity:1;border-bottom-color:var(--color-transparent);border-bottom-left-radius:inherit;border-right-color:rgba(var(--color-border-rgb),var(--tw-border-opacity));border-top-left-radius:inherit}.nav-tabs.nav-stacked>.nav-item>a.active:after{--tw-border-opacity:1;border-color:rgba(var(--color-border-rgb),var(--tw-border-opacity));border-right-color:var(--color-transparent)}.nav-tabs.nav-stacked>.nav-divider{margin:0}.nav-pills.nav-stacked>.nav-item+.nav-item{margin-top:.25rem}.nav-justified>.nav-item:not(.flex-none,.nav-divider){flex:1 1 auto}.nav-justified>.nav-item>a{width:100%}.pager{align-items:center;display:flex;gap:.25rem}.menu.pager-size-menu{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));text-align:center}.menu.pager-size-menu>.menu-item>a{margin:.125rem}.pager .pager-goto-group>.form-control{width:3rem}.pager .pager-goto-group>.input-group-addon{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity));border-color:rgba(var(--color-gray-300-rgb),var(--tw-border-opacity));border-width:1px}.pager>.pager-nav.active{--tw-text-opacity:1;box-shadow:0 0 0 1px var(--color-primary-500);color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}.panel{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.05;border-radius:var(--radius);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);overflow:hidden}.panel-heading{flex-wrap:nowrap;gap:1rem;justify-content:space-between;padding:.5rem 1rem}.panel-heading,.panel-title{align-items:center;display:flex}.panel-title{font-weight:700;gap:.5rem;margin:0}.panel-actions{margin-right:-.5rem}.panel-body{padding:.75rem 1rem}.panel-footer{align-items:center;display:flex;gap:.5rem;padding:.5rem 1rem}.size-sm .panel-body,.size-sm .panel-footer,.size-sm .panel-heading{padding:.375rem .75rem}.size-lg .panel-body,.size-lg .panel-footer,.size-lg .panel-heading{padding:1rem 1.25rem}.picker{position:relative}.picker-select{align-items:center;display:flex;gap:.25rem;justify-content:space-between}.picker-select.form-control{display:flex}.picker-select-placeholder{flex:1 1 auto}.picker-single-selection{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap}.picker-deselect-btn{border-radius:var(--radius);padding:.25rem}.picker-select-multi.form-control{height:auto;min-height:32px;padding-left:.25rem}.picker-multi-selections{display:flex;flex-wrap:wrap;gap:.25rem}.picker-multi-selection{--tw-bg-opacity:1;align-items:center;background-color:rgba(var(--color-surface-rgb),var(--tw-bg-opacity));border-radius:var(--radius);border-width:1px;display:flex;padding-left:.25rem}.picker-menu{background:var(--menu-bg);border:var(--menu-border);border-radius:var(--menu-radius);box-shadow:var(--menu-shadow);display:flex;flex-direction:column;opacity:0;position:absolute;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);z-index:50}.picker-menu.shown{opacity:1}.picker-menu-search{flex:none;margin-top:.5rem;padding-left:.5rem;padding-right:.5rem;position:relative}.picker-menu-search>.magnifier{opacity:.5;position:absolute;right:1rem;top:.625rem}.picker-menu-search-clear.btn{cursor:pointer;height:1.25rem;position:absolute;right:.5rem;top:.375rem;width:1.25rem}.picker-menu-list.menu{--tw-shadow:var(--shadow-none);--tw-shadow-colored:var(--shadow-none);border-style:none;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);flex:1 1 auto}.picker-menu-item-match{font-weight:700;text-decoration-line:underline}:root{--table-head-bg:var(--color-surface);--table-striped-color:var(--color-gray-50);--table-hover-color:rgba(var(--color-primary-500-rgb),.05);--table-border-color:var(--color-border)}.table{border-color:var(--table-border-color);width:100%}.table>thead{background-color:var(--table-head-bg)}.table>*>tr{border-bottom-width:1px}.table>*>tr>*{padding:.5rem 1rem;text-align:left}.table-striped>tbody>tr:nth-child(2n){background:var(--table-striped-color)}.table-hover>tbody>tr:hover>*{background:var(--table-hover-color)}.table.bordered>*>tr>*{border-width:1px}.table.borderless>*>tr,.table.borderless>*>tr>*{border-style:none}.condensed>*>tr>*{padding:.375rem .75rem}.table-fixed{table-layout:fixed}.table-fixed>*>tr>*{overflow:hidden;white-space:nowrap}.tooltip{--tw-text-opacity:1;border-radius:var(--radius);color:rgba(var(--color-white-rgb),var(--tw-text-opacity));display:none;font-size:.75rem;line-height:1rem;opacity:0;padding:.25rem .5rem;z-index:30}.btn.with-tooltip-show{--tw-shadow:var(--shadow-inner);--tw-shadow-colored:var(--shadow-inner);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.tooltip>.arrow-top{margin-bottom:1px}.tooltip>.arrow-bottom{margin-top:1px}.tooltip>.arrow-left{margin-right:1px}.tooltip>.arrow-right{margin-left:1px}.tooltip.fade{transition-delay:.15s;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:linear}.tooltip .arrow,.tooltip.fade{opacity:0}.tooltip.show,.tooltip.show .arrow{display:block;opacity:1}.tab-content>.tab-pane{display:none;padding:.5rem .75rem}.tab-content>.active{display:block}.fade{opacity:0;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.fade.in{opacity:1}.quick-menu{border:1px solid rgba(0,0,0,.15);border-radius:4px;box-shadow:0 6px 12px #0000001f,0 1px 3px #0000001a;box-sizing:border-box}.quick-menu .menu{border:none;box-shadow:none}.quick-menu .has-nested-menu>.menu.menu-nested{background:none}.search-form{--tw-bg-opacity:1;background-color:rgba(var(--color-white-rgb),var(--tw-bg-opacity));border-radius:var(--radius);display:flex;margin-bottom:.5rem;overflow-x:auto;padding:.5rem;width:100%}.search-form-items{display:table;width:100%}.search-form-content{flex:1 1 0%}.search-form-items>.search-col{display:table-cell;width:45%}.search-form-items>.search-col+.search-col{padding-left:.5rem}.search-form-items>.search-col:nth-child(2){vertical-align:middle;width:5rem}.search-form-items>.search-col .search-group{align-items:center;display:flex;gap:.25rem;margin-bottom:.25rem;margin-top:.25rem;width:100%}.search-form-items>.search-col .search-group>.group-name{text-align:right;width:5rem}.search-form-items>.search-col .search-group>.group-select{flex:1 1 0%;min-width:4.8rem}.search-form-items>.search-col .search-group>.group-select+.group-select{max-width:4.8rem}.search-form-items>.search-col .search-group>.group-value{flex:3}.search-form .btn{margin-left:.25rem;margin-right:.25rem;margin-top:.5rem}.search-form .search-toggle-btn{--tw-text-opacity:1;background:#79cdfb;border-radius:var(--radius-full);border-style:none;color:rgba(var(--color-white-rgb),var(--tw-text-opacity));height:1.5rem;line-height:1.25rem;margin-top:1.5rem;padding-left:.125rem;padding-right:.125rem;text-align:center;width:.625rem}.search-form-footer{position:relative}.search-form-footer .save-bar{position:absolute;right:0;top:0}.search-form-footer .save-bar .btn{background-color:var(--color-transparent);border-style:none;margin:0;padding:.25rem}.history-record{border-left:1px solid #eee;max-width:9rem;min-width:7rem;padding:.625rem;width:10rem}.history-record.hidden,.search-form-items>.search-col .search-group.hidden{display:none}.history-record .labels{max-height:7rem;overflow-y:scroll}.history-record .labels .label-btn{margin-bottom:.5rem;margin-top:.5rem}.history-record .labels .label-btn .label{border-radius:var(--radius-full);cursor:pointer;padding:.25rem .5rem}.history-record .labels .label-btn .label:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgba(var(--color-gray-600-rgb),var(--tw-bg-opacity));color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.history-record .labels .label-btn .label .icon-close{border-radius:var(--radius-full);display:inline-block;height:1rem;line-height:1rem;margin-left:.25rem;text-align:center;width:1rem}.history-record .labels .label-btn .label .icon-close:hover{--tw-bg-opacity:1;background-color:rgba(var(--color-danger-400-rgb),var(--tw-bg-opacity))}:root{--scrollbar-size:10px;--scrollbar-opacity:.6;--scrollbar-bg:rgba(var(--color-inverse-rgb),.15);--scrollbar-inset:inset 0 0 0 1px rgba(var(--color-inverse-rgb),.05);--scrollbar-bar-bg:rgba(var(--color-inverse-rgb),.3);--scrollbar-hover-bg:rgba(var(--color-inverse-rgb),.4);--scrollbar-drag-bg:rgba(var(--color-inverse-rgb),.5);--scrollbar-radius:var(--radius-sm);--scrollbar-duration:.7s}.scrollbar{background:var(--scrollbar-bg);box-shadow:var(--scrollbar-shadow);opacity:var(--scrollbar-opacity);position:absolute;transition-duration:.15s;transition-duration:var(--scrollbar-duration);transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.scrollbar-hover .scrollbar{opacity:0}.scrollbar-hover:hover .scrollbar{opacity:var(--scrollbar-opacity)}.scrollbar.is-dragging,.scrollbar:hover{opacity:1!important}.scrollbar-bar{background:var(--scrollbar-bar-bg);border-radius:var(--scrollbar-radius);position:absolute}.scrollbar-bar:hover{background:var(--scrollbar-hover-bg)}.is-dragging>.scrollbar-bar{background:var(--scrollbar-drag-bg)}.is-horz>.scrollbar-bar{height:100%;z-index:20}.is-vert>.scrollbar-bar{width:100%;z-index:20}:root{--dtable-bg:var(--color-canvas);--dtable-striped-bg:var(--color-gray-50);--dtable-hover-bg:rgba(var(--color-gray-500-rgb),.1);--dtable-header-bg:var(--color-surface);--dtable-footer-bg:var(--color-surface);--dtable-border-color:var(--color-border);--dtable-sorter-size:.3125rem}.dtable{outline:2px solid transparent;outline-offset:2px}.dtable,.dtable-header{position:relative}.dtable-header{background:var(--dtable-header-bg);border-top-left-radius:inherit;border-top-right-radius:inherit;overflow:hidden;z-index:20}.dtable-rows{overflow:hidden;z-index:10}.dtable-row,.dtable-rows{position:absolute;width:100%}.dtable-cells{background:var(--dtable-bg);height:100%;position:absolute;z-index:0}.dtable-header .dtable-cells{background:var(--dtable-header-bg)}.dtable-cells.dtable-fixed-left,.dtable-cells.dtable-fixed-right{z-index:10}.dtable-cell{height:100%;position:absolute}.dtable-cell:after,.dtable-cell:before{border:0 solid var(--dtable-border-color);bottom:-1px;content:" ";left:0;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.dtable-row>.dtable-cells:last-child>.dtable-cell:last-child:after,.dtable-row>.dtable-cells:last-child>.dtable-cell:last-child:before{right:0}.dtable-header .dtable-cell:after,.dtable-header .dtable-cell:before{top:0}.dtable-header .dtable-cell{align-items:center;display:flex;font-weight:700}.dtable-cell-content{gap:.25rem;height:100%;overflow:hidden;padding-left:.75rem;padding-right:.75rem;white-space:nowrap}.dtable-cell-content,.dtable-footer{align-items:center;display:flex;width:100%}.dtable-footer{background:var(--dtable-footer-bg);border-top-left-radius:inherit;border-top-right-radius:inherit;position:absolute}.dtable .scrollbar,.dtable-footer{z-index:10}.dtable-scrolled-down .dtable-header{--tw-shadow:var(--shadow-md);--tw-shadow-colored:var(--shadow-md);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.dtable-cell[data-sort]{cursor:pointer}.dtable-sort{height:calc(var(--dtable-sorter-size)*12/5);margin-left:.25rem;opacity:.8;position:relative}.dtable-cell:hover .dtable-sort{opacity:1}.dtable-sort:after,.dtable-sort:before{border-color:var(--color-transparent);border-style:solid;border-width:var(--dtable-sorter-size);content:" ";height:0;left:0;opacity:.4;position:absolute;width:0}.dtable-sort:before{border-bottom-color:var(--color-current);border-top-width:0;top:0}.dtable-sort:after{border-bottom-width:0;border-top-color:var(--color-current);bottom:0}.dtable-sort.dtable-sort-asc:before,.dtable-sort.dtable-sort-desc:after{opacity:.9}.dtable-row{border-bottom-width:1px;border-color:var(--dtable-border-color)}.dtable-cells.dtable-fixed-left:before,.dtable-cells.dtable-fixed-right:before{border-color:var(--color-inherit);border-color:var(--dtable-border-color);content:" ";height:100%;pointer-events:none;position:absolute;width:100%}.dtable-cells.dtable-fixed-left:before{border-right-width:1px;right:-1px}.dtable-cells.dtable-fixed-right:before{border-left-width:1px;left:0}.dtable-bordered .dtable-cell:after{border-width:1px;opacity:1}.dtable-cell.has-border-left:after{border-left-width:1px;opacity:1}.dtable-cell.has-border-right:after{border-right-width:1px;opacity:1}.dtable-bordered .dtable-header:after,.dtable-bordered .dtable-rows:after{border-color:var(--dtable-border-color);border-width:1px;bottom:0;content:" ";left:0;pointer-events:none;position:absolute;right:0;top:-1px;z-index:20}.dtable-bordered .dtable-header:after{top:0}.dtable-striped .dtable-rows>.dtable-row-odd>.dtable-cells{background:var(--dtable-striped-bg)}.dtable-cell.dtable-col-hover,.dtable-hover-row .dtable-rows>.dtable-row:hover .dtable-cell{background:var(--dtable-hover-bg)}.dtable-hover-cell .dtable-rows .dtable-cell:hover:after{background:var(--dtable-hover-bg);opacity:1}:root{--dtable-checked-bg:var(--color-warning-100)}.dtable-rows>.dtable-row.is-checked>.dtable-cells{background:var(--dtable-checked-bg)}:root{--dtable-nt-size:calc(var(--root-font-size)*3/4 + 1px)}.dtable-nested-indent{flex:none;margin-right:-.25rem;order:-10}.dtable-nested-toggle{align-items:center;border-radius:var(--radius-sm);display:flex;flex:none;height:1.25rem;justify-content:center;margin-left:-.25rem;order:-1;width:1.25rem}.dtable-nested-toggle.is-no-child{display:none}.dtable{--dtable-header-bg:var(--color-slate-50);--dtable-footer-bg:var(--color-slate-50);--dtable-border-color:var(--color-slate-100)}.dtable-header .dtable-cell{font-weight:400}.dtable-rows a:visited{--tw-text-opacity:1;color:rgba(var(--color-link-visited-rgb),var(--tw-text-opacity))}.dtable-rows a:hover{--tw-text-opacity:1;color:rgba(var(--color-link-hover-rgb),var(--tw-text-opacity))}.dtable .btn-avatar{--tw-bg-opacity:1;--tw-ring-color:var(--color-transparent);background-color:rgb(241 245 249/var(--tw-bg-opacity));border-radius:var(--radius-full);gap:.25rem;height:1.25rem;padding-left:0;padding-right:.5rem}.dtable .btn-avatar:hover{--tw-shadow:var(--shadow);--tw-shadow-colored:var(--shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.dtable .toggle-icon{border-radius:var(--radius-full)}.dtable .toggle-icon:after,.dtable .toggle-icon:before{--tw-bg-opacity:1;background-color:rgba(var(--color-fore-rgb),var(--tw-bg-opacity))}.dtable-footer{border-top:1px sold var(--dtable-border-color);padding-left:.75rem;padding-right:.75rem}.dtable-footer>.toolbar{margin-right:.5rem}.dtable-header .dtable-cell[data-sort]>.dtable-cell-content:not(:hover){color:var(--color-inherit)}.arrow,.arrow:before{background:inherit;height:calc(var(--arrow-size)*2);position:absolute;width:calc(var(--arrow-size)*2)}.arrow{--arrow-size:5px;visibility:hidden}.arrow:before{--tw-rotate:45deg;border:inherit;content:"";transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));visibility:visible}.arrow-top{border-bottom:inherit;border-right:inherit;bottom:calc(-1px - var(--arrow-size))}.arrow-bottom{border-left:inherit;border-top:inherit;top:calc(-1px - var(--arrow-size))}.arrow-left{border-right:inherit;border-top:inherit;right:calc(-1px - var(--arrow-size))}.arrow-right{border-bottom:inherit;border-left:inherit;left:calc(-1px - var(--arrow-size))}.caret,.caret-down,.caret-left,.caret-right,.caret-up{border:var(--caret-size,4px) solid transparent;display:inline-block;height:0;opacity:var(--caret-opacity,.5);width:0}:focus>.caret,:hover>.caret{opacity:inherit}.caret,.caret-down{border-bottom-width:0;border-top-color:currentColor}.caret-up{border-bottom-color:currentColor;border-top-width:0}.caret-right{border-left-color:currentColor;border-right-width:0}.caret-left{border-left-width:0;border-right-color:currentColor}:root{--toggle-icon-size:calc(var(--root-font-size)*3/4 + 1px)}.toggle-icon,.toggle-icon-collapse,.toggle-icon-expand{border-color:var(--color-current);border-width:1px;display:block;opacity:.5;position:relative}.toggle-icon-collapse:hover,.toggle-icon-expand:hover,.toggle-icon:hover{opacity:.9}.toggle-icon,.toggle-icon-collapse,.toggle-icon-expand{border-radius:inherit;height:var(--toggle-icon-size);width:var(--toggle-icon-size)}.is-collapsed .toggle-icon:after,.is-collapsed .toggle-icon:before,.is-expanded .toggle-icon:before,.toggle-icon-collapse:after,.toggle-icon-collapse:before,.toggle-icon-expand:before{background-color:var(--color-current);content:" ";display:block;height:1px;left:2px;position:absolute;right:2px;top:calc((var(--toggle-icon-size) - 3px)/2)}.is-collapsed .toggle-icon:after,.toggle-icon-collapse:after{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.close{aspect-ratio:1/1;display:block;position:relative;width:1em}.close:after,.close:before{--tw-rotate:45deg;background-color:var(--color-current);border-radius:var(--radius-full);content:"";display:block;height:1px;left:0;position:absolute;top:calc(50% - .5px);width:100%}.close:after,.close:before{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.close:after{--tw-rotate:-45deg}.spinner,.spinner:after,.spinner:before{display:block;height:1em;position:relative;width:1em}.spinner:after,.spinner:before{border-radius:var(--radius-full);content:" ";position:absolute}.spinner:before{animation:-spin 1s cubic-bezier(.6,0,.4,1) infinite;border:.16667em solid transparent;border-top-color:currentcolor}.spinner:after{border:.16667em solid;opacity:.2}.magnifier{display:inline-block;height:1em;position:relative;width:1em}.magnifier:after,.magnifier:before{border-radius:var(--radius-full);content:"";display:block;position:absolute}.magnifier:before{border:1px solid;height:.75em;width:.75em}.magnifier:after{--tw-rotate:45deg;background-color:var(--color-current);height:1px;left:.55em;top:.7em;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));width:.5em}:root{--state-color:rgba(0,0,0,.05);--state-scale:.9;--state-active-color:rgba(0,0,0,.1);--state-focus-color:rgba(0,0,0,.125);--state-disabled-opacity:.65;--state-muted-opacity:.5}.aspect-auto{aspect-ratio:auto}.aspect-square{aspect-ratio:1/1}.aspect-video{aspect-ratio:16/9}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.container{margin-left:auto;margin-right:auto}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.table-cell{display:table-cell}.table-row{display:table-row}.list-item{display:list-item}.hidden{display:none!important}.pull-right{float:right}.pull-left{float:left}.clearfix:after{clear:both;content:"";display:block}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.object-fill{-o-object-fit:fill;object-fit:fill}.object-none{-o-object-fit:none;object-fit:none}.object-scale-down{-o-object-fit:scale-down;object-fit:scale-down}.of-auto{overflow:auto}.of-hidden{overflow:hidden}.of-clip{overflow:clip}.of-visible{overflow:visible}.of-scroll{overflow:scroll}.of-x-auto{overflow-x:auto}.of-y-auto{overflow-y:auto}.of-x-hidden{overflow-x:hidden}.of-y-hidden{overflow-y:hidden}.of-x-clip{overflow-x:clip}.of-y-clip{overflow-y:clip}.of-x-visible{overflow-x:visible}.of-y-visible{overflow-y:visible}.of-x-scroll{overflow-x:scroll}.of-y-scroll{overflow-y:scroll}.of-overlay{overflow:overlay}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-auto{inset:auto}.inset-x-0{left:0;right:0}.inset-y-0{bottom:0;top:0}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.top-full{top:100%}.right-full{right:100%}.bottom-full{bottom:100%}.left-full{left:100%}.top-auto{top:auto}.right-auto{right:auto}.bottom-auto{bottom:auto}.left-auto{left:auto}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-auto{z-index:auto}.basis-0{flex-basis:0px}.basis-1{flex-basis:.25rem}.basis-2{flex-basis:.5rem}.basis-3{flex-basis:.75rem}.basis-4{flex-basis:1rem}.basis-5{flex-basis:1.25rem}.basis-6{flex-basis:1.5rem}.basis-7{flex-basis:1.75rem}.basis-8{flex-basis:2rem}.basis-9{flex-basis:2.25rem}.basis-10{flex-basis:2.5rem}.basis-11{flex-basis:2.75rem}.basis-12{flex-basis:3rem}.basis-14{flex-basis:3.5rem}.basis-16{flex-basis:4rem}.basis-20{flex-basis:5rem}.basis-24{flex-basis:6rem}.basis-28{flex-basis:7rem}.basis-32{flex-basis:8rem}.basis-36{flex-basis:9rem}.basis-40{flex-basis:10rem}.basis-44{flex-basis:11rem}.basis-48{flex-basis:12rem}.basis-52{flex-basis:13rem}.basis-56{flex-basis:14rem}.basis-60{flex-basis:15rem}.basis-64{flex-basis:16rem}.basis-72{flex-basis:18rem}.basis-80{flex-basis:20rem}.basis-96{flex-basis:24rem}.basis-auto{flex-basis:auto}.basis-px{flex-basis:1px}.basis-0\.5{flex-basis:.125rem}.basis-1\.5{flex-basis:.375rem}.basis-2\.5{flex-basis:.625rem}.basis-3\.5{flex-basis:.875rem}.basis-1\/2{flex-basis:50%}.basis-1\/3{flex-basis:33.333333%}.basis-2\/3{flex-basis:66.666667%}.basis-1\/4{flex-basis:25%}.basis-2\/4{flex-basis:50%}.basis-3\/4{flex-basis:75%}.basis-1\/5{flex-basis:20%}.basis-2\/5{flex-basis:40%}.basis-3\/5{flex-basis:60%}.basis-4\/5{flex-basis:80%}.basis-1\/6{flex-basis:16.666667%}.basis-2\/6{flex-basis:33.333333%}.basis-3\/6{flex-basis:50%}.basis-4\/6{flex-basis:66.666667%}.basis-5\/6{flex-basis:83.333333%}.basis-1\/12{flex-basis:8.333333%}.basis-2\/12{flex-basis:16.666667%}.basis-3\/12{flex-basis:25%}.basis-4\/12{flex-basis:33.333333%}.basis-5\/12{flex-basis:41.666667%}.basis-6\/12{flex-basis:50%}.basis-7\/12{flex-basis:58.333333%}.basis-8\/12{flex-basis:66.666667%}.basis-9\/12{flex-basis:75%}.basis-10\/12{flex-basis:83.333333%}.basis-11\/12{flex-basis:91.666667%}.basis-full{flex-basis:100%}.row{display:flex;flex-direction:row}.center,.col{display:flex;flex-direction:column}.center,.center-row{align-items:center;justify-content:center}.center-row{display:flex;flex-direction:row}.center-x,.center-y{align-items:center;display:flex}.center-y{flex-direction:column}.row-reverse{display:flex;flex-direction:row-reverse}.col-reverse{display:flex;flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.flex-wrap-reverse{flex-wrap:wrap-reverse}.flex-nowrap{flex-wrap:nowrap}.flex-1{flex:1 1 0%}.flex-auto{flex:1 1 auto}.flex-initial{flex:0 1 auto}.flex-none{flex:none}.grow{flex-grow:1!important}.grow-0{flex-grow:0!important}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.order-first{order:-9999}.order-last{order:9999}.order-none{order:0}.gap-0{gap:0}.gap-x-0{-moz-column-gap:0;column-gap:0}.gap-y-0{row-gap:0}.gap-px{gap:1px}.gap-x-px{-moz-column-gap:1px;column-gap:1px}.gap-y-px{row-gap:1px}.gap-0\.5{gap:.125rem}.gap-x-0\.5{-moz-column-gap:.125rem;column-gap:.125rem}.gap-y-0\.5{row-gap:.125rem}.gap-1{gap:.25rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-y-1{row-gap:.25rem}.gap-1\.5{gap:.375rem}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-y-1\.5{row-gap:.375rem}.gap-2{gap:.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-2{row-gap:.5rem}.gap-2\.5{gap:.625rem}.gap-x-2\.5{-moz-column-gap:.625rem;column-gap:.625rem}.gap-y-2\.5{row-gap:.625rem}.gap-3{gap:.75rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-3{row-gap:.75rem}.gap-3\.5{gap:.875rem}.gap-x-3\.5{-moz-column-gap:.875rem;column-gap:.875rem}.gap-y-3\.5{row-gap:.875rem}.gap-4{gap:1rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-4{row-gap:1rem}.gap-5{gap:1.25rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-y-5{row-gap:1.25rem}.gap-6{gap:1.5rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-6{row-gap:1.5rem}.gap-7{gap:1.75rem}.gap-x-7{-moz-column-gap:1.75rem;column-gap:1.75rem}.gap-y-7{row-gap:1.75rem}.gap-8{gap:2rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.gap-y-8{row-gap:2rem}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}.self-auto{align-self:auto}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-stretch{align-self:stretch}.self-baseline{align-self:baseline}.content-center{align-content:center}.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-between{align-content:space-between}.content-around{align-content:space-around}.content-evenly{align-content:space-evenly}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.m-0{margin:0}.mx-0{margin-left:0;margin-right:0}.my-0{margin-bottom:0}.mt-0,.my-0{margin-top:0}.mr-0{margin-right:0}.mb-0{margin-bottom:0}.ml-0{margin-left:0}.m-auto{margin:auto}.mx-auto{margin-left:auto;margin-right:auto}.my-auto{margin-bottom:auto}.mt-auto,.my-auto{margin-top:auto}.mr-auto{margin-right:auto}.mb-auto{margin-bottom:auto}.ml-auto{margin-left:auto}.m-px{margin:1px}.mx-px{margin-left:1px;margin-right:1px}.my-px{margin-bottom:1px}.mt-px,.my-px{margin-top:1px}.mr-px{margin-right:1px}.mb-px{margin-bottom:1px}.ml-px{margin-left:1px}.m-0\.5{margin:.125rem}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.my-0\.5{margin-bottom:.125rem}.mt-0\.5,.my-0\.5{margin-top:.125rem}.mr-0\.5{margin-right:.125rem}.mb-0\.5{margin-bottom:.125rem}.ml-0\.5{margin-left:.125rem}.m-1{margin:.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.my-1{margin-bottom:.25rem}.mt-1,.my-1{margin-top:.25rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.ml-1{margin-left:.25rem}.m-1\.5{margin:.375rem}.mx-1\.5{margin-left:.375rem;margin-right:.375rem}.my-1\.5{margin-bottom:.375rem}.mt-1\.5,.my-1\.5{margin-top:.375rem}.mr-1\.5{margin-right:.375rem}.mb-1\.5{margin-bottom:.375rem}.ml-1\.5{margin-left:.375rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem}.mt-2,.my-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.m-2\.5{margin:.625rem}.mx-2\.5{margin-left:.625rem;margin-right:.625rem}.my-2\.5{margin-bottom:.625rem}.mt-2\.5,.my-2\.5{margin-top:.625rem}.mr-2\.5{margin-right:.625rem}.mb-2\.5{margin-bottom:.625rem}.ml-2\.5{margin-left:.625rem}.m-3{margin:.75rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.my-3{margin-bottom:.75rem}.mt-3,.my-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.ml-3{margin-left:.75rem}.m-3\.5{margin:.875rem}.mx-3\.5{margin-left:.875rem;margin-right:.875rem}.my-3\.5{margin-bottom:.875rem}.mt-3\.5,.my-3\.5{margin-top:.875rem}.mr-3\.5{margin-right:.875rem}.mb-3\.5{margin-bottom:.875rem}.ml-3\.5{margin-left:.875rem}.m-4{margin:1rem}.mx-4{margin-left:1rem;margin-right:1rem}.my-4{margin-bottom:1rem}.mt-4,.my-4{margin-top:1rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.ml-4{margin-left:1rem}.m-5{margin:1.25rem}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.my-5{margin-bottom:1.25rem}.mt-5,.my-5{margin-top:1.25rem}.mr-5{margin-right:1.25rem}.mb-5{margin-bottom:1.25rem}.ml-5{margin-left:1.25rem}.m-6{margin:1.5rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.my-6{margin-bottom:1.5rem}.mt-6,.my-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mb-6{margin-bottom:1.5rem}.ml-6{margin-left:1.5rem}.m-7{margin:1.75rem}.mx-7{margin-left:1.75rem;margin-right:1.75rem}.my-7{margin-bottom:1.75rem}.mt-7,.my-7{margin-top:1.75rem}.mr-7{margin-right:1.75rem}.mb-7{margin-bottom:1.75rem}.ml-7{margin-left:1.75rem}.m-8{margin:2rem}.mx-8{margin-left:2rem;margin-right:2rem}.my-8{margin-bottom:2rem}.mt-8,.my-8{margin-top:2rem}.mr-8{margin-right:2rem}.mb-8{margin-bottom:2rem}.ml-8{margin-left:2rem}.p-0{padding:0}.px-0{padding-left:0;padding-right:0}.py-0{padding-bottom:0}.pt-0,.py-0{padding-top:0}.pr-0{padding-right:0}.pb-0{padding-bottom:0}.pl-0{padding-left:0}.p-px{padding:1px}.px-px{padding-left:1px;padding-right:1px}.py-px{padding-bottom:1px}.pt-px,.py-px{padding-top:1px}.pr-px{padding-right:1px}.pb-px{padding-bottom:1px}.pl-px{padding-left:1px}.p-0\.5{padding:.125rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.py-0\.5{padding-bottom:.125rem}.pt-0\.5,.py-0\.5{padding-top:.125rem}.pr-0\.5{padding-right:.125rem}.pb-0\.5{padding-bottom:.125rem}.pl-0\.5{padding-left:.125rem}.p-1{padding:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-1{padding-bottom:.25rem}.pt-1,.py-1{padding-top:.25rem}.pr-1{padding-right:.25rem}.pb-1{padding-bottom:.25rem}.pl-1{padding-left:.25rem}.p-1\.5{padding:.375rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.py-1\.5{padding-bottom:.375rem}.pt-1\.5,.py-1\.5{padding-top:.375rem}.pr-1\.5{padding-right:.375rem}.pb-1\.5{padding-bottom:.375rem}.pl-1\.5{padding-left:.375rem}.p-2{padding:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-2{padding-bottom:.5rem}.pt-2,.py-2{padding-top:.5rem}.pr-2{padding-right:.5rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.p-2\.5{padding:.625rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.py-2\.5{padding-bottom:.625rem}.pt-2\.5,.py-2\.5{padding-top:.625rem}.pr-2\.5{padding-right:.625rem}.pb-2\.5{padding-bottom:.625rem}.pl-2\.5{padding-left:.625rem}.p-3{padding:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-3{padding-bottom:.75rem}.pt-3,.py-3{padding-top:.75rem}.pr-3{padding-right:.75rem}.pb-3{padding-bottom:.75rem}.pl-3{padding-left:.75rem}.p-3\.5{padding:.875rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.py-3\.5{padding-bottom:.875rem}.pt-3\.5,.py-3\.5{padding-top:.875rem}.pr-3\.5{padding-right:.875rem}.pb-3\.5{padding-bottom:.875rem}.pl-3\.5{padding-left:.875rem}.p-4{padding:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-4{padding-bottom:1rem}.pt-4,.py-4{padding-top:1rem}.pr-4{padding-right:1rem}.pb-4{padding-bottom:1rem}.pl-4{padding-left:1rem}.p-5{padding:1.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-bottom:1.25rem}.pt-5,.py-5{padding-top:1.25rem}.pr-5{padding-right:1.25rem}.pb-5{padding-bottom:1.25rem}.pl-5{padding-left:1.25rem}.p-6{padding:1.5rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-6{padding-bottom:1.5rem}.pt-6,.py-6{padding-top:1.5rem}.pr-6{padding-right:1.5rem}.pb-6{padding-bottom:1.5rem}.pl-6{padding-left:1.5rem}.p-7{padding:1.75rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.py-7{padding-bottom:1.75rem}.pt-7,.py-7{padding-top:1.75rem}.pr-7{padding-right:1.75rem}.pb-7{padding-bottom:1.75rem}.pl-7{padding-left:1.75rem}.p-8{padding:2rem}.px-8{padding-left:2rem;padding-right:2rem}.py-8{padding-bottom:2rem}.pt-8,.py-8{padding-top:2rem}.pr-8{padding-right:2rem}.pb-8{padding-bottom:2rem}.pl-8{padding-left:2rem}.space-x-0>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(0px*(1 - var(--tw-space-x-reverse)));margin-right:calc(0px*var(--tw-space-x-reverse))}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.space-x-0\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.125rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.125rem*var(--tw-space-x-reverse))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.125rem*var(--tw-space-y-reverse));margin-top:calc(.125rem*(1 - var(--tw-space-y-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.25rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-x-1\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.375rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.375rem*var(--tw-space-x-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.375rem*var(--tw-space-y-reverse));margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-x-2\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.625rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.625rem*var(--tw-space-x-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.625rem*var(--tw-space-y-reverse));margin-top:calc(.625rem*(1 - var(--tw-space-y-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-x-3\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.875rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.875rem*var(--tw-space-x-reverse))}.space-y-3\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.875rem*var(--tw-space-y-reverse));margin-top:calc(.875rem*(1 - var(--tw-space-y-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1.25rem*var(--tw-space-x-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.space-x-6>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1.5rem*var(--tw-space-x-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.5rem*var(--tw-space-y-reverse));margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)))}.space-x-7>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1.75rem*var(--tw-space-x-reverse))}.space-y-7>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.75rem*var(--tw-space-y-reverse));margin-top:calc(1.75rem*(1 - var(--tw-space-y-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(2rem*var(--tw-space-x-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(2rem*var(--tw-space-y-reverse));margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)))}.w-0{width:0}.w-px{width:1px}.w-0\.5{width:.125rem}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-32{width:8rem}.w-36{width:9rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-52{width:13rem}.w-56{width:14rem}.w-60{width:15rem}.w-64{width:16rem}.w-72{width:18rem}.w-80{width:20rem}.w-96{width:24rem}.w-auto{width:auto}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-2\/3{width:66.666667%}.w-1\/4{width:25%}.w-2\/4{width:50%}.w-3\/4{width:75%}.w-1\/5{width:20%}.w-2\/5{width:40%}.w-3\/5{width:60%}.w-4\/5{width:80%}.w-1\/6{width:16.666667%}.w-2\/6{width:33.333333%}.w-3\/6{width:50%}.w-4\/6{width:66.666667%}.w-5\/6{width:83.333333%}.w-1\/12{width:8.333333%}.w-2\/12{width:16.666667%}.w-3\/12{width:25%}.w-4\/12{width:33.333333%}.w-5\/12{width:41.666667%}.w-6\/12{width:50%}.w-7\/12{width:58.333333%}.w-8\/12{width:66.666667%}.w-9\/12{width:75%}.w-10\/12{width:83.333333%}.w-11\/12{width:91.666667%}.w-full{width:100%}.w-screen{width:100vw}.w-min{width:-moz-min-content;width:min-content}.w-max{width:-moz-max-content;width:max-content}.w-fit{width:-moz-fit-content;width:fit-content}.max-w-full{max-width:100%}.h-0{height:0}.h-px{height:1px}.h-0\.5{height:.125rem}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-24{height:6rem}.h-28{height:7rem}.h-32{height:8rem}.h-36{height:9rem}.h-40{height:10rem}.h-44{height:11rem}.h-48{height:12rem}.h-52{height:13rem}.h-56{height:14rem}.h-60{height:15rem}.h-64{height:16rem}.h-72{height:18rem}.h-80{height:20rem}.h-96{height:24rem}.h-auto{height:auto}.h-1\/2{height:50%}.h-1\/3{height:33.333333%}.h-2\/3{height:66.666667%}.h-1\/4{height:25%}.h-2\/4{height:50%}.h-3\/4{height:75%}.h-1\/5{height:20%}.h-2\/5{height:40%}.h-3\/5{height:60%}.h-4\/5{height:80%}.h-1\/6{height:16.666667%}.h-2\/6{height:33.333333%}.h-3\/6{height:50%}.h-4\/6{height:66.666667%}.h-5\/6{height:83.333333%}.h-full{height:100%}.h-screen{height:100vh}.h-min{height:-moz-min-content;height:min-content}.h-max{height:-moz-max-content;height:max-content}.h-fit{height:-moz-fit-content;height:fit-content}.primary-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-primary-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}.primary-outline,.secondary-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.secondary-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-secondary-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-secondary-500-rgb),var(--tw-text-opacity))}.success-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-success-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-success-500-rgb),var(--tw-text-opacity))}.success-outline,.warning-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.warning-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-warning-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-warning-500-rgb),var(--tw-text-opacity))}.danger-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-danger-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-danger-500-rgb),var(--tw-text-opacity))}.danger-outline,.important-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.important-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-important-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-important-500-rgb),var(--tw-text-opacity))}.special-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-special-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-special-500-rgb),var(--tw-text-opacity))}.lighter-outline,.special-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.lighter-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-100-rgb),var(--tw-ring-opacity));color:rgba(var(--color-gray-100-rgb),var(--tw-text-opacity))}.light-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-300-rgb),var(--tw-ring-opacity));color:rgba(var(--color-gray-300-rgb),var(--tw-text-opacity))}.gray-outline,.light-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.gray-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-500-rgb),var(--tw-ring-opacity));color:rgba(var(--color-gray-500-rgb),var(--tw-text-opacity))}.darken-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-700-rgb),var(--tw-ring-opacity));color:rgba(var(--color-gray-700-rgb),var(--tw-text-opacity))}.darken-outline,.darker-outline{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.darker-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-900-rgb),var(--tw-ring-opacity));color:rgba(var(--color-gray-900-rgb),var(--tw-text-opacity))}.black-outline{--tw-text-opacity:1;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-black-rgb),var(--tw-ring-opacity));box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);color:rgba(var(--color-black-rgb),var(--tw-text-opacity))}.primary-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-primary-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-primary-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}.secondary-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-secondary-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-secondary-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-secondary-500-rgb),var(--tw-text-opacity))}.success-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-success-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-success-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-success-500-rgb),var(--tw-text-opacity))}.warning-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-warning-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-warning-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-warning-500-rgb),var(--tw-text-opacity))}.danger-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-danger-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-danger-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-danger-500-rgb),var(--tw-text-opacity))}.important-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-important-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-important-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-important-500-rgb),var(--tw-text-opacity))}.special-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-special-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-special-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-special-500-rgb),var(--tw-text-opacity))}.lighter-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity));color:rgba(var(--color-gray-500-rgb),var(--tw-text-opacity))}.light-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-200-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-200-rgb),var(--tw-bg-opacity));color:rgba(var(--color-gray-600-rgb),var(--tw-text-opacity))}.gray-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-300-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-300-rgb),var(--tw-bg-opacity))}.darken-pale,.gray-pale{color:rgba(var(--color-gray-700-rgb),var(--tw-text-opacity))}.darken-pale{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-400-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-400-rgb),var(--tw-bg-opacity))}.primary{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-primary-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity))}.primary,.primary:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.primary:hover{--tw-text-opacity:1}.secondary{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-secondary-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-secondary-500-rgb),var(--tw-bg-opacity))}.secondary,.secondary:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.secondary:hover{--tw-text-opacity:1}.success{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-success-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-success-500-rgb),var(--tw-bg-opacity))}.success,.success:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.success:hover{--tw-text-opacity:1}.warning{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-warning-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-warning-500-rgb),var(--tw-bg-opacity))}.warning,.warning:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.warning:hover{--tw-text-opacity:1}.danger{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-danger-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-danger-500-rgb),var(--tw-bg-opacity))}.danger,.danger:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.danger:hover{--tw-text-opacity:1}.important{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-important-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-important-500-rgb),var(--tw-bg-opacity))}.important,.important:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.important:hover{--tw-text-opacity:1}.special{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-special-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-special-500-rgb),var(--tw-bg-opacity))}.special,.special:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.special:hover{--tw-text-opacity:1}.white{--tw-bg-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-white-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-white-rgb),var(--tw-bg-opacity))}.lighter{--tw-bg-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-100-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity))}.light{--tw-bg-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-300-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-300-rgb),var(--tw-bg-opacity))}.gray{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-500-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-500-rgb),var(--tw-bg-opacity))}.gray,.gray:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.gray:hover{--tw-text-opacity:1}.darken{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-700-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-700-rgb),var(--tw-bg-opacity))}.darken,.darken:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.darken:hover{--tw-text-opacity:1}.darker{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-gray-900-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-gray-900-rgb),var(--tw-bg-opacity))}.darker,.darker:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.darker:hover{--tw-text-opacity:1}.black{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-black-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-black-rgb),var(--tw-bg-opacity))}.black,.black:hover{color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.black:hover{--tw-text-opacity:1}.surface{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-surface-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-surface-rgb),var(--tw-bg-opacity))}.canvas,.surface{color:rgba(var(--color-fore-rgb),var(--tw-text-opacity))}.canvas{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-canvas-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity))}.inverse{--tw-bg-opacity:1;--tw-text-opacity:1;--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-fore-rgb),var(--tw-ring-opacity));background-color:rgba(var(--color-fore-rgb),var(--tw-bg-opacity));color:rgba(var(--color-canvas-rgb),var(--tw-text-opacity))}.ghost{--tw-text-opacity:1;--tw-ring-color:var(--color-transparent);background-color:var(--color-transparent);color:rgba(var(--color-fore-rgb),var(--tw-text-opacity))}.sans{font-family:-apple-system,Noto Sans,Helvetica Neue,Helvetica,Nimbus Sans L,Arial,Liberation Sans,PingFang SC,Hiragino Sans GB,Noto Sans CJK SC,Source Han Sans SC,Source Han Sans CN,Microsoft YaHei,Wenquanyi Micro Hei,WenQuanYi Zen Hei,ST Heiti,SimHei,WenQuanYi Zen Hei Sharp,sans-serif}.serif{font-family:Nimbus Roman No9 L,Songti SC,Noto Serif CJK SC,Source Han Serif SC,Source Han Serif CN,STSong,AR PL New Sung,AR PL SungtiL GB,NSimSun,SimSun,TW-Sung,WenQuanYi Bitmap Song,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR PL UMing TW MBE,PMingLiU,MingLiU,serif}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm,.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:.8125rem;line-height:1.25rem}.text-lg{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.125rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.font-thin{font-weight:100}.font-light{font-weight:300}.font-medium{font-weight:500}.font-bold{font-weight:700}.font-black{font-weight:900}.leading-3{line-height:.75rem}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-8{line-height:2rem}.leading-9{line-height:2.25rem}.leading-10{line-height:2.5rem}.leading-none{line-height:1}.leading-tight{line-height:1.25}.leading-snug{line-height:1.375}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.leading-loose{line-height:2}.line-2{-webkit-line-clamp:2}.line-2,.line-3{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-3{-webkit-line-clamp:3}.line-4{-webkit-line-clamp:4}.line-4,.line-5{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-5{-webkit-line-clamp:5}.line-6{-webkit-box-orient:vertical;-webkit-line-clamp:6;display:-webkit-box;overflow:hidden}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-justify{text-align:justify}.align-middle{vertical-align:middle}.align-top{vertical-align:top}.align-bottom{vertical-align:bottom}.align-sub{vertical-align:sub}.align-super{vertical-align:super}.text-primary{--tw-text-opacity:1;color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}.text-secondary{--tw-text-opacity:1;color:rgba(var(--color-secondary-500-rgb),var(--tw-text-opacity))}.text-success{--tw-text-opacity:1;color:rgba(var(--color-success-500-rgb),var(--tw-text-opacity))}.text-warning{--tw-text-opacity:1;color:rgba(var(--color-warning-500-rgb),var(--tw-text-opacity))}.text-danger{--tw-text-opacity:1;color:rgba(var(--color-danger-500-rgb),var(--tw-text-opacity))}.text-important{--tw-text-opacity:1;color:rgba(var(--color-important-500-rgb),var(--tw-text-opacity))}.text-special{--tw-text-opacity:1;color:rgba(var(--color-special-500-rgb),var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgba(var(--color-white-rgb),var(--tw-text-opacity))}.text-lighter{--tw-text-opacity:1;color:rgba(var(--color-gray-300-rgb),var(--tw-text-opacity))}.text-light{--tw-text-opacity:1;color:rgba(var(--color-gray-400-rgb),var(--tw-text-opacity))}.text-gray{--tw-text-opacity:1;color:rgba(var(--color-gray-500-rgb),var(--tw-text-opacity))}.text-darken{--tw-text-opacity:1;color:rgba(var(--color-gray-700-rgb),var(--tw-text-opacity))}.text-darker{--tw-text-opacity:1;color:rgba(var(--color-gray-900-rgb),var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgba(var(--color-black-rgb),var(--tw-text-opacity))}.text-canvas{--tw-text-opacity:1;color:rgba(var(--color-canvas-rgb),var(--tw-text-opacity))}.text-surface{--tw-text-opacity:1;color:rgba(var(--color-surface-rgb),var(--tw-text-opacity))}.text-inverse{--tw-text-opacity:1;color:rgba(var(--color-inverse-rgb),var(--tw-text-opacity))}.text-fore{--tw-text-opacity:1;color:rgba(var(--color-fore-rgb),var(--tw-text-opacity))}.text-focus{--tw-text-opacity:1;color:rgba(var(--color-focus-rgb),var(--tw-text-opacity))}.text-link{--tw-text-opacity:1;color:rgba(var(--color-link-rgb),var(--tw-text-opacity))}.text-link-hover{--tw-text-opacity:1;color:rgba(var(--color-link-hover-rgb),var(--tw-text-opacity))}.text-transparent{color:transparent}.text-current{color:currentColor}.text-inherit{color:inherit}.clip,.ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.clip{text-overflow:clip}.nowrap{white-space:nowrap}.pre{white-space:pre}.pre-line{white-space:pre-line}.pre-wrap{white-space:pre-wrap}.break-normal{overflow-wrap:normal;word-break:normal}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-opacity-0{--tw-text-opacity:0}.text-opacity-10{--tw-text-opacity:.1}.text-opacity-20{--tw-text-opacity:.2}.text-opacity-30{--tw-text-opacity:.3}.text-opacity-40{--tw-text-opacity:.4}.text-opacity-50{--tw-text-opacity:.5}.text-opacity-60{--tw-text-opacity:.6}.text-opacity-70{--tw-text-opacity:.7}.text-opacity-80{--tw-text-opacity:.8}.text-opacity-90{--tw-text-opacity:.9}.text-opacity-100{--tw-text-opacity:1}.underline{text-decoration-line:underline}.overline{text-decoration-line:overline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.bg-primary{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity))}.bg-secondary{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-500-rgb),var(--tw-bg-opacity))}.bg-success{--tw-bg-opacity:1;background-color:rgba(var(--color-success-500-rgb),var(--tw-bg-opacity))}.bg-warning{--tw-bg-opacity:1;background-color:rgba(var(--color-warning-500-rgb),var(--tw-bg-opacity))}.bg-danger{--tw-bg-opacity:1;background-color:rgba(var(--color-danger-500-rgb),var(--tw-bg-opacity))}.bg-important{--tw-bg-opacity:1;background-color:rgba(var(--color-important-500-rgb),var(--tw-bg-opacity))}.bg-special{--tw-bg-opacity:1;background-color:rgba(var(--color-special-500-rgb),var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgba(var(--color-white-rgb),var(--tw-bg-opacity))}.bg-lighter{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity))}.bg-light{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-300-rgb),var(--tw-bg-opacity))}.bg-gray{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-500-rgb),var(--tw-bg-opacity))}.bg-darken{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-700-rgb),var(--tw-bg-opacity))}.bg-darker{--tw-bg-opacity:1;background-color:rgba(var(--color-gray-900-rgb),var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgba(var(--color-black-rgb),var(--tw-bg-opacity))}.bg-canvas{--tw-bg-opacity:1;background-color:rgba(var(--color-canvas-rgb),var(--tw-bg-opacity))}.bg-surface{--tw-bg-opacity:1;background-color:rgba(var(--color-surface-rgb),var(--tw-bg-opacity))}.bg-inverse{--tw-bg-opacity:1;background-color:rgba(var(--color-fore-rgb),var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-inherit{background-color:inherit}.bg-none{background:none}.bg-opacity-0{--tw-bg-opacity:0}.bg-opacity-10{--tw-bg-opacity:.1}.bg-opacity-20{--tw-bg-opacity:.2}.bg-opacity-30{--tw-bg-opacity:.3}.bg-opacity-40{--tw-bg-opacity:.4}.bg-opacity-50{--tw-bg-opacity:.5}.bg-opacity-60{--tw-bg-opacity:.6}.bg-opacity-70{--tw-bg-opacity:.7}.bg-opacity-80{--tw-bg-opacity:.8}.bg-opacity-90{--tw-bg-opacity:.9}.bg-opacity-100{--tw-bg-opacity:1}.border{border-width:1px}.border-t{border-top-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.border-2{border-width:2px}.border-t-2{border-top-width:2px}.border-l-2{border-left-width:2px}.border-r-2{border-right-width:2px}.border-b-2{border-bottom-width:2px}.border-4{border-width:4px}.border-t-4{border-top-width:4px}.border-l-4{border-left-width:4px}.border-r-4{border-right-width:4px}.border-b-4{border-bottom-width:4px}.border-0{border-width:0}.border-t-0{border-top-width:0}.border-r-0{border-right-width:0}.border-b-0{border-bottom-width:0}.border-l-0{border-left-width:0}.border-primary{--tw-border-opacity:1;border-color:rgba(var(--color-primary-500-rgb),var(--tw-border-opacity))}.border-secondary{--tw-border-opacity:1;border-color:rgba(var(--color-secondary-500-rgb),var(--tw-border-opacity))}.border-success{--tw-border-opacity:1;border-color:rgba(var(--color-success-500-rgb),var(--tw-border-opacity))}.border-warning{--tw-border-opacity:1;border-color:rgba(var(--color-warning-500-rgb),var(--tw-border-opacity))}.border-danger{--tw-border-opacity:1;border-color:rgba(var(--color-danger-500-rgb),var(--tw-border-opacity))}.border-important{--tw-border-opacity:1;border-color:rgba(var(--color-important-500-rgb),var(--tw-border-opacity))}.border-special{--tw-border-opacity:1;border-color:rgba(var(--color-special-500-rgb),var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgba(var(--color-white-rgb),var(--tw-border-opacity))}.border-lighter{--tw-border-opacity:1;border-color:rgba(var(--color-gray-100-rgb),var(--tw-border-opacity))}.border-light{--tw-border-opacity:1;border-color:rgba(var(--color-gray-300-rgb),var(--tw-border-opacity))}.border-gray{--tw-border-opacity:1;border-color:rgba(var(--color-gray-500-rgb),var(--tw-border-opacity))}.border-darken{--tw-border-opacity:1;border-color:rgba(var(--color-gray-700-rgb),var(--tw-border-opacity))}.border-darker{--tw-border-opacity:1;border-color:rgba(var(--color-gray-900-rgb),var(--tw-border-opacity))}.border-black{--tw-border-opacity:1;border-color:rgba(var(--color-black-rgb),var(--tw-border-opacity))}.border-canvas{--tw-border-opacity:1;border-color:rgba(var(--color-canvas-rgb),var(--tw-border-opacity))}.border-surface{--tw-border-opacity:1;border-color:rgba(var(--color-surface-rgb),var(--tw-border-opacity))}.border-inverse{--tw-border-opacity:1;border-color:rgba(var(--color-fore-rgb),var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-current{border-color:currentColor}.border-inherit{border-color:inherit}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border-dotted{border-style:dotted}.border-double{border-style:double}.border-hidden{border-style:hidden}.border-none{border-style:none}.border-opacity-0{--tw-border-opacity:0}.border-opacity-10{--tw-border-opacity:.1}.border-opacity-20{--tw-border-opacity:.2}.border-opacity-30{--tw-border-opacity:.3}.border-opacity-40{--tw-border-opacity:.4}.border-opacity-50{--tw-border-opacity:.5}.border-opacity-60{--tw-border-opacity:.6}.border-opacity-70{--tw-border-opacity:.7}.border-opacity-80{--tw-border-opacity:.8}.border-opacity-90{--tw-border-opacity:.9}.border-opacity-100{--tw-border-opacity:1}.rounded-sm{border-radius:var(--radius-sm)}.rounded{border-radius:var(--radius)}.rounded-md{border-radius:var(--radius-md)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.circle,.rounded-full{border-radius:var(--radius-full)}.rounded-none{border-radius:var(--radius-none)}.rounded-l-none{border-bottom-left-radius:var(--radius-none);border-top-left-radius:var(--radius-none)}.rounded-t-none{border-top-left-radius:var(--radius-none)}.rounded-r-none,.rounded-t-none{border-top-right-radius:var(--radius-none)}.rounded-b-none,.rounded-r-none{border-bottom-right-radius:var(--radius-none)}.rounded-b-none{border-bottom-left-radius:var(--radius-none)}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-border-strong-rgb),var(--tw-ring-opacity))}.ring,.ring-0{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-0{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-2,.ring-3{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-3{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-4{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-4,.ring-8{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-8{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(8px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-inset{--tw-ring-inset:inset}.ring-inverse{--tw-ring-opacity:1}.ring-inverse,.ring-light{--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity))}.ring-light{--tw-ring-opacity:.05}.ring-dark{--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.2}.ring-darker{--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.3}.ring-darkest{--tw-ring-color:rgba(var(--color-inverse-rgb),var(--tw-ring-opacity));--tw-ring-opacity:.5}.ring-primary{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-primary-500-rgb),var(--tw-ring-opacity))}.ring-secondary{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-secondary-500-rgb),var(--tw-ring-opacity))}.ring-warning{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-warning-500-rgb),var(--tw-ring-opacity))}.ring-success{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-success-500-rgb),var(--tw-ring-opacity))}.ring-danger{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-danger-500-rgb),var(--tw-ring-opacity))}.ring-important{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-important-500-rgb),var(--tw-ring-opacity))}.ring-special{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-special-500-rgb),var(--tw-ring-opacity))}.ring-inherit{--tw-ring-color:var(--color-inherit)}.ring-current{--tw-ring-color:var(--color-current)}.ring-transparent{--tw-ring-color:var(--color-transparent)}.ring-canvas{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-canvas-rgb),var(--tw-ring-opacity))}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-black-rgb),var(--tw-ring-opacity))}.ring-white{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-white-rgb),var(--tw-ring-opacity))}.ring-opacity-0{--tw-ring-opacity:0}.ring-opacity-5{--tw-ring-opacity:.05}.ring-opacity-10{--tw-ring-opacity:.1}.ring-opacity-20{--tw-ring-opacity:.2}.ring-opacity-30{--tw-ring-opacity:.3}.ring-opacity-40{--tw-ring-opacity:.4}.ring-opacity-50{--tw-ring-opacity:.5}.ring-opacity-60{--tw-ring-opacity:.6}.ring-opacity-70{--tw-ring-opacity:.7}.ring-opacity-80{--tw-ring-opacity:.8}.ring-opacity-90{--tw-ring-opacity:.9}.ring-opacity-100{--tw-ring-opacity:1}.ring-offset-0{--tw-ring-offset-width:0px}.ring-offset-1{--tw-ring-offset-width:1px}.ring-offset-2{--tw-ring-offset-width:2px}.ring-offset-4{--tw-ring-offset-width:4px}.ring-offset-8{--tw-ring-offset-width:8px}.shadow-sm{--tw-shadow:var(--shadow-sm);--tw-shadow-colored:var(--shadow-sm)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:var(--shadow);--tw-shadow-colored:var(--shadow)}.shadow-md{--tw-shadow:var(--shadow-md);--tw-shadow-colored:var(--shadow-md)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg)}.shadow-xl{--tw-shadow:var(--shadow-xl);--tw-shadow-colored:var(--shadow-xl)}.shadow-2xl,.shadow-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:var(--shadow-2xl);--tw-shadow-colored:var(--shadow-2xl)}.shadow-inner{--tw-shadow:var(--shadow-inner);--tw-shadow-colored:var(--shadow-inner)}.shadow-inner,.shadow-none{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow:var(--shadow-none);--tw-shadow-colored:var(--shadow-none)}.shadow-primary{--tw-shadow-color:rgb(var(--color-primary-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-secondary{--tw-shadow-color:rgb(var(--color-secondary-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-success{--tw-shadow-color:rgb(var(--color-success-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-warning{--tw-shadow-color:rgb(var(--color-warning-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-danger{--tw-shadow-color:rgb(var(--color-danger-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-important{--tw-shadow-color:rgb(var(--color-important-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-special{--tw-shadow-color:rgb(var(--color-special-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-white{--tw-shadow-color:rgb(var(--color-white-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-lighter{--tw-shadow-color:rgb(var(--color-gray-100-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-light{--tw-shadow-color:rgb(var(--color-gray-300-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-gray{--tw-shadow-color:rgb(var(--color-gray-500-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-dark{--tw-shadow-color:rgb(var(--color-gray-700-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-darker{--tw-shadow-color:rgb(var(--color-gray-900-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-black{--tw-shadow-color:rgb(var(--color-black-rgb));--tw-shadow:var(--tw-shadow-colored)}.shadow-transparent{--tw-shadow-color:var(--color-transparent);--tw-shadow:var(--tw-shadow-colored)}.shadow-current{--tw-shadow-color:var(--color-current);--tw-shadow:var(--tw-shadow-colored)}.shadow-inherit{--tw-shadow-color:var(--color-inherit);--tw-shadow:var(--tw-shadow-colored)}.opacity-0{opacity:0}.opacity-5{opacity:.05}.opacity-10{opacity:.1}.opacity-20{opacity:.2}.opacity-25{opacity:.25}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.opacity-95{opacity:.95}.opacity-100{opacity:1}.blur-none{--tw-blur:blur(0)}.blur-none,.blur-sm{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-sm{--tw-blur:blur(4px)}.blur{--tw-blur:blur(8px)}.blur,.blur-md{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-md{--tw-blur:blur(12px)}.blur-lg{--tw-blur:blur(16px)}.blur-lg,.blur-xl{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-xl{--tw-blur:blur(24px)}.grayscale{--tw-grayscale:grayscale(100%)}.grayscale,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.dsd-none{--tw-drop-shadow:drop-shadow(0 0 #0000)}.dsd-none,.dsd-sm{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.dsd-sm{--tw-drop-shadow:drop-shadow(0 1px 1px rgba(0,0,0,.05))}.dsd{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.dsd,.dsd-md{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.dsd-md{--tw-drop-shadow:drop-shadow(0 4px 3px rgba(0,0,0,.07)) drop-shadow(0 2px 2px rgba(0,0,0,.06))}.dsd-lg{--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1))}.dsd-lg,.dsd-xl{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.dsd-xl{--tw-drop-shadow:drop-shadow(0 20px 13px rgba(0,0,0,.03)) drop-shadow(0 8px 5px rgba(0,0,0,.08))}.dsd-2xl{--tw-drop-shadow:drop-shadow(0 25px 25px rgba(0,0,0,.15));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.bg-blur-none{--tw-backdrop-blur:blur(0)}.bg-blur-none,.bg-blur-sm{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.bg-blur-sm{--tw-backdrop-blur:blur(4px)}.bg-blur{--tw-backdrop-blur:blur(8px)}.bg-blur,.bg-blur-md{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.bg-blur-md{--tw-backdrop-blur:blur(12px)}.bg-blur-lg{--tw-backdrop-blur:blur(16px)}.bg-blur-lg,.bg-blur-xl{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.bg-blur-xl{--tw-backdrop-blur:blur(24px)}.bg-blur-2xl{--tw-backdrop-blur:blur(40px)}.bg-blur-2xl,.bg-blur-3xl{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.bg-blur-3xl{--tw-backdrop-blur:blur(64px)}.trans{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-shadow{transition-duration:.15s;transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-transform{transition-duration:.15s;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.trans-75{transition-duration:75ms}.trans-100{transition-duration:.1s}.trans-200{transition-duration:.2s}.trans-300{transition-duration:.3s}.trans-500{transition-duration:.5s}.trans-1000{transition-duration:1s}.fade,.fade-from-bottom,.fade-from-center,.fade-from-left,.fade-from-right,.fade-from-top{opacity:0;transition-duration:.15s;transition-property:opacity,transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.fade-from-bottom,.fade-from-center,.fade-from-left,.fade-from-right,.fade-from-top{--tw-scale-x:.75;--tw-scale-y:.75}.fade-from-bottom,.fade-from-center,.fade-from-left,.fade-from-right,.fade-from-top{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.fade-from-bottom{--tw-translate-y:50%}.fade-from-top{--tw-translate-y:-50%}.fade-from-left,.fade-from-top{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.fade-from-left{--tw-translate-x:-50%}.fade-from-right{--tw-translate-x:50%}.fade-from-bottom.in,.fade-from-center.in,.fade-from-left.in,.fade-from-right,.fade-from-right.in,.fade-from-top.in,.fade.in{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.fade-from-bottom.in,.fade-from-center.in,.fade-from-left.in,.fade-from-right.in,.fade-from-top.in,.fade.in{--tw-translate-x:0px;--tw-translate-y:0px;--tw-scale-x:1;--tw-scale-y:1;opacity:1}.spin{animation:-spin 1s linear infinite}@keyframes -ping{75%,to{opacity:0;transform:scale(2)}}.ping{animation:-ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes -pulse{50%{opacity:.5}}.pulse{animation:-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes -bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}.bounce{animation:-bounce 1s infinite}.scale-0{--tw-scale-x:0;--tw-scale-y:0}.scale-0,.scale-50{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-50{--tw-scale-x:.5;--tw-scale-y:.5}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-100,.scale-105{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05}.scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1}.scale-110,.scale-125{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-125{--tw-scale-x:1.25;--tw-scale-y:1.25}.scale-150{--tw-scale-x:1.5;--tw-scale-y:1.5}.flip-x,.scale-150{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.flip-x{--tw-scale-x:-1}.flip-y{--tw-scale-y:-1}.flip-y,.rotate-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-0{--tw-rotate:0deg}.rotate-1{--tw-rotate:1deg}.rotate-1,.rotate-2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-2{--tw-rotate:2deg}.rotate-3{--tw-rotate:3deg}.rotate-3,.rotate-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-6{--tw-rotate:6deg}.rotate-12{--tw-rotate:12deg}.rotate-12,.rotate-45{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate:45deg}.rotate-90{--tw-rotate:90deg}.rotate-180,.rotate-90{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.btn,.state,a{cursor:pointer;position:relative}.btn:before,.state:before,a:before{background:var(--state-color);border-radius:inherit;content:" ";display:block;inset:0;opacity:0;position:absolute;transform:scale(var(--state-scale));transition-duration:.2s;transition-property:opacity,transform,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1)}.btn:active:before,.btn:focus-visible:before,.btn:hover:before,.state:active:before,.state:focus-visible:before,.state:hover:before,a:active:before,a:focus-visible:before,a:hover:before{--tw-scale-x:1;--tw-scale-y:1;opacity:1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.btn:focus-visible,.state:focus-visible,a:focus-visible{outline:2px solid transparent;outline-offset:2px}.btn:focus-visible:before,.state:focus-visible:before,a:focus-visible:before{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-opacity:1;--tw-ring-color:rgba(var(--color-focus-rgb),var(--tw-ring-opacity));background:var(--state-focus-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.btn:active:before,.state:active:before,a:active:before{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-color:var(--color-current);background:var(--state-active-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);transition-duration:.7s}.btn.disabled:before,.btn[disabled]:before,.state.disabled:before,.state[disabled]:before,a.disabled:before,a[disabled]:before{display:none}.disabled,.disabled *,[disabled],[disabled] *{--tw-grayscale:grayscale(100%);cursor:not-allowed!important;filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);opacity:var(--state-disabled-opacity)}.muted{opacity:var(--state-muted-opacity)}.load-indicator:after,.load-indicator:before{display:block;opacity:0;position:absolute;transition-delay:0s;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);visibility:hidden}.load-indicator:before{--tw-content:attr(data-loading);align-items:center;background-color:rgba(var(--color-canvas-rgb),.7);border-radius:inherit;content:var(--tw-content);display:flex;font-size:.75rem;inset:0;justify-content:center;line-height:1rem;z-index:99}.load-indicator[data-loading]:before{padding-top:3.5rem}.load-indicator:after{height:2rem;left:50%;margin-left:-1rem;margin-top:-1rem;top:50%;width:2rem;z-index:100}@keyframes -spin{to{transform:rotate(1turn)}}.load-indicator:after{--tw-content:"";animation:-spin 1s linear infinite;border-color:var(--color-current);border-radius:var(--radius-full);border-top-color:var(--color-transparent);border-width:4px;content:var(--tw-content)}.load-indicator.loading:after,.load-indicator.loading:before{opacity:1;transition-delay:.5s;visibility:visible}.load-indicator.loading:after{opacity:.7}.events-none{pointer-events:none}.events-auto{pointer-events:auto}.scroll-auto{scroll-behavior:auto}.scroll-smooth{scroll-behavior:smooth}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-text{-webkit-user-select:text;-moz-user-select:text;user-select:text}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.select-auto{-webkit-user-select:auto;-moz-user-select:auto;user-select:auto}.bg-primary-50{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-50-rgb),var(--tw-bg-opacity))}.bg-primary-100{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-100-rgb),var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-200-rgb),var(--tw-bg-opacity))}.bg-primary-300{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-300-rgb),var(--tw-bg-opacity))}.bg-primary-400{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-400-rgb),var(--tw-bg-opacity))}.bg-primary-500{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-600-rgb),var(--tw-bg-opacity))}.bg-primary-700{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-700-rgb),var(--tw-bg-opacity))}.bg-primary-800{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-800-rgb),var(--tw-bg-opacity))}.bg-primary-900{--tw-bg-opacity:1;background-color:rgba(var(--color-primary-900-rgb),var(--tw-bg-opacity))}.bg-secondary-50{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-50-rgb),var(--tw-bg-opacity))}.bg-secondary-100{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-100-rgb),var(--tw-bg-opacity))}.bg-secondary-200{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-200-rgb),var(--tw-bg-opacity))}.bg-secondary-300{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-300-rgb),var(--tw-bg-opacity))}.bg-secondary-400{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-400-rgb),var(--tw-bg-opacity))}.bg-secondary-500{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-500-rgb),var(--tw-bg-opacity))}.bg-secondary-600{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-600-rgb),var(--tw-bg-opacity))}.bg-secondary-700{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-700-rgb),var(--tw-bg-opacity))}.bg-secondary-800{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-800-rgb),var(--tw-bg-opacity))}.bg-secondary-900{--tw-bg-opacity:1;background-color:rgba(var(--color-secondary-900-rgb),var(--tw-bg-opacity))}.text-primary-50{--tw-text-opacity:1;color:rgba(var(--color-primary-50-rgb),var(--tw-text-opacity))}.text-primary-100{--tw-text-opacity:1;color:rgba(var(--color-primary-100-rgb),var(--tw-text-opacity))}.text-primary-200{--tw-text-opacity:1;color:rgba(var(--color-primary-200-rgb),var(--tw-text-opacity))}.text-primary-300{--tw-text-opacity:1;color:rgba(var(--color-primary-300-rgb),var(--tw-text-opacity))}.text-primary-400{--tw-text-opacity:1;color:rgba(var(--color-primary-400-rgb),var(--tw-text-opacity))}.text-primary-500{--tw-text-opacity:1;color:rgba(var(--color-primary-500-rgb),var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgba(var(--color-primary-600-rgb),var(--tw-text-opacity))}.text-primary-700{--tw-text-opacity:1;color:rgba(var(--color-primary-700-rgb),var(--tw-text-opacity))}.text-primary-800{--tw-text-opacity:1;color:rgba(var(--color-primary-800-rgb),var(--tw-text-opacity))}.text-primary-900{--tw-text-opacity:1;color:rgba(var(--color-primary-900-rgb),var(--tw-text-opacity))}.text-secondary-50{--tw-text-opacity:1;color:rgba(var(--color-secondary-50-rgb),var(--tw-text-opacity))}.text-secondary-100{--tw-text-opacity:1;color:rgba(var(--color-secondary-100-rgb),var(--tw-text-opacity))}.text-secondary-200{--tw-text-opacity:1;color:rgba(var(--color-secondary-200-rgb),var(--tw-text-opacity))}.text-secondary-300{--tw-text-opacity:1;color:rgba(var(--color-secondary-300-rgb),var(--tw-text-opacity))}.text-secondary-400{--tw-text-opacity:1;color:rgba(var(--color-secondary-400-rgb),var(--tw-text-opacity))}.text-secondary-500{--tw-text-opacity:1;color:rgba(var(--color-secondary-500-rgb),var(--tw-text-opacity))}.text-secondary-600{--tw-text-opacity:1;color:rgba(var(--color-secondary-600-rgb),var(--tw-text-opacity))}.text-secondary-700{--tw-text-opacity:1;color:rgba(var(--color-secondary-700-rgb),var(--tw-text-opacity))}.text-secondary-800{--tw-text-opacity:1;color:rgba(var(--color-secondary-800-rgb),var(--tw-text-opacity))}.text-secondary-900{--tw-text-opacity:1;color:rgba(var(--color-secondary-900-rgb),var(--tw-text-opacity))} diff --git a/www/js/zui3/zui.zentao.js b/www/js/zui3/zui.zentao.js new file mode 100644 index 0000000000..7ed8c731ee --- /dev/null +++ b/www/js/zui3/zui.zentao.js @@ -0,0 +1,7539 @@ +var Aa = Object.defineProperty; +var Na = (e, n, t) => n in e ? Aa(e, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[n] = t; +var w = (e, n, t) => (Na(e, typeof n != "symbol" ? n + "" : n, t), t), Ji = (e, n, t) => { + if (!n.has(e)) + throw TypeError("Cannot " + t); +}; +var m = (e, n, t) => (Ji(e, n, "read from private field"), t ? t.call(e) : n.get(e)), x = (e, n, t) => { + if (n.has(e)) + throw TypeError("Cannot add the same private member more than once"); + n instanceof WeakSet ? n.add(e) : n.set(e, t); +}, R = (e, n, t, s) => (Ji(e, n, "write to private field"), s ? s.call(e, t) : n.set(e, t), t), ir = (e, n, t, s) => ({ + set _(i) { + R(e, n, i, t); + }, + get _() { + return m(e, n, s); + } +}), N = (e, n, t) => (Ji(e, n, "access private method"), t); +var rs, z, cl, it, ye, or, al, fo, ul, ks = {}, hl = [], La = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; +function Bt(e, n) { + for (var t in n) + e[t] = n[t]; + return e; +} +function fl(e) { + var n = e.parentNode; + n && n.removeChild(e); +} +function E(e, n, t) { + var s, i, o, r = {}; + for (o in n) + o == "key" ? s = n[o] : o == "ref" ? i = n[o] : r[o] = n[o]; + if (arguments.length > 2 && (r.children = arguments.length > 3 ? rs.call(arguments, 2) : t), typeof e == "function" && e.defaultProps != null) + for (o in e.defaultProps) + r[o] === void 0 && (r[o] = e.defaultProps[o]); + return bn(e, r, s, i, null); +} +function bn(e, n, t, s, i) { + var o = { type: e, props: n, key: t, ref: s, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, __h: null, constructor: void 0, __v: i ?? ++cl }; + return i == null && z.vnode != null && z.vnode(o), o; +} +function cn() { + return { current: null }; +} +function ls(e) { + return e.children; +} +function U(e, n) { + this.props = e, this.context = n; +} +function Tn(e, n) { + if (n == null) + return e.__ ? Tn(e.__, e.__.__k.indexOf(e) + 1) : null; + for (var t; n < e.__k.length; n++) + if ((t = e.__k[n]) != null && t.__e != null) + return t.__e; + return typeof e.type == "function" ? Tn(e) : null; +} +function dl(e) { + var n, t; + if ((e = e.__) != null && e.__c != null) { + for (e.__e = e.__c.base = null, n = 0; n < e.__k.length; n++) + if ((t = e.__k[n]) != null && t.__e != null) { + e.__e = e.__c.base = t.__e; + break; + } + return dl(e); + } +} +function po(e) { + (!e.__d && (e.__d = !0) && ye.push(e) && !Ts.__r++ || or !== z.debounceRendering) && ((or = z.debounceRendering) || al)(Ts); +} +function Ts() { + var e, n, t, s, i, o, r, l; + for (ye.sort(fo); e = ye.shift(); ) + e.__d && (n = ye.length, s = void 0, i = void 0, r = (o = (t = e).__v).__e, (l = t.__P) && (s = [], (i = Bt({}, o)).__v = o.__v + 1, To(l, o, i, t.__n, l.ownerSVGElement !== void 0, o.__h != null ? [r] : null, s, r ?? Tn(o), o.__h), bl(s, o), o.__e != r && dl(o)), ye.length > n && ye.sort(fo)); + Ts.__r = 0; +} +function pl(e, n, t, s, i, o, r, l, a, h) { + var c, u, d, f, p, g, y, _ = s && s.__k || hl, v = _.length; + for (t.__k = [], c = 0; c < n.length; c++) + if ((f = t.__k[c] = (f = n[c]) == null || typeof f == "boolean" || typeof f == "function" ? null : typeof f == "string" || typeof f == "number" || typeof f == "bigint" ? bn(null, f, null, null, f) : Array.isArray(f) ? bn(ls, { children: f }, null, null, null) : f.__b > 0 ? bn(f.type, f.props, f.key, f.ref ? f.ref : null, f.__v) : f) != null) { + if (f.__ = t, f.__b = t.__b + 1, (d = _[c]) === null || d && f.key == d.key && f.type === d.type) + _[c] = void 0; + else + for (u = 0; u < v; u++) { + if ((d = _[u]) && f.key == d.key && f.type === d.type) { + _[u] = void 0; + break; + } + d = null; + } + To(e, f, d = d || ks, i, o, r, l, a, h), p = f.__e, (u = f.ref) && d.ref != u && (y || (y = []), d.ref && y.push(d.ref, null, f), y.push(u, f.__c || p, f)), p != null ? (g == null && (g = p), typeof f.type == "function" && f.__k === d.__k ? f.__d = a = ml(f, a, e) : a = yl(e, f, d, _, p, a), typeof t.type == "function" && (t.__d = a)) : a && d.__e == a && a.parentNode != e && (a = Tn(d)); + } + for (t.__e = g, c = v; c--; ) + _[c] != null && (typeof t.type == "function" && _[c].__e != null && _[c].__e == t.__d && (t.__d = _l(s).nextSibling), vl(_[c], _[c])); + if (y) + for (c = 0; c < y.length; c++) + wl(y[c], y[++c], y[++c]); +} +function ml(e, n, t) { + for (var s, i = e.__k, o = 0; i && o < i.length; o++) + (s = i[o]) && (s.__ = e, n = typeof s.type == "function" ? ml(s, n, t) : yl(t, s, s, i, s.__e, n)); + return n; +} +function gl(e, n) { + return n = n || [], e == null || typeof e == "boolean" || (Array.isArray(e) ? e.some(function(t) { + gl(t, n); + }) : n.push(e)), n; +} +function yl(e, n, t, s, i, o) { + var r, l, a; + if (n.__d !== void 0) + r = n.__d, n.__d = void 0; + else if (t == null || i != o || i.parentNode == null) + t: + if (o == null || o.parentNode !== e) + e.appendChild(i), r = null; + else { + for (l = o, a = 0; (l = l.nextSibling) && a < s.length; a += 1) + if (l == i) + break t; + e.insertBefore(i, o), r = o; + } + return r !== void 0 ? r : i.nextSibling; +} +function _l(e) { + var n, t, s; + if (e.type == null || typeof e.type == "string") + return e.__e; + if (e.__k) { + for (n = e.__k.length - 1; n >= 0; n--) + if ((t = e.__k[n]) && (s = _l(t))) + return s; + } + return null; +} +function Ma(e, n, t, s, i) { + var o; + for (o in t) + o === "children" || o === "key" || o in n || As(e, o, null, t[o], s); + for (o in n) + i && typeof n[o] != "function" || o === "children" || o === "key" || o === "value" || o === "checked" || t[o] === n[o] || As(e, o, n[o], t[o], s); +} +function rr(e, n, t) { + n[0] === "-" ? e.setProperty(n, t ?? "") : e[n] = t == null ? "" : typeof t != "number" || La.test(n) ? t : t + "px"; +} +function As(e, n, t, s, i) { + var o; + t: + if (n === "style") + if (typeof t == "string") + e.style.cssText = t; + else { + if (typeof s == "string" && (e.style.cssText = s = ""), s) + for (n in s) + t && n in t || rr(e.style, n, ""); + if (t) + for (n in t) + s && t[n] === s[n] || rr(e.style, n, t[n]); + } + else if (n[0] === "o" && n[1] === "n") + o = n !== (n = n.replace(/Capture$/, "")), n = n.toLowerCase() in e ? n.toLowerCase().slice(2) : n.slice(2), e.l || (e.l = {}), e.l[n + o] = t, t ? s || e.addEventListener(n, o ? cr : lr, o) : e.removeEventListener(n, o ? cr : lr, o); + else if (n !== "dangerouslySetInnerHTML") { + if (i) + n = n.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s"); + else if (n !== "width" && n !== "height" && n !== "href" && n !== "list" && n !== "form" && n !== "tabIndex" && n !== "download" && n in e) + try { + e[n] = t ?? ""; + break t; + } catch { + } + typeof t == "function" || (t == null || t === !1 && n[4] !== "-" ? e.removeAttribute(n) : e.setAttribute(n, t)); + } +} +function lr(e) { + return this.l[e.type + !1](z.event ? z.event(e) : e); +} +function cr(e) { + return this.l[e.type + !0](z.event ? z.event(e) : e); +} +function To(e, n, t, s, i, o, r, l, a) { + var h, c, u, d, f, p, g, y, _, v, S, $, T, D, L, O = n.type; + if (n.constructor !== void 0) + return null; + t.__h != null && (a = t.__h, l = n.__e = t.__e, n.__h = null, o = [l]), (h = z.__b) && h(n); + try { + t: + if (typeof O == "function") { + if (y = n.props, _ = (h = O.contextType) && s[h.__c], v = h ? _ ? _.props.value : h.__ : s, t.__c ? g = (c = n.__c = t.__c).__ = c.__E : ("prototype" in O && O.prototype.render ? n.__c = c = new O(y, v) : (n.__c = c = new U(y, v), c.constructor = O, c.render = Pa), _ && _.sub(c), c.props = y, c.state || (c.state = {}), c.context = v, c.__n = s, u = c.__d = !0, c.__h = [], c._sb = []), c.__s == null && (c.__s = c.state), O.getDerivedStateFromProps != null && (c.__s == c.state && (c.__s = Bt({}, c.__s)), Bt(c.__s, O.getDerivedStateFromProps(y, c.__s))), d = c.props, f = c.state, c.__v = n, u) + O.getDerivedStateFromProps == null && c.componentWillMount != null && c.componentWillMount(), c.componentDidMount != null && c.__h.push(c.componentDidMount); + else { + if (O.getDerivedStateFromProps == null && y !== d && c.componentWillReceiveProps != null && c.componentWillReceiveProps(y, v), !c.__e && c.shouldComponentUpdate != null && c.shouldComponentUpdate(y, c.__s, v) === !1 || n.__v === t.__v) { + for (n.__v !== t.__v && (c.props = y, c.state = c.__s, c.__d = !1), c.__e = !1, n.__e = t.__e, n.__k = t.__k, n.__k.forEach(function(k) { + k && (k.__ = n); + }), S = 0; S < c._sb.length; S++) + c.__h.push(c._sb[S]); + c._sb = [], c.__h.length && r.push(c); + break t; + } + c.componentWillUpdate != null && c.componentWillUpdate(y, c.__s, v), c.componentDidUpdate != null && c.__h.push(function() { + c.componentDidUpdate(d, f, p); + }); + } + if (c.context = v, c.props = y, c.__P = e, $ = z.__r, T = 0, "prototype" in O && O.prototype.render) { + for (c.state = c.__s, c.__d = !1, $ && $(n), h = c.render(c.props, c.state, c.context), D = 0; D < c._sb.length; D++) + c.__h.push(c._sb[D]); + c._sb = []; + } else + do + c.__d = !1, $ && $(n), h = c.render(c.props, c.state, c.context), c.state = c.__s; + while (c.__d && ++T < 25); + c.state = c.__s, c.getChildContext != null && (s = Bt(Bt({}, s), c.getChildContext())), u || c.getSnapshotBeforeUpdate == null || (p = c.getSnapshotBeforeUpdate(d, f)), L = h != null && h.type === ls && h.key == null ? h.props.children : h, pl(e, Array.isArray(L) ? L : [L], n, t, s, i, o, r, l, a), c.base = n.__e, n.__h = null, c.__h.length && r.push(c), g && (c.__E = c.__ = null), c.__e = !1; + } else + o == null && n.__v === t.__v ? (n.__k = t.__k, n.__e = t.__e) : n.__e = Oa(t.__e, n, t, s, i, o, r, a); + (h = z.diffed) && h(n); + } catch (k) { + n.__v = null, (a || o != null) && (n.__e = l, n.__h = !!a, o[o.indexOf(l)] = null), z.__e(k, n, t); + } +} +function bl(e, n) { + z.__c && z.__c(n, e), e.some(function(t) { + try { + e = t.__h, t.__h = [], e.some(function(s) { + s.call(t); + }); + } catch (s) { + z.__e(s, t.__v); + } + }); +} +function Oa(e, n, t, s, i, o, r, l) { + var a, h, c, u = t.props, d = n.props, f = n.type, p = 0; + if (f === "svg" && (i = !0), o != null) { + for (; p < o.length; p++) + if ((a = o[p]) && "setAttribute" in a == !!f && (f ? a.localName === f : a.nodeType === 3)) { + e = a, o[p] = null; + break; + } + } + if (e == null) { + if (f === null) + return document.createTextNode(d); + e = i ? document.createElementNS("http://www.w3.org/2000/svg", f) : document.createElement(f, d.is && d), o = null, l = !1; + } + if (f === null) + u === d || l && e.data === d || (e.data = d); + else { + if (o = o && rs.call(e.childNodes), h = (u = t.props || ks).dangerouslySetInnerHTML, c = d.dangerouslySetInnerHTML, !l) { + if (o != null) + for (u = {}, p = 0; p < e.attributes.length; p++) + u[e.attributes[p].name] = e.attributes[p].value; + (c || h) && (c && (h && c.__html == h.__html || c.__html === e.innerHTML) || (e.innerHTML = c && c.__html || "")); + } + if (Ma(e, d, u, i, l), c) + n.__k = []; + else if (p = n.props.children, pl(e, Array.isArray(p) ? p : [p], n, t, s, i && f !== "foreignObject", o, r, o ? o[0] : t.__k && Tn(t, 0), l), o != null) + for (p = o.length; p--; ) + o[p] != null && fl(o[p]); + l || ("value" in d && (p = d.value) !== void 0 && (p !== e.value || f === "progress" && !p || f === "option" && p !== u.value) && As(e, "value", p, u.value, !1), "checked" in d && (p = d.checked) !== void 0 && p !== e.checked && As(e, "checked", p, u.checked, !1)); + } + return e; +} +function wl(e, n, t) { + try { + typeof e == "function" ? e(n) : e.current = n; + } catch (s) { + z.__e(s, t); + } +} +function vl(e, n, t) { + var s, i; + if (z.unmount && z.unmount(e), (s = e.ref) && (s.current && s.current !== e.__e || wl(s, null, n)), (s = e.__c) != null) { + if (s.componentWillUnmount) + try { + s.componentWillUnmount(); + } catch (o) { + z.__e(o, n); + } + s.base = s.__P = null, e.__c = void 0; + } + if (s = e.__k) + for (i = 0; i < s.length; i++) + s[i] && vl(s[i], n, t || typeof e.type != "function"); + t || e.__e == null || fl(e.__e), e.__ = e.__e = e.__d = void 0; +} +function Pa(e, n, t) { + return this.constructor(e, t); +} +function cs(e, n, t) { + var s, i, o; + z.__ && z.__(e, n), i = (s = typeof t == "function") ? null : t && t.__k || n.__k, o = [], To(n, e = (!s && t || n).__k = E(ls, null, [e]), i || ks, ks, n.ownerSVGElement !== void 0, !s && t ? [t] : i ? null : n.firstChild ? rs.call(n.childNodes) : null, o, !s && t ? t : i ? i.__e : n.firstChild, s), bl(o, e); +} +function xl(e, n) { + cs(e, n, xl); +} +function Da(e, n, t) { + var s, i, o, r = Bt({}, e.props); + for (o in n) + o == "key" ? s = n[o] : o == "ref" ? i = n[o] : r[o] = n[o]; + return arguments.length > 2 && (r.children = arguments.length > 3 ? rs.call(arguments, 2) : t), bn(e.type, r, s || e.key, i || e.ref, null); +} +function Ha(e, n) { + var t = { __c: n = "__cC" + ul++, __: e, Consumer: function(s, i) { + return s.children(i); + }, Provider: function(s) { + var i, o; + return this.getChildContext || (i = [], (o = {})[n] = this, this.getChildContext = function() { + return o; + }, this.shouldComponentUpdate = function(r) { + this.props.value !== r.value && i.some(function(l) { + l.__e = !0, po(l); + }); + }, this.sub = function(r) { + i.push(r); + var l = r.componentWillUnmount; + r.componentWillUnmount = function() { + i.splice(i.indexOf(r), 1), l && l.call(r); + }; + }), s.children; + } }; + return t.Provider.__ = t.Consumer.contextType = t; +} +rs = hl.slice, z = { __e: function(e, n, t, s) { + for (var i, o, r; n = n.__; ) + if ((i = n.__c) && !i.__) + try { + if ((o = i.constructor) && o.getDerivedStateFromError != null && (i.setState(o.getDerivedStateFromError(e)), r = i.__d), i.componentDidCatch != null && (i.componentDidCatch(e, s || {}), r = i.__d), r) + return i.__E = i; + } catch (l) { + e = l; + } + throw e; +} }, cl = 0, it = function(e) { + return e != null && e.constructor === void 0; +}, U.prototype.setState = function(e, n) { + var t; + t = this.__s != null && this.__s !== this.state ? this.__s : this.__s = Bt({}, this.state), typeof e == "function" && (e = e(Bt({}, t), this.props)), e && Bt(t, e), e != null && this.__v && (n && this._sb.push(n), po(this)); +}, U.prototype.forceUpdate = function(e) { + this.__v && (this.__e = !0, e && this.__h.push(e), po(this)); +}, U.prototype.render = ls, ye = [], al = typeof Promise == "function" ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, fo = function(e, n) { + return e.__v.__b - n.__v.__b; +}, Ts.__r = 0, ul = 0; +const Ia = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ + __proto__: null, + Component: U, + Fragment: ls, + cloneElement: Da, + createContext: Ha, + createElement: E, + createRef: cn, + h: E, + hydrate: xl, + get isValidElement() { + return it; + }, + get options() { + return z; + }, + render: cs, + toChildArray: gl +}, Symbol.toStringTag, { value: "Module" })); +var ja = 0; +function b(e, n, t, s, i, o) { + var r, l, a = {}; + for (l in n) + l == "ref" ? r = n[l] : a[l] = n[l]; + var h = { type: e, props: a, key: t, ref: r, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, __h: null, constructor: void 0, __v: --ja, __source: i, __self: o }; + if (typeof e == "function" && (r = e.defaultProps)) + for (l in r) + a[l] === void 0 && (a[l] = r[l]); + return z.vnode && z.vnode(h), h; +} +var Dt; +class Wa { + constructor(n = "") { + x(this, Dt, void 0); + typeof n == "object" ? R(this, Dt, n) : R(this, Dt, document.appendChild(document.createComment(n))); + } + on(n, t, s) { + m(this, Dt).addEventListener(n, t, s); + } + once(n, t, s) { + m(this, Dt).addEventListener(n, t, { once: !0, ...s }); + } + off(n, t, s) { + m(this, Dt).removeEventListener(n, t, s); + } + emit(n) { + return m(this, Dt).dispatchEvent(n), n; + } +} +Dt = new WeakMap(); +const mo = /* @__PURE__ */ new Set([ + "click", + "dblclick", + "mouseup", + "mousedown", + "contextmenu", + "mousewheel", + "DOMMouseScroll", + "mouseover", + "mouseout", + "mousemove", + "selectstart", + "selectend", + "keydown", + "keypress", + "keyup", + "orientationchange", + "touchstart", + "touchmove", + "touchend", + "touchcancel", + "pointerdown", + "pointermove", + "pointerup", + "pointerleave", + "pointercancel", + "gesturestart", + "gesturechange", + "gestureend", + "focus", + "blur", + "change", + "reset", + "select", + "submit", + "focusin", + "focusout", + "load", + "unload", + "beforeunload", + "resize", + "move", + "DOMContentLoaded", + "readystatechange", + "error", + "abort", + "scroll" +]); +class Hi extends Wa { + on(n, t, s) { + super.on(n, t, s); + } + off(n, t, s) { + super.off(n, t, s); + } + once(n, t, s) { + super.once(n, t, s); + } + emit(n, t) { + return typeof n == "string" && (mo.has(n) ? (n = new Event(n), Object.assign(n, { detail: t })) : n = new CustomEvent(n, { detail: t })), super.emit(Hi.createEvent(n, t)); + } + static createEvent(n, t) { + return typeof n == "string" && (mo.has(n) ? (n = new Event(n), Object.assign(n, { detail: t })) : n = new CustomEvent(n, { detail: t })), n; + } +} +var Ht, Pn, be, pn; +class ar extends Hi { + constructor(t = "", s) { + super(t); + x(this, be); + x(this, Ht, /* @__PURE__ */ new Map()); + x(this, Pn, void 0); + R(this, Pn, s == null ? void 0 : s.customEventSuffix); + } + on(t, s, i) { + t = N(this, be, pn).call(this, t), super.on(t, s, i), m(this, Ht).set(s, [t, i]); + } + off(t, s, i) { + t = N(this, be, pn).call(this, t), super.off(t, s, i), m(this, Ht).delete(s); + } + once(t, s, i) { + t = N(this, be, pn).call(this, t); + const o = (r) => { + s(r), m(this, Ht).delete(o); + }; + super.once(t, o, i), m(this, Ht).set(o, [t, i]); + } + emit(t, s) { + return typeof t == "string" && (t = N(this, be, pn).call(this, t)), super.emit(t, s); + } + offAll() { + Array.from(m(this, Ht).entries()).forEach(([t, [s, i]]) => { + super.off(s, t, i); + }), m(this, Ht).clear(); + } +} +Ht = new WeakMap(), Pn = new WeakMap(), be = new WeakSet(), pn = function(t) { + const s = m(this, Pn); + return mo.has(t) || typeof s != "string" || t.endsWith(s) ? t : `${t}${s}`; +}; +function Fa(e, n) { + if (e == null) + return [e, void 0]; + typeof n == "string" && (n = n.split(".")); + const t = n.join("."); + let s = e; + const i = [s]; + for (; typeof s == "object" && s !== null && n.length; ) { + let o = n.shift(), r; + const l = o.indexOf("["); + if (l > 0 && l < o.length - 1 && o.endsWith("]") && (r = o.substring(l + 1, o.length - 1), o = o.substring(0, l)), s = s[o], i.push(s), r !== void 0) + if (typeof s == "object" && s !== null) + s instanceof Map ? s = s.get(r) : s = s[r], i.push(s); + else + throw new Error(`Cannot access property "${o}[${r}]", the full path is "${t}".`); + } + if (n.length) + throw new Error(`Cannot access property with rest path "${n.join(".")}", the full path is "${t}".`); + return i; +} +function Ba(e, n, t) { + const s = Fa(e, n), i = s[s.length - 1]; + return i === void 0 ? t : i; +} +function Qi(e) { + return !!e && typeof e == "object" && !Array.isArray(e); +} +function go(e, ...n) { + if (!n.length) + return e; + const t = n.shift(); + if (Qi(e) && Qi(t)) + for (const s in t) + Qi(t[s]) ? (e[s] || Object.assign(e, { [s]: {} }), go(e[s], t[s])) : Object.assign(e, { [s]: t[s] }); + return go(e, ...n); +} +function tt(e, ...n) { + if (n.length === 0) + return e; + if (n.length === 1 && typeof n[0] == "object" && n[0]) { + const t = n[0]; + return Object.keys(t).forEach((s) => { + const i = t[s] ?? 0; + e = e.replace(new RegExp(`\\{${s}\\}`, "g"), `${i}`); + }), e; + } + for (let t = 0; t < n.length; t++) { + const s = n[t] ?? ""; + e = e.replace(new RegExp(`\\{${t}\\}`, "g"), `${s}`); + } + return e; +} +var Ao = /* @__PURE__ */ ((e) => (e[e.B = 1] = "B", e[e.KB = 1024] = "KB", e[e.MB = 1048576] = "MB", e[e.GB = 1073741824] = "GB", e[e.TB = 1099511627776] = "TB", e))(Ao || {}); +function dd(e, n = 2, t = "") { + return Number.isNaN(e) ? "?KB" : (t || (e < 1024 ? t = "B" : e < 1048576 ? t = "KB" : e < 1073741824 ? t = "MB" : e < 1099511627776 ? t = "GB" : t = "TB"), (e / Ao[t]).toFixed(n) + t); +} +const pd = (e) => { + const n = /^[0-9]*(B|KB|MB|GB|TB)$/; + e = e.toUpperCase(); + const t = e.match(n); + if (!t) + return 0; + const s = t[1]; + return e = e.replace(s, ""), Number.parseInt(e, 10) * Ao[s]; +}; +var ll; +let No = ((ll = document.documentElement.getAttribute("lang")) == null ? void 0 : ll.toLowerCase()) ?? "zh_cn", Xt; +function za() { + return No; +} +function Ua(e) { + No = e.toLowerCase(); +} +function Va(e, n) { + Xt || (Xt = {}), typeof e == "string" && (e = { [e]: n ?? {} }), go(Xt, e); +} +function as(e, n, t, s, i, o) { + Array.isArray(e) ? Xt && e.unshift(Xt) : e = Xt ? [Xt, e] : [e], typeof t == "string" && (o = i, i = s, s = t, t = void 0); + const r = i || No; + let l; + for (const a of e) { + if (!a) + continue; + const h = a[r]; + if (!h) + continue; + const c = o && a === Xt ? `${o}.${n}` : n; + if (l = Ba(h, c), l !== void 0) + break; + } + return l === void 0 ? s : t ? tt(l, ...Array.isArray(t) ? t : [t]) : l; +} +as.addLang = Va; +as.getCode = za; +as.setCode = Ua; +function qa(e) { + return Object.fromEntries(Object.entries(e).map(([n, t]) => { + if (typeof t == "string") + try { + t = JSON.parse(t); + } catch { + } + return [n, t]; + })); +} +const Zi = /* @__PURE__ */ new Map(); +var It, De, mt; +class kt { + constructor(n, t) { + x(this, It, void 0); + x(this, De, void 0); + x(this, mt, void 0); + n = typeof n == "string" ? document.querySelector(n) : n, this.constructor.EVENTS && R(this, mt, new ar(n, { customEventSuffix: `.${this.constructor.KEY}` })), R(this, It, { ...this.constructor.DEFAULT }), this.setOptions({ ...n instanceof HTMLElement ? qa(n.dataset) : null, ...t }), this.constructor.all.set(n, this), R(this, De, n), this.init(), requestAnimationFrame(() => { + this.afterInit(), this.emit("inited", this); + }); + } + get options() { + return m(this, It); + } + get element() { + return m(this, De); + } + get events() { + return m(this, mt); + } + init() { + } + afterInit() { + } + setOptions(n) { + return n && Object.assign(m(this, It), n), m(this, It); + } + render(n) { + this.setOptions(n); + } + destroy() { + this.constructor.all.delete(m(this, De)), m(this, mt) && (this.emit("destroyed", this), m(this, mt).offAll()); + } + on(n, t, s) { + var i; + (i = m(this, mt)) == null || i.on(n, t, s); + } + once(n, t, s) { + var i; + (i = m(this, mt)) == null || i.once(n, t, s); + } + off(n, t, s) { + var i; + (i = m(this, mt)) == null || i.off(n, t, s); + } + emit(n, t, s) { + var o; + let i = ar.createEvent(n, t); + if (s !== !1) { + const r = s || `on${n[0].toUpperCase()}${n.substring(1)}`, l = m(this, It)[r]; + l && l(i) === !1 && (i.preventDefault(), i.stopPropagation()); + } + return i = (o = m(this, mt)) == null ? void 0 : o.emit(n, t), i; + } + i18n(n, t, s) { + return as(m(this, It).i18n, n, t, s, this.options.lang, this.constructor.NAME) ?? `{i18n:${n}}`; + } + /** + * Component internal name, like "Menu" + */ + static get NAME() { + throw new Error(`static NAME should be override in class ${this.name}`); + } + /** + * Component data key, like "zui.menu" + */ + static get KEY() { + return `zui.${this.NAME}`; + } + static get all() { + const n = this.NAME; + if (Zi.has(n)) + return Zi.get(n); + const t = /* @__PURE__ */ new Map(); + return Zi.set(n, t), t; + } + static getAll() { + return this.all; + } + static get(n) { + return this.all.get(n); + } + static ensure(n, t) { + return this.get(n) || new this(n, t); + } +} +It = new WeakMap(), De = new WeakMap(), mt = new WeakMap(), w(kt, "EVENTS", !1), w(kt, "DEFAULT", {}); +class J extends kt { + constructor() { + super(...arguments); + w(this, "ref", cn()); + } + get $() { + return this.ref.current; + } + init() { + requestAnimationFrame(() => this.render()); + } + destroy() { + super.destroy(), this.element.innerHTML = ""; + } + render(t) { + const s = this.constructor.Component; + cs(/* @__PURE__ */ b(s, { ref: this.ref, ...this.setOptions(t) }), this.element); + } +} +w(J, "Component"); +var Lo, q, Sl, El, wn, ur, Cl = {}, $l = [], Ga = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; +function ie(e, n) { + for (var t in n) + e[t] = n[t]; + return e; +} +function Rl(e) { + var n = e.parentNode; + n && n.removeChild(e); +} +function an(e, n, t) { + var s, i, o, r = {}; + for (o in n) + o == "key" ? s = n[o] : o == "ref" ? i = n[o] : r[o] = n[o]; + if (arguments.length > 2 && (r.children = arguments.length > 3 ? Lo.call(arguments, 2) : t), typeof e == "function" && e.defaultProps != null) + for (o in e.defaultProps) + r[o] === void 0 && (r[o] = e.defaultProps[o]); + return vs(e, r, s, i, null); +} +function vs(e, n, t, s, i) { + var o = { type: e, props: n, key: t, ref: s, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, __h: null, constructor: void 0, __v: i ?? ++Sl }; + return i == null && q.vnode != null && q.vnode(o), o; +} +function Ka() { + return { current: null }; +} +function Mo(e) { + return e.children; +} +function vn(e, n) { + this.props = e, this.context = n; +} +function An(e, n) { + if (n == null) + return e.__ ? An(e.__, e.__.__k.indexOf(e) + 1) : null; + for (var t; n < e.__k.length; n++) + if ((t = e.__k[n]) != null && t.__e != null) + return t.__e; + return typeof e.type == "function" ? An(e) : null; +} +function kl(e) { + var n, t; + if ((e = e.__) != null && e.__c != null) { + for (e.__e = e.__c.base = null, n = 0; n < e.__k.length; n++) + if ((t = e.__k[n]) != null && t.__e != null) { + e.__e = e.__c.base = t.__e; + break; + } + return kl(e); + } +} +function hr(e) { + (!e.__d && (e.__d = !0) && wn.push(e) && !Ns.__r++ || ur !== q.debounceRendering) && ((ur = q.debounceRendering) || setTimeout)(Ns); +} +function Ns() { + for (var e; Ns.__r = wn.length; ) + e = wn.sort(function(n, t) { + return n.__v.__b - t.__v.__b; + }), wn = [], e.some(function(n) { + var t, s, i, o, r, l; + n.__d && (r = (o = (t = n).__v).__e, (l = t.__P) && (s = [], (i = ie({}, o)).__v = o.__v + 1, Ll(l, o, i, t.__n, l.ownerSVGElement !== void 0, o.__h != null ? [r] : null, s, r ?? An(o), o.__h), Xa(s, o), o.__e != r && kl(o))); + }); +} +function Tl(e, n, t, s, i, o, r, l, a, h) { + var c, u, d, f, p, g, y, _ = s && s.__k || $l, v = _.length; + for (t.__k = [], c = 0; c < n.length; c++) + if ((f = t.__k[c] = (f = n[c]) == null || typeof f == "boolean" ? null : typeof f == "string" || typeof f == "number" || typeof f == "bigint" ? vs(null, f, null, null, f) : Array.isArray(f) ? vs(Mo, { children: f }, null, null, null) : f.__b > 0 ? vs(f.type, f.props, f.key, f.ref ? f.ref : null, f.__v) : f) != null) { + if (f.__ = t, f.__b = t.__b + 1, (d = _[c]) === null || d && f.key == d.key && f.type === d.type) + _[c] = void 0; + else + for (u = 0; u < v; u++) { + if ((d = _[u]) && f.key == d.key && f.type === d.type) { + _[u] = void 0; + break; + } + d = null; + } + Ll(e, f, d = d || Cl, i, o, r, l, a, h), p = f.__e, (u = f.ref) && d.ref != u && (y || (y = []), d.ref && y.push(d.ref, null, f), y.push(u, f.__c || p, f)), p != null ? (g == null && (g = p), typeof f.type == "function" && f.__k === d.__k ? f.__d = a = Al(f, a, e) : a = Nl(e, f, d, _, p, a), typeof t.type == "function" && (t.__d = a)) : a && d.__e == a && a.parentNode != e && (a = An(d)); + } + for (t.__e = g, c = v; c--; ) + _[c] != null && Ol(_[c], _[c]); + if (y) + for (c = 0; c < y.length; c++) + Ml(y[c], y[++c], y[++c]); +} +function Al(e, n, t) { + for (var s, i = e.__k, o = 0; i && o < i.length; o++) + (s = i[o]) && (s.__ = e, n = typeof s.type == "function" ? Al(s, n, t) : Nl(t, s, s, i, s.__e, n)); + return n; +} +function Nl(e, n, t, s, i, o) { + var r, l, a; + if (n.__d !== void 0) + r = n.__d, n.__d = void 0; + else if (t == null || i != o || i.parentNode == null) + t: + if (o == null || o.parentNode !== e) + e.appendChild(i), r = null; + else { + for (l = o, a = 0; (l = l.nextSibling) && a < s.length; a += 2) + if (l == i) + break t; + e.insertBefore(i, o), r = o; + } + return r !== void 0 ? r : i.nextSibling; +} +function Ya(e, n, t, s, i) { + var o; + for (o in t) + o === "children" || o === "key" || o in n || Ls(e, o, null, t[o], s); + for (o in n) + i && typeof n[o] != "function" || o === "children" || o === "key" || o === "value" || o === "checked" || t[o] === n[o] || Ls(e, o, n[o], t[o], s); +} +function fr(e, n, t) { + n[0] === "-" ? e.setProperty(n, t) : e[n] = t == null ? "" : typeof t != "number" || Ga.test(n) ? t : t + "px"; +} +function Ls(e, n, t, s, i) { + var o; + t: + if (n === "style") + if (typeof t == "string") + e.style.cssText = t; + else { + if (typeof s == "string" && (e.style.cssText = s = ""), s) + for (n in s) + t && n in t || fr(e.style, n, ""); + if (t) + for (n in t) + s && t[n] === s[n] || fr(e.style, n, t[n]); + } + else if (n[0] === "o" && n[1] === "n") + o = n !== (n = n.replace(/Capture$/, "")), n = n.toLowerCase() in e ? n.toLowerCase().slice(2) : n.slice(2), e.l || (e.l = {}), e.l[n + o] = t, t ? s || e.addEventListener(n, o ? pr : dr, o) : e.removeEventListener(n, o ? pr : dr, o); + else if (n !== "dangerouslySetInnerHTML") { + if (i) + n = n.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s"); + else if (n !== "href" && n !== "list" && n !== "form" && n !== "tabIndex" && n !== "download" && n in e) + try { + e[n] = t ?? ""; + break t; + } catch { + } + typeof t == "function" || (t == null || t === !1 && n.indexOf("-") == -1 ? e.removeAttribute(n) : e.setAttribute(n, t)); + } +} +function dr(e) { + this.l[e.type + !1](q.event ? q.event(e) : e); +} +function pr(e) { + this.l[e.type + !0](q.event ? q.event(e) : e); +} +function Ll(e, n, t, s, i, o, r, l, a) { + var h, c, u, d, f, p, g, y, _, v, S, $, T, D, L, O = n.type; + if (n.constructor !== void 0) + return null; + t.__h != null && (a = t.__h, l = n.__e = t.__e, n.__h = null, o = [l]), (h = q.__b) && h(n); + try { + t: + if (typeof O == "function") { + if (y = n.props, _ = (h = O.contextType) && s[h.__c], v = h ? _ ? _.props.value : h.__ : s, t.__c ? g = (c = n.__c = t.__c).__ = c.__E : ("prototype" in O && O.prototype.render ? n.__c = c = new O(y, v) : (n.__c = c = new vn(y, v), c.constructor = O, c.render = Qa), _ && _.sub(c), c.props = y, c.state || (c.state = {}), c.context = v, c.__n = s, u = c.__d = !0, c.__h = [], c._sb = []), c.__s == null && (c.__s = c.state), O.getDerivedStateFromProps != null && (c.__s == c.state && (c.__s = ie({}, c.__s)), ie(c.__s, O.getDerivedStateFromProps(y, c.__s))), d = c.props, f = c.state, u) + O.getDerivedStateFromProps == null && c.componentWillMount != null && c.componentWillMount(), c.componentDidMount != null && c.__h.push(c.componentDidMount); + else { + if (O.getDerivedStateFromProps == null && y !== d && c.componentWillReceiveProps != null && c.componentWillReceiveProps(y, v), !c.__e && c.shouldComponentUpdate != null && c.shouldComponentUpdate(y, c.__s, v) === !1 || n.__v === t.__v) { + for (c.props = y, c.state = c.__s, n.__v !== t.__v && (c.__d = !1), c.__v = n, n.__e = t.__e, n.__k = t.__k, n.__k.forEach(function(k) { + k && (k.__ = n); + }), S = 0; S < c._sb.length; S++) + c.__h.push(c._sb[S]); + c._sb = [], c.__h.length && r.push(c); + break t; + } + c.componentWillUpdate != null && c.componentWillUpdate(y, c.__s, v), c.componentDidUpdate != null && c.__h.push(function() { + c.componentDidUpdate(d, f, p); + }); + } + if (c.context = v, c.props = y, c.__v = n, c.__P = e, $ = q.__r, T = 0, "prototype" in O && O.prototype.render) { + for (c.state = c.__s, c.__d = !1, $ && $(n), h = c.render(c.props, c.state, c.context), D = 0; D < c._sb.length; D++) + c.__h.push(c._sb[D]); + c._sb = []; + } else + do + c.__d = !1, $ && $(n), h = c.render(c.props, c.state, c.context), c.state = c.__s; + while (c.__d && ++T < 25); + c.state = c.__s, c.getChildContext != null && (s = ie(ie({}, s), c.getChildContext())), u || c.getSnapshotBeforeUpdate == null || (p = c.getSnapshotBeforeUpdate(d, f)), L = h != null && h.type === Mo && h.key == null ? h.props.children : h, Tl(e, Array.isArray(L) ? L : [L], n, t, s, i, o, r, l, a), c.base = n.__e, n.__h = null, c.__h.length && r.push(c), g && (c.__E = c.__ = null), c.__e = !1; + } else + o == null && n.__v === t.__v ? (n.__k = t.__k, n.__e = t.__e) : n.__e = Ja(t.__e, n, t, s, i, o, r, a); + (h = q.diffed) && h(n); + } catch (k) { + n.__v = null, (a || o != null) && (n.__e = l, n.__h = !!a, o[o.indexOf(l)] = null), q.__e(k, n, t); + } +} +function Xa(e, n) { + q.__c && q.__c(n, e), e.some(function(t) { + try { + e = t.__h, t.__h = [], e.some(function(s) { + s.call(t); + }); + } catch (s) { + q.__e(s, t.__v); + } + }); +} +function Ja(e, n, t, s, i, o, r, l) { + var a, h, c, u = t.props, d = n.props, f = n.type, p = 0; + if (f === "svg" && (i = !0), o != null) { + for (; p < o.length; p++) + if ((a = o[p]) && "setAttribute" in a == !!f && (f ? a.localName === f : a.nodeType === 3)) { + e = a, o[p] = null; + break; + } + } + if (e == null) { + if (f === null) + return document.createTextNode(d); + e = i ? document.createElementNS("http://www.w3.org/2000/svg", f) : document.createElement(f, d.is && d), o = null, l = !1; + } + if (f === null) + u === d || l && e.data === d || (e.data = d); + else { + if (o = o && Lo.call(e.childNodes), h = (u = t.props || Cl).dangerouslySetInnerHTML, c = d.dangerouslySetInnerHTML, !l) { + if (o != null) + for (u = {}, p = 0; p < e.attributes.length; p++) + u[e.attributes[p].name] = e.attributes[p].value; + (c || h) && (c && (h && c.__html == h.__html || c.__html === e.innerHTML) || (e.innerHTML = c && c.__html || "")); + } + if (Ya(e, d, u, i, l), c) + n.__k = []; + else if (p = n.props.children, Tl(e, Array.isArray(p) ? p : [p], n, t, s, i && f !== "foreignObject", o, r, o ? o[0] : t.__k && An(t, 0), l), o != null) + for (p = o.length; p--; ) + o[p] != null && Rl(o[p]); + l || ("value" in d && (p = d.value) !== void 0 && (p !== e.value || f === "progress" && !p || f === "option" && p !== u.value) && Ls(e, "value", p, u.value, !1), "checked" in d && (p = d.checked) !== void 0 && p !== e.checked && Ls(e, "checked", p, u.checked, !1)); + } + return e; +} +function Ml(e, n, t) { + try { + typeof e == "function" ? e(n) : e.current = n; + } catch (s) { + q.__e(s, t); + } +} +function Ol(e, n, t) { + var s, i; + if (q.unmount && q.unmount(e), (s = e.ref) && (s.current && s.current !== e.__e || Ml(s, null, n)), (s = e.__c) != null) { + if (s.componentWillUnmount) + try { + s.componentWillUnmount(); + } catch (o) { + q.__e(o, n); + } + s.base = s.__P = null, e.__c = void 0; + } + if (s = e.__k) + for (i = 0; i < s.length; i++) + s[i] && Ol(s[i], n, t || typeof e.type != "function"); + t || e.__e == null || Rl(e.__e), e.__ = e.__e = e.__d = void 0; +} +function Qa(e, n, t) { + return this.constructor(e, t); +} +Lo = $l.slice, q = { __e: function(e, n, t, s) { + for (var i, o, r; n = n.__; ) + if ((i = n.__c) && !i.__) + try { + if ((o = i.constructor) && o.getDerivedStateFromError != null && (i.setState(o.getDerivedStateFromError(e)), r = i.__d), i.componentDidCatch != null && (i.componentDidCatch(e, s || {}), r = i.__d), r) + return i.__E = i; + } catch (l) { + e = l; + } + throw e; +} }, Sl = 0, El = function(e) { + return e != null && e.constructor === void 0; +}, vn.prototype.setState = function(e, n) { + var t; + t = this.__s != null && this.__s !== this.state ? this.__s : this.__s = ie({}, this.state), typeof e == "function" && (e = e(ie({}, t), this.props)), e && ie(t, e), e != null && this.__v && (n && this._sb.push(n), hr(this)); +}, vn.prototype.forceUpdate = function(e) { + this.__v && (this.__e = !0, e && this.__h.push(e), hr(this)); +}, vn.prototype.render = Mo, wn = [], Ns.__r = 0; +var Za = 0; +function ft(e, n, t, s, i) { + var o, r, l = {}; + for (r in n) + r == "ref" ? o = n[r] : l[r] = n[r]; + var a = { type: e, props: l, key: t, ref: o, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, __h: null, constructor: void 0, __v: --Za, __source: i, __self: s }; + if (typeof e == "function" && (o = e.defaultProps)) + for (r in o) + l[r] === void 0 && (l[r] = o[r]); + return q.vnode && q.vnode(a), a; +} +function Ii(...e) { + const n = [], t = /* @__PURE__ */ new Map(), s = (i, o) => { + if (Array.isArray(i) && (o = i[1], i = i[0]), !i.length) + return; + const r = t.get(i); + typeof r == "number" ? n[r][1] = !!o : (t.set(i, n.length), n.push([i, !!o])); + }; + return e.forEach((i) => { + typeof i == "function" && (i = i()), Array.isArray(i) ? Ii(...i).forEach(s) : i && typeof i == "object" ? Object.entries(i).forEach(s) : typeof i == "string" && i.split(" ").forEach((o) => s(o, !0)); + }), n.sort((i, o) => (t.get(i[0]) || 0) - (t.get(o[0]) || 0)); +} +const M = (...e) => Ii(...e).reduce((n, [t, s]) => (s && n.push(t), n), []).join(" "); +function tu({ + component: e = "div", + className: n, + children: t, + style: s, + attrs: i +}) { + return an(e, { + className: M(n), + style: s, + ...i + }, t); +} +function Pl({ + component: e = "a", + className: n, + children: t, + attrs: s, + url: i, + disabled: o, + active: r, + icon: l, + text: a, + target: h, + trailingIcon: c, + hint: u, + onClick: d, + ...f +}) { + const p = [ + typeof l == "string" ? /* @__PURE__ */ ft("i", { class: `icon ${l}` }) : l, + /* @__PURE__ */ ft("span", { className: "text", children: a }), + typeof t == "function" ? t() : t, + typeof c == "string" ? /* @__PURE__ */ ft("i", { class: `icon ${c}` }) : c + ]; + return an(e, { + className: M(n, { disabled: o, active: r }), + title: u, + [e === "a" ? "href" : "data-url"]: i, + [e === "a" ? "target" : "data-target"]: h, + onClick: d, + ...f, + ...s + }, ...p); +} +function eu({ + component: e = "div", + className: n, + text: t, + attrs: s, + children: i, + style: o, + onClick: r +}) { + return an(e, { + className: M(n), + style: o, + onClick: r, + ...s + }, t, typeof i == "function" ? i() : i); +} +function nu({ + component: e = "div", + className: n, + style: t, + space: s, + flex: i, + attrs: o, + onClick: r, + children: l +}) { + return an(e, { + className: M(n), + style: { width: s, height: s, flex: i, ...t }, + onClick: r, + ...o + }, l); +} +function su(e) { + const { + tag: n, + className: t, + style: s, + renders: i, + generateArgs: o = [], + generatorThis: r, + generators: l, + onGenerate: a, + onRenderItem: h, + ...c + } = e, u = [t], d = { ...s }, f = [], p = []; + return i.forEach((g) => { + const y = []; + typeof g == "string" && l && l[g] && (g = l[g]), typeof g == "function" ? a ? y.push(...a.call(r, g, f, ...o)) : y.push(...g.call(r, f, ...o) ?? []) : y.push(g), y.forEach((_) => { + _ != null && (typeof _ == "object" && !it(_) && ("html" in _ || "__html" in _ || "className" in _ || "style" in _ || "attrs" in _ || "children" in _) ? _.html ? f.push( + /* @__PURE__ */ b("div", { className: M(_.className), style: _.style, dangerouslySetInnerHTML: { __html: _.html }, ..._.attrs ?? {} }) + ) : _.__html ? p.push(_.__html) : (_.style && Object.assign(d, _.style), _.className && u.push(_.className), _.children && f.push(_.children), _.attrs && Object.assign(c, _.attrs)) : f.push(_)); + }); + }), p.length && Object.assign(c, { dangerouslySetInnerHTML: { __html: p } }), [{ + className: M(u), + style: d, + ...c + }, f]; +} +function yo({ + tag: e = "div", + ...n +}) { + const [t, s] = su(n); + return E(e, t, ...s); +} +function iu({ type: e, ...n }) { + return /* @__PURE__ */ ft(yo, { ...n }); +} +function Dl({ + component: e = "div", + className: n, + children: t, + style: s, + attrs: i +}) { + return an(e, { + className: M(n), + style: s, + ...i + }, t); +} +var Ft; +let ji = (Ft = class extends vn { + constructor() { + super(...arguments); + w(this, "ref", Ka()); + } + get name() { + return this.props.name ?? this.constructor.NAME; + } + componentDidMount() { + this.afterRender(!0); + } + componentDidUpdate() { + this.afterRender(!1); + } + componentWillUnmount() { + var t, s; + (s = (t = this.props).beforeDestroy) == null || s.call(t, { menu: this }); + } + afterRender(t) { + var s, i; + (i = (s = this.props).afterRender) == null || i.call(s, { menu: this, firstRender: t }); + } + handleItemClick(t, s, i, o) { + i && i.call(o.target, o); + const { onClickItem: r } = this.props; + r && r({ menu: this, item: t, index: s, event: o }); + } + beforeRender() { + var i; + const t = { ...this.props }; + typeof t.items == "function" && (t.items = t.items(this)); + const s = (i = t.beforeRender) == null ? void 0 : i.call(t, { menu: this, options: t }); + return s && Object.assign(t, s), t; + } + getItemRenderProps(t, s, i) { + const { commonItemProps: o, onClickItem: r } = t, l = { key: i, ...s }; + return o && Object.assign(l, o[s.type || "item"]), (r || s.onClick) && (l.onClick = this.handleItemClick.bind(this, l, i, s.onClick)), l.className = M(l.className), l; + } + renderItem(t, s, i) { + const o = this.getItemRenderProps(t, s, i), { itemRender: r } = t; + if (r) { + if (typeof r == "object") { + const y = r[s.type || "item"]; + if (y) + return /* @__PURE__ */ ft(y, { ...o }); + } else if (typeof r == "function") { + const y = r.call(this, o, an); + if (El(y)) + return y; + typeof y == "object" && Object.assign(o, y); + } + } + const { type: l = "item", component: a, key: h = i, rootAttrs: c, rootClass: u, rootStyle: d, rootChildren: f, ...p } = o; + if (l === "html") + return /* @__PURE__ */ ft( + "li", + { + className: M("action-menu-item", `${this.name}-html`, u, p.className), + ...c, + style: d || p.style, + dangerouslySetInnerHTML: { __html: p.html } + }, + h + ); + const g = !a || typeof a == "string" ? this.constructor.ItemComponents && this.constructor.ItemComponents[l] || Ft.ItemComponents[l] : a; + return Object.assign(p, { + type: l, + component: typeof a == "string" ? a : void 0 + }), this.renderTypedItem(g, { + className: M(u), + children: f, + style: d, + key: h, + ...c + }, { + ...p, + type: l, + component: typeof a == "string" ? a : void 0 + }); + } + renderTypedItem(t, s, i) { + const { children: o, className: r, key: l, ...a } = s, { activeClass: h = "", activeKey: c, activeIcon: u } = this.props, d = u && c === l ? /* @__PURE__ */ ft("i", { className: `checked icon icon-${u}` }) : null, f = c === l; + return /* @__PURE__ */ ft( + "li", + { + className: M("action-menu-item", `${this.name}-${i.type}`, r, { [h]: f }), + ...a, + children: [ + /* @__PURE__ */ ft(t, { ...i }), + d, + typeof o == "function" ? o() : o + ] + }, + l + ); + } + render() { + const t = this.beforeRender(), { + name: s, + style: i, + commonItemProps: o, + className: r, + items: l, + children: a, + itemRender: h, + onClickItem: c, + beforeRender: u, + afterRender: d, + beforeDestroy: f, + activeClass: p, + activeKey: g, + ...y + } = t, _ = this.constructor.ROOT_TAG; + return /* @__PURE__ */ ft(_, { class: M(this.name, r), style: i, ...y, ref: this.ref, children: [ + l && l.map(this.renderItem.bind(this, t)), + a + ] }); + } +}, w(Ft, "ItemComponents", { + divider: tu, + item: Pl, + heading: eu, + space: nu, + custom: iu, + basic: Dl +}), w(Ft, "ROOT_TAG", "menu"), w(Ft, "NAME", "action-menu"), Ft); +class mr extends J { +} +w(mr, "NAME", "actionmenu"), w(mr, "Component", ji); +function gr({ + ...e +}) { + return /* @__PURE__ */ ft(Pl, { ...e }); +} +var lo, Dn, wt, He; +let Hl = (lo = class extends ji { + constructor(t) { + super(t); + x(this, Dn, /* @__PURE__ */ new Set()); + x(this, wt, void 0); + x(this, He, (t, s, i) => { + this.toggleNestedMenu(t, s), i.preventDefault(); + }); + R(this, wt, t.nestedShow === void 0), m(this, wt) && (this.state = { nestedShow: t.defaultNestedShow ?? {} }); + } + get nestedTrigger() { + return this.props.nestedTrigger; + } + beforeRender() { + const t = super.beforeRender(), { nestedShow: s, nestedTrigger: i, defaultNestedShow: o, controlledMenu: r, ...l } = t; + return l; + } + renderNestedMenu(t) { + let { items: s } = t; + if (!s || (typeof s == "function" && (s = s(t, this)), !s.length)) + return; + const i = this.constructor, { name: o, controlledMenu: r, nestedShow: l, beforeDestroy: a, beforeRender: h, itemRender: c, activeClass: u, activeKey: d, onClickItem: f, afterRender: p, commonItemProps: g, activeIcon: y } = this.props; + return /* @__PURE__ */ ft( + i, + { + items: s, + name: o, + nestedShow: m(this, wt) ? this.state.nestedShow : l, + nestedTrigger: this.nestedTrigger, + controlledMenu: r || this, + commonItemProps: g, + onClickItem: f, + afterRender: p, + beforeRender: h, + beforeDestroy: a, + itemRender: c, + activeClass: u, + activeKey: d, + activeIcon: y + } + ); + } + isNestedItem(t) { + return (!t.type || t.type === "item") && !!t.items; + } + renderToggleIcon(t, s) { + } + getItemRenderProps(t, s, i) { + const o = super.getItemRenderProps(t, s, i); + if (!this.isNestedItem(o)) + return o; + const r = o.key ?? i; + m(this, Dn).add(r); + const l = this.isNestedMenuShow(r); + if (l && (o.rootChildren = [ + o.rootChildren, + this.renderNestedMenu(s) + ], o.component = gr), this.nestedTrigger === "hover") + o.rootAttrs = { + ...o.rootAttrs, + onMouseEnter: m(this, He).bind(this, r, !0), + onMouseLeave: m(this, He).bind(this, r, !1) + }; + else if (this.nestedTrigger === "click") { + const { onClick: h } = o; + o.onClick = (c) => { + m(this, He).call(this, r, void 0, c), h == null || h(c); + }; + } + const a = this.renderToggleIcon(l, o); + return a && (o.children = [o.children, a]), o.rootClass = [o.rootClass, "has-nested-menu", l ? "show" : ""], o; + } + isNestedMenuShow(t) { + const s = m(this, wt) ? this.state.nestedShow : this.props.nestedShow; + return s && typeof s == "object" ? s[t] : !!s; + } + toggleNestedMenu(t, s) { + const { controlledMenu: i } = this.props; + if (i) + return i.toggleNestedMenu(t, s); + if (!m(this, wt)) + return !1; + let { nestedShow: o = {} } = this.state; + if (typeof o == "boolean" && (o === !0 ? o = [...m(this, Dn).values()].reduce((r, l) => (r[l] = !0, r), {}) : o = {}), s === void 0) + s = !o[t]; + else if (!!o[t] == !!s) + return !1; + return s ? o[t] = s : delete o[t], this.setState({ nestedShow: { ...o } }), !0; + } + showNestedMenu(t) { + return this.toggleNestedMenu(t, !0); + } + hideNestedMenu(t) { + return this.toggleNestedMenu(t, !1); + } + showAllNestedMenu() { + m(this, wt) && this.setState({ nestedShow: !0 }); + } + hideAllNestedMenu() { + m(this, wt) && this.setState({ nestedShow: !1 }); + } +}, Dn = new WeakMap(), wt = new WeakMap(), He = new WeakMap(), w(lo, "ItemComponents", { + item: gr +}), lo); +class yr extends J { +} +w(yr, "NAME", "actionmenunested"), w(yr, "Component", Hl); +let Tt = class extends U { + render() { + const { + component: n, + type: t, + btnType: s, + size: i, + className: o, + children: r, + url: l, + target: a, + disabled: h, + active: c, + loading: u, + loadingIcon: d, + loadingText: f, + icon: p, + text: g, + trailingIcon: y, + caret: _, + square: v, + hint: S, + ...$ + } = this.props, T = n || (l ? "a" : "button"), D = g == null || typeof g == "string" && !g.length || u && !f, L = _ && D && !p && !y && !r && !u; + return E( + T, + { + className: M("btn", t, o, { + "btn-caret": L, + disabled: h || u, + active: c, + loading: u, + square: v === void 0 ? !L && !r && D : v + }, i ? `size-${i}` : ""), + title: S, + [T === "a" ? "href" : "data-url"]: l, + [T === "a" ? "target" : "data-target"]: a, + type: T === "button" ? s : void 0, + ...$ + }, + u ? /* @__PURE__ */ b("i", { class: `spin icon ${d || "icon-spinner-snake"}` }) : typeof p == "string" ? /* @__PURE__ */ b("i", { class: `icon ${p}` }) : p, + D ? null : /* @__PURE__ */ b("span", { className: "text", children: u ? f : g }), + u ? null : r, + u ? null : typeof y == "string" ? /* @__PURE__ */ b("i", { class: `icon ${y}` }) : y, + u ? null : _ ? /* @__PURE__ */ b("span", { className: typeof _ == "string" ? `caret-${_}` : "caret" }) : null + ); + } +}; +class _r extends J { +} +w(_r, "NAME", "button"), w(_r, "Component", Tt); +var co; +let oe = (co = class extends Hl { + get nestedTrigger() { + return this.props.nestedTrigger || "click"; + } + get menuName() { + return "menu-nested"; + } + beforeRender() { + const n = super.beforeRender(); + let { hasIcons: t } = n; + return t === void 0 && (t = n.items.some((s) => s.icon)), n.className = M(n.className, this.menuName, { + "has-icons": t, + "has-nested-items": n.items.some((s) => this.isNestedItem(s)), + "menu-popup": n.popup + }), n; + } + renderToggleIcon(n) { + return /* @__PURE__ */ b("span", { class: `${this.name}-toggle-icon caret-${n ? "down" : "right"}` }); + } +}, w(co, "NAME", "menu"), co); +class br extends J { +} +w(br, "NAME", "menu"), w(br, "Component", oe); +let us = (e = 21) => crypto.getRandomValues(new Uint8Array(e)).reduce((n, t) => (t &= 63, t < 36 ? n += t.toString(36) : t < 62 ? n += (t - 26).toString(36).toUpperCase() : t > 62 ? n += "-" : n += "_", n), ""); +const Ut = document, Ms = window, Il = Ut.documentElement, Te = Ut.createElement.bind(Ut), jl = Te("div"), to = Te("table"), ou = Te("tbody"), wr = Te("tr"), { isArray: Wi, prototype: Wl } = Array, { concat: ru, filter: Oo, indexOf: Fl, map: Bl, push: lu, slice: zl, some: Po, splice: cu } = Wl, au = /^#(?:[\w-]|\\.|[^\x00-\xa0])*$/, uu = /^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/, hu = /<.+>/, fu = /^\w+$/; +function Do(e, n) { + const t = du(n); + return !e || !t && !ln(n) && !X(n) ? [] : !t && uu.test(e) ? n.getElementsByClassName(e.slice(1).replace(/\\/g, "")) : !t && fu.test(e) ? n.getElementsByTagName(e) : n.querySelectorAll(e); +} +class Fi { + constructor(n, t) { + if (!n) + return; + if (_o(n)) + return n; + let s = n; + if (ot(n)) { + const i = (_o(t) ? t[0] : t) || Ut; + if (s = au.test(n) && "getElementById" in i ? i.getElementById(n.slice(1).replace(/\\/g, "")) : hu.test(n) ? ql(n) : Do(n, i), !s) + return; + } else if (Ae(n)) + return this.ready(n); + (s.nodeType || s === Ms) && (s = [s]), this.length = s.length; + for (let i = 0, o = this.length; i < o; i++) + this[i] = s[i]; + } + init(n, t) { + return new Fi(n, t); + } +} +const C = Fi.prototype, A = C.init; +A.fn = A.prototype = C; +C.length = 0; +C.splice = cu; +typeof Symbol == "function" && (C[Symbol.iterator] = Wl[Symbol.iterator]); +function _o(e) { + return e instanceof Fi; +} +function rn(e) { + return !!e && e === e.window; +} +function ln(e) { + return !!e && e.nodeType === 9; +} +function du(e) { + return !!e && e.nodeType === 11; +} +function X(e) { + return !!e && e.nodeType === 1; +} +function pu(e) { + return !!e && e.nodeType === 3; +} +function mu(e) { + return typeof e == "boolean"; +} +function Ae(e) { + return typeof e == "function"; +} +function ot(e) { + return typeof e == "string"; +} +function ct(e) { + return e === void 0; +} +function Nn(e) { + return e === null; +} +function Ul(e) { + return !isNaN(parseFloat(e)) && isFinite(e); +} +function Ho(e) { + if (typeof e != "object" || e === null) + return !1; + const n = Object.getPrototypeOf(e); + return n === null || n === Object.prototype; +} +A.isWindow = rn; +A.isFunction = Ae; +A.isArray = Wi; +A.isNumeric = Ul; +A.isPlainObject = Ho; +function Z(e, n, t) { + if (t) { + let s = e.length; + for (; s--; ) + if (n.call(e[s], s, e[s]) === !1) + return e; + } else if (Ho(e)) { + const s = Object.keys(e); + for (let i = 0, o = s.length; i < o; i++) { + const r = s[i]; + if (n.call(e[r], r, e[r]) === !1) + return e; + } + } else + for (let s = 0, i = e.length; s < i; s++) + if (n.call(e[s], s, e[s]) === !1) + return e; + return e; +} +A.each = Z; +C.each = function(e) { + return Z(this, e); +}; +C.empty = function() { + return this.each((e, n) => { + for (; n.firstChild; ) + n.removeChild(n.firstChild); + }); +}; +function Os(...e) { + const n = mu(e[0]) ? e.shift() : !1, t = e.shift(), s = e.length; + if (!t) + return {}; + if (!s) + return Os(n, A, t); + for (let i = 0; i < s; i++) { + const o = e[i]; + for (const r in o) + n && (Wi(o[r]) || Ho(o[r])) ? ((!t[r] || t[r].constructor !== o[r].constructor) && (t[r] = new o[r].constructor()), Os(n, t[r], o[r])) : t[r] = o[r]; + } + return t; +} +A.extend = Os; +C.extend = function(e) { + return Os(C, e); +}; +const gu = /\S+/g; +function Bi(e) { + return ot(e) ? e.match(gu) || [] : []; +} +C.toggleClass = function(e, n) { + const t = Bi(e), s = !ct(n); + return this.each((i, o) => { + X(o) && Z(t, (r, l) => { + s ? n ? o.classList.add(l) : o.classList.remove(l) : o.classList.toggle(l); + }); + }); +}; +C.addClass = function(e) { + return this.toggleClass(e, !0); +}; +C.removeAttr = function(e) { + const n = Bi(e); + return this.each((t, s) => { + X(s) && Z(n, (i, o) => { + s.removeAttribute(o); + }); + }); +}; +function yu(e, n) { + if (e) { + if (ot(e)) { + if (arguments.length < 2) { + if (!this[0] || !X(this[0])) + return; + const t = this[0].getAttribute(e); + return Nn(t) ? void 0 : t; + } + return ct(n) ? this : Nn(n) ? this.removeAttr(e) : this.each((t, s) => { + X(s) && s.setAttribute(e, n); + }); + } + for (const t in e) + this.attr(t, e[t]); + return this; + } +} +C.attr = yu; +C.removeClass = function(e) { + return arguments.length ? this.toggleClass(e, !1) : this.attr("class", ""); +}; +C.hasClass = function(e) { + return !!e && Po.call(this, (n) => X(n) && n.classList.contains(e)); +}; +C.get = function(e) { + return ct(e) ? zl.call(this) : (e = Number(e), this[e < 0 ? e + this.length : e]); +}; +C.eq = function(e) { + return A(this.get(e)); +}; +C.first = function() { + return this.eq(0); +}; +C.last = function() { + return this.eq(-1); +}; +function _u(e) { + return ct(e) ? this.get().map((n) => X(n) || pu(n) ? n.textContent : "").join("") : this.each((n, t) => { + X(t) && (t.textContent = e); + }); +} +C.text = _u; +function Vt(e, n, t) { + if (!X(e)) + return; + const s = Ms.getComputedStyle(e, null); + return t ? s.getPropertyValue(n) || void 0 : s[n] || e.style[n]; +} +function Ct(e, n) { + return parseInt(Vt(e, n), 10) || 0; +} +function vr(e, n) { + return Ct(e, `border${n ? "Left" : "Top"}Width`) + Ct(e, `padding${n ? "Left" : "Top"}`) + Ct(e, `padding${n ? "Right" : "Bottom"}`) + Ct(e, `border${n ? "Right" : "Bottom"}Width`); +} +const eo = {}; +function bu(e) { + if (eo[e]) + return eo[e]; + const n = Te(e); + Ut.body.insertBefore(n, null); + const t = Vt(n, "display"); + return Ut.body.removeChild(n), eo[e] = t !== "none" ? t : "block"; +} +function xr(e) { + return Vt(e, "display") === "none"; +} +function Vl(e, n) { + const t = e && (e.matches || e.webkitMatchesSelector || e.msMatchesSelector); + return !!t && !!n && t.call(e, n); +} +function zi(e) { + return ot(e) ? (n, t) => Vl(t, e) : Ae(e) ? e : _o(e) ? (n, t) => e.is(t) : e ? (n, t) => t === e : () => !1; +} +C.filter = function(e) { + const n = zi(e); + return A(Oo.call(this, (t, s) => n.call(t, s, t))); +}; +function he(e, n) { + return n ? e.filter(n) : e; +} +C.detach = function(e) { + return he(this, e).each((n, t) => { + t.parentNode && t.parentNode.removeChild(t); + }), this; +}; +const wu = /^\s*<(\w+)[^>]*>/, vu = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, Sr = { + "*": jl, + tr: ou, + td: wr, + th: wr, + thead: to, + tbody: to, + tfoot: to +}; +function ql(e) { + if (!ot(e)) + return []; + if (vu.test(e)) + return [Te(RegExp.$1)]; + const n = wu.test(e) && RegExp.$1, t = Sr[n] || Sr["*"]; + return t.innerHTML = e, A(t.childNodes).detach().get(); +} +A.parseHTML = ql; +C.has = function(e) { + const n = ot(e) ? (t, s) => Do(e, s).length : (t, s) => s.contains(e); + return this.filter(n); +}; +C.not = function(e) { + const n = zi(e); + return this.filter((t, s) => (!ot(e) || X(s)) && !n.call(s, t, s)); +}; +function Kt(e, n, t, s) { + const i = [], o = Ae(n), r = s && zi(s); + for (let l = 0, a = e.length; l < a; l++) + if (o) { + const h = n(e[l]); + h.length && lu.apply(i, h); + } else { + let h = e[l][n]; + for (; h != null && !(s && r(-1, h)); ) + i.push(h), h = t ? h[n] : null; + } + return i; +} +function Gl(e) { + return e.multiple && e.options ? Kt(Oo.call(e.options, (n) => n.selected && !n.disabled && !n.parentNode.disabled), "value") : e.value || ""; +} +function xu(e) { + return arguments.length ? this.each((n, t) => { + const s = t.multiple && t.options; + if (s || ec.test(t.type)) { + const i = Wi(e) ? Bl.call(e, String) : Nn(e) ? [] : [String(e)]; + s ? Z(t.options, (o, r) => { + r.selected = i.indexOf(r.value) >= 0; + }, !0) : t.checked = i.indexOf(t.value) >= 0; + } else + t.value = ct(e) || Nn(e) ? "" : e; + }) : this[0] && Gl(this[0]); +} +C.val = xu; +C.is = function(e) { + const n = zi(e); + return Po.call(this, (t, s) => n.call(t, s, t)); +}; +A.guid = 1; +function At(e) { + return e.length > 1 ? Oo.call(e, (n, t, s) => Fl.call(s, n) === t) : e; +} +A.unique = At; +C.add = function(e, n) { + return A(At(this.get().concat(A(e, n).get()))); +}; +C.children = function(e) { + return he(A(At(Kt(this, (n) => n.children))), e); +}; +C.parent = function(e) { + return he(A(At(Kt(this, "parentNode"))), e); +}; +C.index = function(e) { + const n = e ? A(e)[0] : this[0], t = e ? this : A(n).parent().children(); + return Fl.call(t, n); +}; +C.closest = function(e) { + const n = this.filter(e); + if (n.length) + return n; + const t = this.parent(); + return t.length ? t.closest(e) : n; +}; +C.siblings = function(e) { + return he(A(At(Kt(this, (n) => A(n).parent().children().not(n)))), e); +}; +C.find = function(e) { + return A(At(Kt(this, (n) => Do(e, n)))); +}; +const Su = /^\s*\s*$/g, Eu = /^$|^module$|\/(java|ecma)script/i, Cu = ["type", "src", "nonce", "noModule"]; +function $u(e, n) { + const t = A(e); + t.filter("script").add(t.find("script")).each((s, i) => { + if (Eu.test(i.type) && Il.contains(i)) { + const o = Te("script"); + o.text = i.textContent.replace(Su, ""), Z(Cu, (r, l) => { + i[l] && (o[l] = i[l]); + }), n.head.insertBefore(o, null), n.head.removeChild(o); + } + }); +} +function Ru(e, n, t, s, i) { + s ? e.insertBefore(n, t ? e.firstChild : null) : e.nodeName === "HTML" ? e.parentNode.replaceChild(n, e) : e.parentNode.insertBefore(n, t ? e : e.nextSibling), i && $u(n, e.ownerDocument); +} +function fe(e, n, t, s, i, o, r, l) { + return Z(e, (a, h) => { + Z(A(h), (c, u) => { + Z(A(n), (d, f) => { + const p = t ? u : f, g = t ? f : u, y = t ? c : d; + Ru(p, y ? g.cloneNode(!0) : g, s, i, !y); + }, l); + }, r); + }, o), n; +} +C.after = function() { + return fe(arguments, this, !1, !1, !1, !0, !0); +}; +C.append = function() { + return fe(arguments, this, !1, !1, !0); +}; +function ku(e) { + if (!arguments.length) + return this[0] && this[0].innerHTML; + if (ct(e)) + return this; + const n = /]/.test(e); + return this.each((t, s) => { + X(s) && (n ? A(s).empty().append(e) : s.innerHTML = e); + }); +} +C.html = ku; +C.appendTo = function(e) { + return fe(arguments, this, !0, !1, !0); +}; +C.wrapInner = function(e) { + return this.each((n, t) => { + const s = A(t), i = s.contents(); + i.length ? i.wrapAll(e) : s.append(e); + }); +}; +C.before = function() { + return fe(arguments, this, !1, !0); +}; +C.wrapAll = function(e) { + let n = A(e), t = n[0]; + for (; t.children.length; ) + t = t.firstElementChild; + return this.first().before(n), this.appendTo(t); +}; +C.wrap = function(e) { + return this.each((n, t) => { + const s = A(e)[0]; + A(t).wrapAll(n ? s.cloneNode(!0) : s); + }); +}; +C.insertAfter = function(e) { + return fe(arguments, this, !0, !1, !1, !1, !1, !0); +}; +C.insertBefore = function(e) { + return fe(arguments, this, !0, !0); +}; +C.prepend = function() { + return fe(arguments, this, !1, !0, !0, !0, !0); +}; +C.prependTo = function(e) { + return fe(arguments, this, !0, !0, !0, !1, !1, !0); +}; +C.contents = function() { + return A(At(Kt(this, (e) => e.tagName === "IFRAME" ? [e.contentDocument] : e.tagName === "TEMPLATE" ? e.content.childNodes : e.childNodes))); +}; +C.next = function(e, n, t) { + return he(A(At(Kt(this, "nextElementSibling", n, t))), e); +}; +C.nextAll = function(e) { + return this.next(e, !0); +}; +C.nextUntil = function(e, n) { + return this.next(n, !0, e); +}; +C.parents = function(e, n) { + return he(A(At(Kt(this, "parentElement", !0, n))), e); +}; +C.parentsUntil = function(e, n) { + return this.parents(n, e); +}; +C.prev = function(e, n, t) { + return he(A(At(Kt(this, "previousElementSibling", n, t))), e); +}; +C.prevAll = function(e) { + return this.prev(e, !0); +}; +C.prevUntil = function(e, n) { + return this.prev(n, !0, e); +}; +C.map = function(e) { + return A(ru.apply([], Bl.call(this, (n, t) => e.call(n, t, n)))); +}; +C.clone = function() { + return this.map((e, n) => n.cloneNode(!0)); +}; +C.offsetParent = function() { + return this.map((e, n) => { + let t = n.offsetParent; + for (; t && Vt(t, "position") === "static"; ) + t = t.offsetParent; + return t || Il; + }); +}; +C.slice = function(e, n) { + return A(zl.call(this, e, n)); +}; +const Tu = /-([a-z])/g; +function Io(e) { + return e.replace(Tu, (n, t) => t.toUpperCase()); +} +C.ready = function(e) { + const n = () => setTimeout(e, 0, A); + return Ut.readyState !== "loading" ? n() : Ut.addEventListener("DOMContentLoaded", n), this; +}; +C.unwrap = function() { + return this.parent().each((e, n) => { + if (n.tagName === "BODY") + return; + const t = A(n); + t.replaceWith(t.children()); + }), this; +}; +C.offset = function() { + const e = this[0]; + if (!e) + return; + const n = e.getBoundingClientRect(); + return { + top: n.top + Ms.pageYOffset, + left: n.left + Ms.pageXOffset + }; +}; +C.position = function() { + const e = this[0]; + if (!e) + return; + const n = Vt(e, "position") === "fixed", t = n ? e.getBoundingClientRect() : this.offset(); + if (!n) { + const s = e.ownerDocument; + let i = e.offsetParent || s.documentElement; + for (; (i === s.body || i === s.documentElement) && Vt(i, "position") === "static"; ) + i = i.parentNode; + if (i !== e && X(i)) { + const o = A(i).offset(); + t.top -= o.top + Ct(i, "borderTopWidth"), t.left -= o.left + Ct(i, "borderLeftWidth"); + } + } + return { + top: t.top - Ct(e, "marginTop"), + left: t.left - Ct(e, "marginLeft") + }; +}; +const Kl = { + /* GENERAL */ + class: "className", + contenteditable: "contentEditable", + /* LABEL */ + for: "htmlFor", + /* INPUT */ + readonly: "readOnly", + maxlength: "maxLength", + tabindex: "tabIndex", + /* TABLE */ + colspan: "colSpan", + rowspan: "rowSpan", + /* IMAGE */ + usemap: "useMap" +}; +C.prop = function(e, n) { + if (e) { + if (ot(e)) + return e = Kl[e] || e, arguments.length < 2 ? this[0] && this[0][e] : this.each((t, s) => { + s[e] = n; + }); + for (const t in e) + this.prop(t, e[t]); + return this; + } +}; +C.removeProp = function(e) { + return this.each((n, t) => { + delete t[Kl[e] || e]; + }); +}; +const Au = /^--/; +function jo(e) { + return Au.test(e); +} +const no = {}, { style: Nu } = jl, Lu = ["webkit", "moz", "ms"]; +function Mu(e, n = jo(e)) { + if (n) + return e; + if (!no[e]) { + const t = Io(e), s = `${t[0].toUpperCase()}${t.slice(1)}`, i = `${t} ${Lu.join(`${s} `)}${s}`.split(" "); + Z(i, (o, r) => { + if (r in Nu) + return no[e] = r, !1; + }); + } + return no[e]; +} +const Ou = { + animationIterationCount: !0, + columnCount: !0, + flexGrow: !0, + flexShrink: !0, + fontWeight: !0, + gridArea: !0, + gridColumn: !0, + gridColumnEnd: !0, + gridColumnStart: !0, + gridRow: !0, + gridRowEnd: !0, + gridRowStart: !0, + lineHeight: !0, + opacity: !0, + order: !0, + orphans: !0, + widows: !0, + zIndex: !0 +}; +function Yl(e, n, t = jo(e)) { + return !t && !Ou[e] && Ul(n) ? `${n}px` : n; +} +function Pu(e, n) { + if (ot(e)) { + const t = jo(e); + return e = Mu(e, t), arguments.length < 2 ? this[0] && Vt(this[0], e, t) : e ? (n = Yl(e, n, t), this.each((s, i) => { + X(i) && (t ? i.style.setProperty(e, n) : i.style[e] = n); + })) : this; + } + for (const t in e) + this.css(t, e[t]); + return this; +} +C.css = Pu; +function Xl(e, n) { + try { + return e(n); + } catch { + return n; + } +} +const Du = /^\s+|\s+$/; +function Er(e, n) { + const t = e.dataset[n] || e.dataset[Io(n)]; + return Du.test(t) ? t : Xl(JSON.parse, t); +} +function Hu(e, n, t) { + t = Xl(JSON.stringify, t), e.dataset[Io(n)] = t; +} +function Iu(e, n) { + if (!e) { + if (!this[0]) + return; + const t = {}; + for (const s in this[0].dataset) + t[s] = Er(this[0], s); + return t; + } + if (ot(e)) + return arguments.length < 2 ? this[0] && Er(this[0], e) : ct(n) ? this : this.each((t, s) => { + Hu(s, e, n); + }); + for (const t in e) + this.data(t, e[t]); + return this; +} +C.data = Iu; +function Jl(e, n) { + const t = e.documentElement; + return Math.max(e.body[`scroll${n}`], t[`scroll${n}`], e.body[`offset${n}`], t[`offset${n}`], t[`client${n}`]); +} +Z([!0, !1], (e, n) => { + Z(["Width", "Height"], (t, s) => { + const i = `${n ? "outer" : "inner"}${s}`; + C[i] = function(o) { + if (this[0]) + return rn(this[0]) ? n ? this[0][`inner${s}`] : this[0].document.documentElement[`client${s}`] : ln(this[0]) ? Jl(this[0], s) : this[0][`${n ? "offset" : "client"}${s}`] + (o && n ? Ct(this[0], `margin${t ? "Top" : "Left"}`) + Ct(this[0], `margin${t ? "Bottom" : "Right"}`) : 0); + }; + }); +}); +Z(["Width", "Height"], (e, n) => { + const t = n.toLowerCase(); + C[t] = function(s) { + if (!this[0]) + return ct(s) ? void 0 : this; + if (!arguments.length) + return rn(this[0]) ? this[0].document.documentElement[`client${n}`] : ln(this[0]) ? Jl(this[0], n) : this[0].getBoundingClientRect()[t] - vr(this[0], !e); + const i = parseInt(s, 10); + return this.each((o, r) => { + if (!X(r)) + return; + const l = Vt(r, "boxSizing"); + r.style[t] = Yl(t, i + (l === "border-box" ? vr(r, !e) : 0)); + }); + }; +}); +const Cr = "___cd"; +C.toggle = function(e) { + return this.each((n, t) => { + if (!X(t)) + return; + (ct(e) ? xr(t) : e) ? (t.style.display = t[Cr] || "", xr(t) && (t.style.display = bu(t.tagName))) : (t[Cr] = Vt(t, "display"), t.style.display = "none"); + }); +}; +C.hide = function() { + return this.toggle(!1); +}; +C.show = function() { + return this.toggle(!0); +}; +const $r = "___ce", Wo = ".", Fo = { focus: "focusin", blur: "focusout" }, Ql = { mouseenter: "mouseover", mouseleave: "mouseout" }, ju = /^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i; +function Bo(e) { + return Ql[e] || Fo[e] || e; +} +function zo(e) { + const n = e.split(Wo); + return [n[0], n.slice(1).sort()]; +} +C.trigger = function(e, n) { + if (ot(e)) { + const [s, i] = zo(e), o = Bo(s); + if (!o) + return this; + const r = ju.test(o) ? "MouseEvents" : "HTMLEvents"; + e = Ut.createEvent(r), e.initEvent(o, !0, !0), e.namespace = i.join(Wo), e.___ot = s; + } + e.___td = n; + const t = e.___ot in Fo; + return this.each((s, i) => { + t && Ae(i[e.___ot]) && (i[`___i${e.type}`] = !0, i[e.___ot](), i[`___i${e.type}`] = !1), i.dispatchEvent(e); + }); +}; +function Zl(e) { + return e[$r] = e[$r] || {}; +} +function Wu(e, n, t, s, i) { + const o = Zl(e); + o[n] = o[n] || [], o[n].push([t, s, i]), e.addEventListener(n, i); +} +function tc(e, n) { + return !n || !Po.call(n, (t) => e.indexOf(t) < 0); +} +function Ps(e, n, t, s, i) { + const o = Zl(e); + if (n) + o[n] && (o[n] = o[n].filter(([r, l, a]) => { + if (i && a.guid !== i.guid || !tc(r, t) || s && s !== l) + return !0; + e.removeEventListener(n, a); + })); + else + for (n in o) + Ps(e, n, t, s, i); +} +C.off = function(e, n, t) { + if (ct(e)) + this.each((s, i) => { + !X(i) && !ln(i) && !rn(i) || Ps(i); + }); + else if (ot(e)) + Ae(n) && (t = n, n = ""), Z(Bi(e), (s, i) => { + const [o, r] = zo(i), l = Bo(o); + this.each((a, h) => { + !X(h) && !ln(h) && !rn(h) || Ps(h, l, r, n, t); + }); + }); + else + for (const s in e) + this.off(s, e[s]); + return this; +}; +C.remove = function(e) { + return he(this, e).detach().off(), this; +}; +C.replaceWith = function(e) { + return this.before(e).remove(); +}; +C.replaceAll = function(e) { + return A(e).replaceWith(this), this; +}; +function Fu(e, n, t, s, i) { + if (!ot(e)) { + for (const o in e) + this.on(o, n, t, e[o], i); + return this; + } + return ot(n) || (ct(n) || Nn(n) ? n = "" : ct(t) ? (t = n, n = "") : (s = t, t = n, n = "")), Ae(s) || (s = t, t = void 0), s ? (Z(Bi(e), (o, r) => { + const [l, a] = zo(r), h = Bo(l), c = l in Ql, u = l in Fo; + h && this.each((d, f) => { + if (!X(f) && !ln(f) && !rn(f)) + return; + const p = function(g) { + if (g.target[`___i${g.type}`]) + return g.stopImmediatePropagation(); + if (g.namespace && !tc(a, g.namespace.split(Wo)) || !n && (u && (g.target !== f || g.___ot === h) || c && g.relatedTarget && f.contains(g.relatedTarget))) + return; + let y = f; + if (n) { + let v = g.target; + for (; !Vl(v, n); ) + if (v === f || (v = v.parentNode, !v)) + return; + y = v; + } + Object.defineProperty(g, "currentTarget", { + configurable: !0, + get() { + return y; + } + }), Object.defineProperty(g, "delegateTarget", { + configurable: !0, + get() { + return f; + } + }), Object.defineProperty(g, "data", { + configurable: !0, + get() { + return t; + } + }); + const _ = s.call(y, g, g.___td); + i && Ps(f, h, a, n, p), _ === !1 && (g.preventDefault(), g.stopPropagation()); + }; + p.guid = s.guid = s.guid || A.guid++, Wu(f, h, a, n, p); + }); + }), this) : this; +} +C.on = Fu; +function Bu(e, n, t, s) { + return this.on(e, n, t, s, !0); +} +C.one = Bu; +const zu = /\r?\n/g; +function Uu(e, n) { + return `&${encodeURIComponent(e)}=${encodeURIComponent(n.replace(zu, `\r +`))}`; +} +const Vu = /file|reset|submit|button|image/i, ec = /radio|checkbox/i; +C.serialize = function() { + let e = ""; + return this.each((n, t) => { + Z(t.elements || [t], (s, i) => { + if (i.disabled || !i.name || i.tagName === "FIELDSET" || Vu.test(i.type) || ec.test(i.type) && !i.checked) + return; + const o = Gl(i); + if (!ct(o)) { + const r = Wi(o) ? o : [o]; + Z(r, (l, a) => { + e += Uu(i.name, a); + }); + } + }); + }), e.slice(1); +}; +window.$ = A; +const qu = A; +function Gu({ + key: e, + type: n, + btnType: t, + ...s +}) { + return /* @__PURE__ */ b(Tt, { type: t, ...s }); +} +function Ku(e) { + return e.button === 2; +} +function Uo(e) { + return e.split("-")[1]; +} +function nc(e) { + return e === "y" ? "height" : "width"; +} +function xn(e) { + return e.split("-")[0]; +} +function sc(e) { + return ["top", "bottom"].includes(xn(e)) ? "x" : "y"; +} +function Rr(e, n, t) { + let { reference: s, floating: i } = e; + const o = s.x + s.width / 2 - i.width / 2, r = s.y + s.height / 2 - i.height / 2, l = sc(n), a = nc(l), h = s[a] / 2 - i[a] / 2, c = l === "x"; + let u; + switch (xn(n)) { + case "top": + u = { x: o, y: s.y - i.height }; + break; + case "bottom": + u = { x: o, y: s.y + s.height }; + break; + case "right": + u = { x: s.x + s.width, y: r }; + break; + case "left": + u = { x: s.x - i.width, y: r }; + break; + default: + u = { x: s.x, y: s.y }; + } + switch (Uo(n)) { + case "start": + u[l] -= h * (t && c ? -1 : 1); + break; + case "end": + u[l] += h * (t && c ? -1 : 1); + } + return u; +} +const Yu = async (e, n, t) => { + const { placement: s = "bottom", strategy: i = "absolute", middleware: o = [], platform: r } = t, l = o.filter(Boolean), a = await (r.isRTL == null ? void 0 : r.isRTL(n)); + let h = await r.getElementRects({ reference: e, floating: n, strategy: i }), { x: c, y: u } = Rr(h, s, a), d = s, f = {}, p = 0; + for (let g = 0; g < l.length; g++) { + const { name: y, fn: _ } = l[g], { x: v, y: S, data: $, reset: T } = await _({ x: c, y: u, initialPlacement: s, placement: d, strategy: i, middlewareData: f, rects: h, platform: r, elements: { reference: e, floating: n } }); + c = v ?? c, u = S ?? u, f = { ...f, [y]: { ...f[y], ...$ } }, T && p <= 50 && (p++, typeof T == "object" && (T.placement && (d = T.placement), T.rects && (h = T.rects === !0 ? await r.getElementRects({ reference: e, floating: n, strategy: i }) : T.rects), { x: c, y: u } = Rr(h, d, a)), g = -1); + } + return { x: c, y: u, placement: d, strategy: i, middlewareData: f }; +}; +function Xu(e) { + return typeof e != "number" ? function(n) { + return { top: 0, right: 0, bottom: 0, left: 0, ...n }; + }(e) : { top: e, right: e, bottom: e, left: e }; +} +function Ds(e) { + return { ...e, top: e.y, left: e.x, right: e.x + e.width, bottom: e.y + e.height }; +} +async function Ju(e, n) { + var t; + n === void 0 && (n = {}); + const { x: s, y: i, platform: o, rects: r, elements: l, strategy: a } = e, { boundary: h = "clippingAncestors", rootBoundary: c = "viewport", elementContext: u = "floating", altBoundary: d = !1, padding: f = 0 } = n, p = Xu(f), g = l[d ? u === "floating" ? "reference" : "floating" : u], y = Ds(await o.getClippingRect({ element: (t = await (o.isElement == null ? void 0 : o.isElement(g))) == null || t ? g : g.contextElement || await (o.getDocumentElement == null ? void 0 : o.getDocumentElement(l.floating)), boundary: h, rootBoundary: c, strategy: a })), _ = u === "floating" ? { ...r.floating, x: s, y: i } : r.reference, v = await (o.getOffsetParent == null ? void 0 : o.getOffsetParent(l.floating)), S = await (o.isElement == null ? void 0 : o.isElement(v)) && await (o.getScale == null ? void 0 : o.getScale(v)) || { x: 1, y: 1 }, $ = Ds(o.convertOffsetParentRelativeRectToViewportRelativeRect ? await o.convertOffsetParentRelativeRectToViewportRelativeRect({ rect: _, offsetParent: v, strategy: a }) : _); + return { top: (y.top - $.top + p.top) / S.y, bottom: ($.bottom - y.bottom + p.bottom) / S.y, left: (y.left - $.left + p.left) / S.x, right: ($.right - y.right + p.right) / S.x }; +} +const Qu = ["top", "right", "bottom", "left"]; +Qu.reduce((e, n) => e.concat(n, n + "-start", n + "-end"), []); +const Zu = { left: "right", right: "left", bottom: "top", top: "bottom" }; +function Hs(e) { + return e.replace(/left|right|bottom|top/g, (n) => Zu[n]); +} +function th(e, n, t) { + t === void 0 && (t = !1); + const s = Uo(e), i = sc(e), o = nc(i); + let r = i === "x" ? s === (t ? "end" : "start") ? "right" : "left" : s === "start" ? "bottom" : "top"; + return n.reference[o] > n.floating[o] && (r = Hs(r)), { main: r, cross: Hs(r) }; +} +const eh = { start: "end", end: "start" }; +function so(e) { + return e.replace(/start|end/g, (n) => eh[n]); +} +const ic = function(e) { + return e === void 0 && (e = {}), { name: "flip", options: e, async fn(n) { + var t; + const { placement: s, middlewareData: i, rects: o, initialPlacement: r, platform: l, elements: a } = n, { mainAxis: h = !0, crossAxis: c = !0, fallbackPlacements: u, fallbackStrategy: d = "bestFit", fallbackAxisSideDirection: f = "none", flipAlignment: p = !0, ...g } = e, y = xn(s), _ = xn(r) === r, v = await (l.isRTL == null ? void 0 : l.isRTL(a.floating)), S = u || (_ || !p ? [Hs(r)] : function(j) { + const P = Hs(j); + return [so(j), P, so(P)]; + }(r)); + u || f === "none" || S.push(...function(j, P, V, F) { + const G = Uo(j); + let I = function(K, bt, de) { + const pe = ["left", "right"], me = ["right", "left"], Lt = ["top", "bottom"], Ne = ["bottom", "top"]; + switch (K) { + case "top": + case "bottom": + return de ? bt ? me : pe : bt ? pe : me; + case "left": + case "right": + return bt ? Lt : Ne; + default: + return []; + } + }(xn(j), V === "start", F); + return G && (I = I.map((K) => K + "-" + G), P && (I = I.concat(I.map(so)))), I; + }(r, p, f, v)); + const $ = [r, ...S], T = await Ju(n, g), D = []; + let L = ((t = i.flip) == null ? void 0 : t.overflows) || []; + if (h && D.push(T[y]), c) { + const { main: j, cross: P } = th(s, o, v); + D.push(T[j], T[P]); + } + if (L = [...L, { placement: s, overflows: D }], !D.every((j) => j <= 0)) { + var O; + const j = (((O = i.flip) == null ? void 0 : O.index) || 0) + 1, P = $[j]; + if (P) + return { data: { index: j, overflows: L }, reset: { placement: P } }; + let V = "bottom"; + switch (d) { + case "bestFit": { + var k; + const F = (k = L.map((G) => [G, G.overflows.filter((I) => I > 0).reduce((I, K) => I + K, 0)]).sort((G, I) => G[1] - I[1])[0]) == null ? void 0 : k[0].placement; + F && (V = F); + break; + } + case "initialPlacement": + V = r; + } + if (s !== V) + return { reset: { placement: V } }; + } + return {}; + } }; +}; +function dt(e) { + var n; + return ((n = e.ownerDocument) == null ? void 0 : n.defaultView) || window; +} +function $t(e) { + return dt(e).getComputedStyle(e); +} +function ce(e) { + return rc(e) ? (e.nodeName || "").toLowerCase() : ""; +} +let ps; +function oc() { + if (ps) + return ps; + const e = navigator.userAgentData; + return e && Array.isArray(e.brands) ? (ps = e.brands.map((n) => n.brand + "/" + n.version).join(" "), ps) : navigator.userAgent; +} +function qt(e) { + return e instanceof dt(e).HTMLElement; +} +function yt(e) { + return e instanceof dt(e).Element; +} +function rc(e) { + return e instanceof dt(e).Node; +} +function kr(e) { + return typeof ShadowRoot > "u" ? !1 : e instanceof dt(e).ShadowRoot || e instanceof ShadowRoot; +} +function Ui(e) { + const { overflow: n, overflowX: t, overflowY: s, display: i } = $t(e); + return /auto|scroll|overlay|hidden|clip/.test(n + s + t) && !["inline", "contents"].includes(i); +} +function nh(e) { + return ["table", "td", "th"].includes(ce(e)); +} +function bo(e) { + const n = /firefox/i.test(oc()), t = $t(e), s = t.backdropFilter || t.WebkitBackdropFilter; + return t.transform !== "none" || t.perspective !== "none" || !!s && s !== "none" || n && t.willChange === "filter" || n && !!t.filter && t.filter !== "none" || ["transform", "perspective"].some((i) => t.willChange.includes(i)) || ["paint", "layout", "strict", "content"].some((i) => { + const o = t.contain; + return o != null && o.includes(i); + }); +} +function lc() { + return !/^((?!chrome|android).)*safari/i.test(oc()); +} +function Vo(e) { + return ["html", "body", "#document"].includes(ce(e)); +} +const Tr = Math.min, Sn = Math.max, Is = Math.round; +function cc(e) { + const n = $t(e); + let t = parseFloat(n.width), s = parseFloat(n.height); + const i = e.offsetWidth, o = e.offsetHeight, r = Is(t) !== i || Is(s) !== o; + return r && (t = i, s = o), { width: t, height: s, fallback: r }; +} +function ac(e) { + return yt(e) ? e : e.contextElement; +} +const uc = { x: 1, y: 1 }; +function Me(e) { + const n = ac(e); + if (!qt(n)) + return uc; + const t = n.getBoundingClientRect(), { width: s, height: i, fallback: o } = cc(n); + let r = (o ? Is(t.width) : t.width) / s, l = (o ? Is(t.height) : t.height) / i; + return r && Number.isFinite(r) || (r = 1), l && Number.isFinite(l) || (l = 1), { x: r, y: l }; +} +function $e(e, n, t, s) { + var i, o; + n === void 0 && (n = !1), t === void 0 && (t = !1); + const r = e.getBoundingClientRect(), l = ac(e); + let a = uc; + n && (s ? yt(s) && (a = Me(s)) : a = Me(e)); + const h = l ? dt(l) : window, c = !lc() && t; + let u = (r.left + (c && ((i = h.visualViewport) == null ? void 0 : i.offsetLeft) || 0)) / a.x, d = (r.top + (c && ((o = h.visualViewport) == null ? void 0 : o.offsetTop) || 0)) / a.y, f = r.width / a.x, p = r.height / a.y; + if (l) { + const g = dt(l), y = s && yt(s) ? dt(s) : s; + let _ = g.frameElement; + for (; _ && s && y !== g; ) { + const v = Me(_), S = _.getBoundingClientRect(), $ = getComputedStyle(_); + S.x += (_.clientLeft + parseFloat($.paddingLeft)) * v.x, S.y += (_.clientTop + parseFloat($.paddingTop)) * v.y, u *= v.x, d *= v.y, f *= v.x, p *= v.y, u += S.x, d += S.y, _ = dt(_).frameElement; + } + } + return { width: f, height: p, top: d, right: u + f, bottom: d + p, left: u, x: u, y: d }; +} +function re(e) { + return ((rc(e) ? e.ownerDocument : e.document) || window.document).documentElement; +} +function Vi(e) { + return yt(e) ? { scrollLeft: e.scrollLeft, scrollTop: e.scrollTop } : { scrollLeft: e.pageXOffset, scrollTop: e.pageYOffset }; +} +function hc(e) { + return $e(re(e)).left + Vi(e).scrollLeft; +} +function sh(e, n, t) { + const s = qt(n), i = re(n), o = $e(e, !0, t === "fixed", n); + let r = { scrollLeft: 0, scrollTop: 0 }; + const l = { x: 0, y: 0 }; + if (s || !s && t !== "fixed") + if ((ce(n) !== "body" || Ui(i)) && (r = Vi(n)), qt(n)) { + const a = $e(n, !0); + l.x = a.x + n.clientLeft, l.y = a.y + n.clientTop; + } else + i && (l.x = hc(i)); + return { x: o.left + r.scrollLeft - l.x, y: o.top + r.scrollTop - l.y, width: o.width, height: o.height }; +} +function Ln(e) { + if (ce(e) === "html") + return e; + const n = e.assignedSlot || e.parentNode || (kr(e) ? e.host : null) || re(e); + return kr(n) ? n.host : n; +} +function Ar(e) { + return qt(e) && $t(e).position !== "fixed" ? e.offsetParent : null; +} +function Nr(e) { + const n = dt(e); + let t = Ar(e); + for (; t && nh(t) && $t(t).position === "static"; ) + t = Ar(t); + return t && (ce(t) === "html" || ce(t) === "body" && $t(t).position === "static" && !bo(t)) ? n : t || function(s) { + let i = Ln(s); + for (; qt(i) && !Vo(i); ) { + if (bo(i)) + return i; + i = Ln(i); + } + return null; + }(e) || n; +} +function fc(e) { + const n = Ln(e); + return Vo(n) ? e.ownerDocument.body : qt(n) && Ui(n) ? n : fc(n); +} +function En(e, n) { + var t; + n === void 0 && (n = []); + const s = fc(e), i = s === ((t = e.ownerDocument) == null ? void 0 : t.body), o = dt(s); + return i ? n.concat(o, o.visualViewport || [], Ui(s) ? s : []) : n.concat(s, En(s)); +} +function Lr(e, n, t) { + return n === "viewport" ? Ds(function(s, i) { + const o = dt(s), r = re(s), l = o.visualViewport; + let a = r.clientWidth, h = r.clientHeight, c = 0, u = 0; + if (l) { + a = l.width, h = l.height; + const d = lc(); + (d || !d && i === "fixed") && (c = l.offsetLeft, u = l.offsetTop); + } + return { width: a, height: h, x: c, y: u }; + }(e, t)) : yt(n) ? function(s, i) { + const o = $e(s, !0, i === "fixed"), r = o.top + s.clientTop, l = o.left + s.clientLeft, a = qt(s) ? Me(s) : { x: 1, y: 1 }, h = s.clientWidth * a.x, c = s.clientHeight * a.y, u = l * a.x, d = r * a.y; + return { top: d, left: u, right: u + h, bottom: d + c, x: u, y: d, width: h, height: c }; + }(n, t) : Ds(function(s) { + var i; + const o = re(s), r = Vi(s), l = (i = s.ownerDocument) == null ? void 0 : i.body, a = Sn(o.scrollWidth, o.clientWidth, l ? l.scrollWidth : 0, l ? l.clientWidth : 0), h = Sn(o.scrollHeight, o.clientHeight, l ? l.scrollHeight : 0, l ? l.clientHeight : 0); + let c = -r.scrollLeft + hc(s); + const u = -r.scrollTop; + return $t(l || o).direction === "rtl" && (c += Sn(o.clientWidth, l ? l.clientWidth : 0) - a), { width: a, height: h, x: c, y: u }; + }(re(e))); +} +const ih = { getClippingRect: function(e) { + let { element: n, boundary: t, rootBoundary: s, strategy: i } = e; + const o = t === "clippingAncestors" ? function(h, c) { + const u = c.get(h); + if (u) + return u; + let d = En(h).filter((y) => yt(y) && ce(y) !== "body"), f = null; + const p = $t(h).position === "fixed"; + let g = p ? Ln(h) : h; + for (; yt(g) && !Vo(g); ) { + const y = $t(g), _ = bo(g); + (p ? _ || f : _ || y.position !== "static" || !f || !["absolute", "fixed"].includes(f.position)) ? f = y : d = d.filter((v) => v !== g), g = Ln(g); + } + return c.set(h, d), d; + }(n, this._c) : [].concat(t), r = [...o, s], l = r[0], a = r.reduce((h, c) => { + const u = Lr(n, c, i); + return h.top = Sn(u.top, h.top), h.right = Tr(u.right, h.right), h.bottom = Tr(u.bottom, h.bottom), h.left = Sn(u.left, h.left), h; + }, Lr(n, l, i)); + return { width: a.right - a.left, height: a.bottom - a.top, x: a.left, y: a.top }; +}, convertOffsetParentRelativeRectToViewportRelativeRect: function(e) { + let { rect: n, offsetParent: t, strategy: s } = e; + const i = qt(t), o = re(t); + if (t === o) + return n; + let r = { scrollLeft: 0, scrollTop: 0 }, l = { x: 1, y: 1 }; + const a = { x: 0, y: 0 }; + if ((i || !i && s !== "fixed") && ((ce(t) !== "body" || Ui(o)) && (r = Vi(t)), qt(t))) { + const h = $e(t); + l = Me(t), a.x = h.x + t.clientLeft, a.y = h.y + t.clientTop; + } + return { width: n.width * l.x, height: n.height * l.y, x: n.x * l.x - r.scrollLeft * l.x + a.x, y: n.y * l.y - r.scrollTop * l.y + a.y }; +}, isElement: yt, getDimensions: function(e) { + return cc(e); +}, getOffsetParent: Nr, getDocumentElement: re, getScale: Me, async getElementRects(e) { + let { reference: n, floating: t, strategy: s } = e; + const i = this.getOffsetParent || Nr, o = this.getDimensions; + return { reference: sh(n, await i(t), s), floating: { x: 0, y: 0, ...await o(t) } }; +}, getClientRects: (e) => Array.from(e.getClientRects()), isRTL: (e) => $t(e).direction === "rtl" }; +function oh(e, n, t, s) { + s === void 0 && (s = {}); + const { ancestorScroll: i = !0, ancestorResize: o = !0, elementResize: r = !0, animationFrame: l = !1 } = s, a = i && !l, h = a || o ? [...yt(e) ? En(e) : e.contextElement ? En(e.contextElement) : [], ...En(n)] : []; + h.forEach((f) => { + a && f.addEventListener("scroll", t, { passive: !0 }), o && f.addEventListener("resize", t); + }); + let c, u = null; + if (r) { + let f = !0; + u = new ResizeObserver(() => { + f || t(), f = !1; + }), yt(e) && !l && u.observe(e), yt(e) || !e.contextElement || l || u.observe(e.contextElement), u.observe(n); + } + let d = l ? $e(e) : null; + return l && function f() { + const p = $e(e); + !d || p.x === d.x && p.y === d.y && p.width === d.width && p.height === d.height || t(), d = p, c = requestAnimationFrame(f); + }(), t(), () => { + var f; + h.forEach((p) => { + a && p.removeEventListener("scroll", t), o && p.removeEventListener("resize", t); + }), (f = u) == null || f.disconnect(), u = null, l && cancelAnimationFrame(c); + }; +} +const dc = (e, n, t) => { + const s = /* @__PURE__ */ new Map(), i = { platform: ih, ...t }, o = { ...i.platform, _c: s }; + return Yu(e, n, { ...i, platform: o }); +}; +let rh = class extends oe { + get nestedTrigger() { + return this.props.nestedTrigger || "hover"; + } + get name() { + return "menu"; + } + get menuName() { + return "menu-context"; + } + componentWillUnmount() { + super.componentWillUnmount(); + } + _getPopperOptions() { + return { + middleware: [ic()], + placement: "right-start" + }; + } + _getPopperElement() { + var n; + return (n = this.ref.current) == null ? void 0 : n.parentElement; + } + _createPopper() { + const n = this._getPopperOptions(); + this.ref.current && dc(this._getPopperElement(), this.ref.current, n).then(({ x: t, y: s }) => { + Object.assign(this.ref.current.style, { + left: `${t}px`, + top: `${s}px`, + position: "absolute" + }); + }); + } + afterRender(n) { + super.afterRender(n), this.props.controlledMenu && this._createPopper(); + } + beforeRender() { + const n = super.beforeRender(); + return n.className = M(n.className, "menu-popup"), n; + } + renderToggleIcon() { + return /* @__PURE__ */ b("span", { class: "contextmenu-toggle-icon caret-right" }); + } +}; +var Qt, Ie, Hn, In, qs, pc, Gs, mc; +class lt extends kt { + constructor() { + super(...arguments); + x(this, qs); + x(this, Gs); + x(this, Qt, void 0); + x(this, Ie, void 0); + x(this, Hn, void 0); + w(this, "arrowEl"); + x(this, In, void 0); + } + get isShown() { + var t; + return (t = m(this, Qt)) == null ? void 0 : t.classList.contains(this.constructor.CLASS_SHOW); + } + get menu() { + return m(this, Qt) || this._ensureMenu(); + } + get trigger() { + return m(this, Hn) || this.element; + } + get isDynamic() { + return this.options.items || this.options.menu; + } + init() { + const { element: t } = this; + t !== document.body && !t.hasAttribute("data-toggle") && t.setAttribute("data-toggle", "contextmenu"); + } + show(t) { + return R(this, Hn, t), this.emit("show", { menu: this, trigger: this.trigger }).defaultPrevented || this.isDynamic && !this._renderMenu() ? !1 : (this.menu.classList.add(this.constructor.CLASS_SHOW), this._createPopper(), this.emit("shown", this), !0); + } + hide() { + var s, i; + return (s = m(this, In)) == null || s.call(this), this.emit("hide", this).defaultPrevented ? !1 : ((i = m(this, Qt)) == null || i.classList.remove(this.constructor.CLASS_SHOW), this.emit("hidden", this), !0); + } + toggle(t) { + return this.isShown ? this.hide() : this.show(t); + } + destroy() { + var t; + super.destroy(), (t = m(this, Qt)) == null || t.remove(); + } + _ensureMenu() { + var o; + const { element: t } = this, s = this.constructor.MENU_CLASS; + let i; + if (this.isDynamic) + i = document.createElement("div"), i.classList.add(s), document.body.appendChild(i); + else if (t) { + const r = t.getAttribute("href") ?? t.dataset.target; + if ((r == null ? void 0 : r[0]) === "#" && (i = document.querySelector(r)), !i) { + const l = t.nextElementSibling; + l != null && l.classList.contains(s) ? i = l : i = (o = t.parentNode) == null ? void 0 : o.querySelector(`.${s}`); + } + i && i.classList.add("menu-popup"); + } + if (!i) + throw new Error("ContextMenu: Cannot find menu element"); + return i.style.width = "max-content", i.style.position = this.options.strategy, i.style.top = "0", i.style.left = "0", R(this, Qt, i), i; + } + _getPopperOptions() { + var o; + const { placement: t, strategy: s } = this.options, i = { + middleware: [], + placement: t, + strategy: s + }; + return this.options.flip && ((o = i.middleware) == null || o.push(ic())), i; + } + _createPopper() { + const t = this._getPopperOptions(), s = this._getPopperElement(); + R(this, In, oh(s, this.menu, () => { + dc(s, this.menu, t).then(({ x: i, y: o, middlewareData: r, placement: l }) => { + Object.assign(this.menu.style, { + left: `${i}px`, + top: `${o}px` + }); + const a = l.split("-")[0], h = N(this, qs, pc).call(this, a); + if (r.arrow && this.arrowEl) { + const { x: c, y: u } = r.arrow; + Object.assign(this.arrowEl.style, { + left: c != null ? `${c}px` : "", + top: u != null ? `${u}px` : "", + [h]: `${-this.arrowEl.offsetWidth / 2}px`, + background: "inherit", + border: "inherit", + ...N(this, Gs, mc).call(this, a) + }); + } + }); + })); + } + _getMenuOptions() { + const { menu: t, items: s } = this.options; + let i = s || (t == null ? void 0 : t.items); + if (i) + return typeof i == "function" && (i = i(this)), { + nestedTrigger: "hover", + ...t, + items: i + }; + } + _renderMenu() { + const t = this._getMenuOptions(); + return !t || this.emit("updateMenu", { menu: t, trigger: this.trigger, contextmenu: this }).defaultPrevented ? !1 : (cs(E(rh, t), this.menu), !0); + } + _getPopperElement() { + return m(this, Ie) || R(this, Ie, { + getBoundingClientRect: () => { + const { trigger: t } = this; + if (t instanceof MouseEvent) { + const { clientX: s, clientY: i } = t; + return { + width: 0, + height: 0, + top: i, + right: s, + bottom: i, + left: s + }; + } + return t instanceof HTMLElement ? t.getBoundingClientRect() : t; + }, + contextElement: this.element + }), m(this, Ie); + } + static clear(t) { + var a, h; + t instanceof Event && (t = { event: t }); + const { event: s, exclude: i, ignoreSelector: o = ".not-hide-menu" } = t || {}; + if (s && o && ((h = (a = s.target).closest) != null && h.call(a, o)) || s && Ku(s)) + return; + const r = this.getAll().entries(), l = new Set(i || []); + for (const [c, u] of r) + l.has(c) || u.hide(); + } + static show(t) { + const { event: s, ...i } = t, o = this.ensure(document.body); + return Object.keys(i).length && o.setOptions(i), o.show(s), s instanceof Event && s.stopPropagation(), o; + } + static hide() { + const t = this.get(document.body); + return t == null || t.hide(), t; + } +} +Qt = new WeakMap(), Ie = new WeakMap(), Hn = new WeakMap(), In = new WeakMap(), qs = new WeakSet(), pc = function(t) { + return { + top: "bottom", + right: "left", + bottom: "top", + left: "right" + }[t]; +}, Gs = new WeakSet(), mc = function(t) { + return t === "bottom" ? { + borderBottomStyle: "none", + borderRightStyle: "none" + } : t === "top" ? { + borderTopStyle: "none", + borderLeftStyle: "none" + } : t === "left" ? { + borderBottomStyle: "none", + borderLeftStyle: "none" + } : { + borderTopStyle: "none", + borderRightStyle: "none" + }; +}, w(lt, "NAME", "contextmenu"), w(lt, "EVENTS", !0), w(lt, "DEFAULT", { + placement: "bottom-start", + strategy: "fixed", + flip: !0, + preventOverflow: !0 +}), w(lt, "MENU_CLASS", "contextmenu"), w(lt, "CLASS_SHOW", "show"), w(lt, "MENU_SELECTOR", '[data-toggle="contextmenu"]:not(.disabled):not(:disabled)'); +document.addEventListener("contextmenu", (e) => { + var s; + const n = e.target; + if ((s = n.closest) != null && s.call(n, `.${lt.MENU_CLASS}`)) + return; + const t = n.closest(lt.MENU_SELECTOR); + t && (lt.ensure(t).show(e), e.preventDefault()); +}); +document.addEventListener("click", lt.clear.bind(lt)); +function gc(e) { + return e.split("-")[1]; +} +function lh(e) { + return e === "y" ? "height" : "width"; +} +function yc(e) { + return e.split("-")[0]; +} +function _c(e) { + return ["top", "bottom"].includes(yc(e)) ? "x" : "y"; +} +function ch(e) { + return typeof e != "number" ? function(n) { + return { top: 0, right: 0, bottom: 0, left: 0, ...n }; + }(e) : { top: e, right: e, bottom: e, left: e }; +} +const ah = Math.min, uh = Math.max; +function hh(e, n, t) { + return uh(e, ah(n, t)); +} +const fh = (e) => ({ name: "arrow", options: e, async fn(n) { + const { element: t, padding: s = 0 } = e || {}, { x: i, y: o, placement: r, rects: l, platform: a } = n; + if (t == null) + return {}; + const h = ch(s), c = { x: i, y: o }, u = _c(r), d = lh(u), f = await a.getDimensions(t), p = u === "y" ? "top" : "left", g = u === "y" ? "bottom" : "right", y = l.reference[d] + l.reference[u] - c[u] - l.floating[d], _ = c[u] - l.reference[u], v = await (a.getOffsetParent == null ? void 0 : a.getOffsetParent(t)); + let S = v ? u === "y" ? v.clientHeight || 0 : v.clientWidth || 0 : 0; + S === 0 && (S = l.floating[d]); + const $ = y / 2 - _ / 2, T = h[p], D = S - f[d] - h[g], L = S / 2 - f[d] / 2 + $, O = hh(T, L, D), k = gc(r) != null && L != O && l.reference[d] / 2 - (L < T ? h[p] : h[g]) - f[d] / 2 < 0; + return { [u]: c[u] - (k ? L < T ? T - L : D - L : 0), data: { [u]: O, centerOffset: L - O } }; +} }), dh = ["top", "right", "bottom", "left"]; +dh.reduce((e, n) => e.concat(n, n + "-start", n + "-end"), []); +const ph = function(e) { + return e === void 0 && (e = 0), { name: "offset", options: e, async fn(n) { + const { x: t, y: s } = n, i = await async function(o, r) { + const { placement: l, platform: a, elements: h } = o, c = await (a.isRTL == null ? void 0 : a.isRTL(h.floating)), u = yc(l), d = gc(l), f = _c(l) === "x", p = ["left", "top"].includes(u) ? -1 : 1, g = c && f ? -1 : 1, y = typeof r == "function" ? r(o) : r; + let { mainAxis: _, crossAxis: v, alignmentAxis: S } = typeof y == "number" ? { mainAxis: y, crossAxis: 0, alignmentAxis: null } : { mainAxis: 0, crossAxis: 0, alignmentAxis: null, ...y }; + return d && typeof S == "number" && (v = d === "end" ? -1 * S : S), f ? { x: v * g, y: _ * p } : { x: _ * p, y: v * g }; + }(n, e); + return { x: t + i.x, y: s + i.y, data: i }; + } }; +}; +var je, We, Fe, Ks, bc; +const Yo = class extends lt { + constructor() { + super(...arguments); + x(this, Ks); + x(this, je, !1); + x(this, We, 0); + w(this, "hideLater", () => { + m(this, Fe).call(this), R(this, We, window.setTimeout(this.hide.bind(this), 100)); + }); + x(this, Fe, () => { + clearTimeout(m(this, We)), R(this, We, 0); + }); + } + get isHover() { + return this.options.trigger === "hover"; + } + get elementShowClass() { + return `with-${this.constructor.NAME}-show`; + } + show(t, s) { + (s == null ? void 0 : s.clearOthers) !== !1 && Yo.clear({ event: s == null ? void 0 : s.event, exclude: [this.element] }); + const i = super.show(t); + return i && (!m(this, je) && this.isHover && N(this, Ks, bc).call(this), this.element.classList.add(this.elementShowClass)), i; + } + hide() { + const t = super.hide(); + return t && this.element.classList.remove(this.elementShowClass), t; + } + toggle(t, s) { + return this.isShown ? this.hide() : this.show(t, { event: t, ...s }); + } + destroy() { + m(this, je) && (this.element.removeEventListener("mouseleave", this.hideLater), this.menu.removeEventListener("mouseenter", m(this, Fe)), this.menu.removeEventListener("mouseleave", this.hideLater)), super.destroy(); + } + _getArrowSize() { + const { arrow: t } = this.options; + return t ? typeof t == "number" ? t : 8 : 0; + } + _getPopperOptions() { + var i, o; + const t = super._getPopperOptions(), s = this._getArrowSize(); + return s && this.arrowEl && ((i = t.middleware) == null || i.push(ph(s)), (o = t.middleware) == null || o.push(fh({ element: this.arrowEl }))), t; + } + _ensureMenu() { + const t = super._ensureMenu(); + if (this.options.arrow) { + const s = this._getArrowSize(); + this.arrowEl = document.createElement("div"), this.arrowEl.style.position = "absolute", this.arrowEl.style.width = `${s}px`, this.arrowEl.style.height = `${s}px`, this.arrowEl.style.transform = "rotate(45deg)", t.append(this.arrowEl); + } + return t; + } + _getMenuOptions() { + const t = super._getMenuOptions(); + if (t && this.options.arrow) { + const { afterRender: s } = t; + t.afterRender = (...i) => { + var o; + this.arrowEl && ((o = this.menu.querySelector(".menu")) == null || o.appendChild(this.arrowEl)), s == null || s(...i); + }; + } + return t; + } +}; +let st = Yo; +je = new WeakMap(), We = new WeakMap(), Fe = new WeakMap(), Ks = new WeakSet(), bc = function() { + const { menu: t } = this; + t.addEventListener("mouseenter", m(this, Fe)), t.addEventListener("mouseleave", this.hideLater), this.element.addEventListener("mouseleave", this.hideLater), R(this, je, !0); +}, w(st, "NAME", "dropdown"), w(st, "MENU_CLASS", "dropdown-menu"), w(st, "MENU_SELECTOR", '[data-toggle="dropdown"]:not(.disabled):not(:disabled)'), w(st, "DEFAULT", { + ...lt.DEFAULT, + strategy: "fixed", + trigger: "click" +}); +document.addEventListener("click", function(e) { + var s; + const n = e.target, t = (s = n.closest) == null ? void 0 : s.call(n, st.MENU_SELECTOR); + if (t) { + const i = st.ensure(t); + i.options.trigger === "click" && i.toggle(); + } else + st.clear({ event: e }); +}); +document.addEventListener("mouseover", function(e) { + var i; + const n = e.target, t = (i = n.closest) == null ? void 0 : i.call(n, st.MENU_SELECTOR); + if (!t) + return; + const s = st.ensure(t); + s.isHover && s.show(); +}); +const mh = (e) => { + const n = document.getElementsByClassName("with-dropdown-show")[0]; + if (!n) + return; + const t = typeof n.closest == "function" ? n.closest(st.MENU_SELECTOR) : null; + !t || !e.target.contains(t) || st.clear({ event: e }); +}; +window.addEventListener("scroll", mh, !0); +var jn, Be; +class gh extends U { + constructor(t) { + var s; + super(t); + x(this, jn, void 0); + x(this, Be, cn()); + this.state = { placement: ((s = t.dropdown) == null ? void 0 : s.placement) || "", show: !1 }; + } + get ref() { + return m(this, Be); + } + get triggerElement() { + return m(this, Be).current; + } + componentDidMount() { + const { modifiers: t = [], ...s } = this.props.dropdown || {}; + t.push({ + name: "dropdown-trigger", + enabled: !0, + phase: "beforeMain", + fn: ({ state: i }) => { + var r; + const o = ((r = i.placement) == null ? void 0 : r.split("-").shift()) || ""; + this.setState({ placement: o }); + } + }), R(this, jn, st.ensure(this.triggerElement, { + ...s, + modifiers: t, + onShow: () => { + this.setState({ show: !0 }); + }, + onHide: () => { + this.setState({ show: !0 }); + } + })); + } + componentWillUnmount() { + var t; + (t = m(this, jn)) == null || t.destroy(); + } + beforeRender() { + const { className: t, children: s, dropdown: i, ...o } = this.props; + return { + className: M("dropdown", t), + children: typeof s == "function" ? s(this.state) : s, + ...o, + "data-toggle": "dropdown", + "data-dropdown-placement": this.state.placement, + ref: m(this, Be) + }; + } + render() { + const { children: t, ...s } = this.beforeRender(); + return /* @__PURE__ */ b("div", { ...s, children: t }); + } +} +jn = new WeakMap(), Be = new WeakMap(); +class yh extends gh { + get triggerElement() { + return this.ref.current.base; + } + render() { + var o; + const { placement: n, show: t } = this.state, s = this.beforeRender(); + let { caret: i = !0 } = s; + if (i !== !1 && (t || i === !0)) { + const r = t ? n : (o = this.props.dropdown) == null ? void 0 : o.placement; + i = (r === "top" ? "up" : r === "bottom" ? "down" : r) || (typeof i == "string" ? i : "") || "down"; + } + return s.caret = i, /* @__PURE__ */ b(Tt, { ...s }); + } +} +function wc({ + key: e, + type: n, + btnType: t, + ...s +}) { + return /* @__PURE__ */ b(yh, { type: t, ...s }); +} +let vc = class extends U { + componentDidMount() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !0 }); + } + componentDidUpdate() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !1 }); + } + componentWillUnmount() { + var n; + (n = this.props.beforeDestroy) == null || n.call(this); + } + handleItemClick(n, t, s, i) { + s && s.call(i.target, i); + const { onClickItem: o } = this.props; + o && o.call(this, { item: n, index: t, event: i }); + } + beforeRender() { + var s; + const n = { ...this.props }, t = (s = n.beforeRender) == null ? void 0 : s.call(this, n); + return t && Object.assign(n, t), typeof n.items == "function" && (n.items = n.items.call(this)), n; + } + onRenderItem(n, t) { + const { key: s = t, ...i } = n; + return /* @__PURE__ */ b(Tt, { ...i }, s); + } + renderItem(n, t, s) { + const { itemRender: i, defaultBtnProps: o, onClickItem: r } = n, l = { key: s, ...t }; + if (o && Object.assign(l, o), r && (l.onClick = this.handleItemClick.bind(this, l, s, t.onClick)), i) { + const a = i.call(this, l, E); + if (it(a)) + return a; + typeof a == "object" && Object.assign(l, a); + } + return this.onRenderItem(l, s); + } + render() { + const n = this.beforeRender(), { + className: t, + items: s, + size: i, + type: o, + defaultBtnProps: r, + children: l, + itemRender: a, + onClickItem: h, + beforeRender: c, + afterRender: u, + beforeDestroy: d, + ...f + } = n; + return /* @__PURE__ */ b( + "div", + { + className: M("btn-group", i ? `size-${i}` : "", t), + ...f, + children: [ + s && s.map(this.renderItem.bind(this, n)), + l + ] + } + ); + } +}; +function _h({ + key: e, + type: n, + btnType: t, + ...s +}) { + return /* @__PURE__ */ b(vc, { type: t, ...s }); +} +var Le; +let ae = (Le = class extends ji { + beforeRender() { + const { gap: n, btnProps: t, wrap: s, ...i } = super.beforeRender(); + return i.className = M(i.className, s ? "flex-wrap" : "", typeof n == "number" ? `gap-${n}` : ""), typeof n == "string" && (i.style ? i.style.gap = n : i.style = { gap: n }), i; + } + isBtnItem(n) { + return n === "item" || n === "dropdown"; + } + renderTypedItem(n, t, s) { + const i = this.isBtnItem(s.type) ? { btnType: "ghost", ...this.props.btnProps } : {}, o = { + ...t, + ...i, + ...s, + className: M(`${this.name}-${s.type}`, t.className, i.className, s.className), + style: Object.assign({}, t.style, i.style, s.style) + }; + return /* @__PURE__ */ b(n, { ...o }); + } +}, w(Le, "ItemComponents", { + item: Gu, + dropdown: wc, + "btn-group": _h +}), w(Le, "ROOT_TAG", "nav"), w(Le, "NAME", "toolbar"), w(Le, "defaultProps", { + btnProps: { + btnType: "ghost" + } +}), Le); +function bh({ + className: e, + style: n, + actions: t, + heading: s, + content: i, + contentClass: o, + children: r, + close: l, + onClose: a, + icon: h, + ...c +}) { + let u; + l === !0 ? u = /* @__PURE__ */ b(Tt, { className: "alert-close btn ghost", square: !0, onClick: a, children: /* @__PURE__ */ b("span", { class: "close" }) }) : it(l) ? u = l : typeof l == "object" && (u = /* @__PURE__ */ b(Tt, { ...l, onClick: a })); + const d = it(t) ? t : t ? /* @__PURE__ */ b(ae, { ...t }) : null; + return /* @__PURE__ */ b("div", { className: M("alert", e), style: n, ...c, children: [ + it(h) ? h : typeof h == "string" ? /* @__PURE__ */ b("i", { className: `icon ${h}` }) : null, + it(i) ? i : /* @__PURE__ */ b("div", { className: M("alert-content", o), children: [ + it(s) ? s : s && /* @__PURE__ */ b("div", { className: "alert-heading", children: s }), + /* @__PURE__ */ b("div", { className: "alert-text", children: i }), + s ? d : null + ] }), + s ? null : d, + u, + r + ] }); +} +function wh(e) { + if (e === "center") + return "fade-from-center"; + if (e) { + if (e.includes("top")) + return "fade-from-top"; + if (e.includes("bottom")) + return "fade-from-bottom"; + } + return "fade"; +} +let vh = class extends U { + componentDidMount() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !0 }); + } + componentDidUpdate() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !1 }); + } + componentWillUnmount() { + var n; + (n = this.props.beforeDestroy) == null || n.call(this); + } + render() { + const { + afterRender: n, + beforeDestroy: t, + margin: s, + type: i, + placement: o, + animation: r, + show: l, + className: a, + time: h, + ...c + } = this.props; + return /* @__PURE__ */ b( + bh, + { + className: M("messager", a, i, r === !0 ? wh(o) : r, l ? "in" : ""), + ...c + } + ); + } +}; +var ze, Ss; +class xs extends J { + constructor() { + super(...arguments); + x(this, ze); + w(this, "_show", !1); + w(this, "_showTimer", 0); + w(this, "_afterRender", ({ firstRender: t }) => { + t && this.show(); + const { margin: s } = this.options; + s && (this.element.style.margin = `${s}px`); + }); + } + get isShown() { + return this._show; + } + afterInit() { + this.on("click", (t) => { + t.target.closest('.alert-close,[data-dismiss="messager"]') && (t.preventDefault(), t.stopPropagation(), this.hide()); + }); + } + setOptions(t) { + return t = super.setOptions(t), { + ...t, + show: this._show, + afterRender: this._afterRender + }; + } + show() { + this._show || (this.emit("show"), this.render(), this._show = !0, N(this, ze, Ss).call(this, () => { + this.emit("shown"); + const { time: t } = this.options; + t && N(this, ze, Ss).call(this, () => this.hide(), t); + })); + } + hide() { + this._show && (this._show = !1, this.emit("hide"), this.render(), N(this, ze, Ss).call(this, () => { + this.emit("hidden"); + })); + } +} +ze = new WeakSet(), Ss = function(t, s = 200) { + this._showTimer && clearTimeout(this._showTimer), this._showTimer = window.setTimeout(() => { + t(), this._showTimer = 0; + }, s); +}, w(xs, "NAME", "MessagerItem"), w(xs, "EVENTS", !0), w(xs, "Component", vh); +var we, Ue, jt, Ys, xc, Xs, Sc; +const Xo = class extends kt { + constructor() { + super(...arguments); + x(this, Ys); + x(this, Xs); + x(this, we, void 0); + x(this, Ue, us(6)); + x(this, jt, void 0); + } + get id() { + return m(this, Ue); + } + get isShown() { + var t; + return !!((t = m(this, jt)) != null && t.isShown); + } + show(t) { + this.setOptions(t), N(this, Ys, xc).call(this).show(); + } + hide() { + var t; + (t = m(this, jt)) == null || t.hide(); + } + static show(t) { + typeof t == "string" && (t = { content: t }); + const { container: s, ...i } = t, o = new Xo(s || "body", i); + return o.show(), o; + } +}; +let mn = Xo; +we = new WeakMap(), Ue = new WeakMap(), jt = new WeakMap(), Ys = new WeakSet(), xc = function() { + if (m(this, jt)) + m(this, jt).setOptions(this.options); + else { + const t = N(this, Xs, Sc).call(this), s = new xs(t, this.options); + s.on("hidden", () => { + s.destroy(), t.remove(), R(this, we, void 0); + }), R(this, jt, s); + } + return m(this, jt); +}, Xs = new WeakSet(), Sc = function() { + if (m(this, we)) + return m(this, we); + const { placement: t = "top" } = this.options; + let s = this.element.querySelector(`.messagers-${t}`); + s || (s = document.createElement("div"), s.className = `messagers messagers-${t}`, this.element.appendChild(s)); + let i = s.querySelector(`#messager-${m(this, Ue)}`); + return i || (i = document.createElement("div"), i.className = "messager-holder", i.id = `messager-${m(this, Ue)}`, s.appendChild(i), R(this, we, i)), i; +}, w(mn, "NAME", "messager"), w(mn, "DEFAULT", { + placement: "top", + animation: !0, + close: !0, + margin: 6, + time: 5e3 +}); +A(document).on("zui.messager.show", (e, n) => { + n && mn.show(n); +}); +var bs; +let xh = (bs = class extends U { + render() { + const { percent: n, circleSize: t, circleBorderSize: s, circleBgColor: i, circleColor: o } = this.props, r = (t - s) / 2, l = t / 2; + return /* @__PURE__ */ b("svg", { width: t, height: t, class: "progress-circle", children: [ + /* @__PURE__ */ b("circle", { cx: l, cy: l, r, stroke: i, "stroke-width": s }), + /* @__PURE__ */ b("circle", { cx: l, cy: l, r, stroke: o, "stroke-dasharray": Math.PI * r * 2, "stroke-dashoffset": Math.PI * r * 2 * (100 - n) / 100, "stroke-width": s }), + /* @__PURE__ */ b("text", { x: l, y: l + s / 4, "dominant-baseline": "middle", style: { fontSize: `${r}px` }, children: Math.round(n) }) + ] }); + } +}, w(bs, "NAME", "zui.progress-circle"), w(bs, "defaultProps", { + circleSize: 24, + circleBorderSize: 2, + circleBgColor: "var(--progress-circle-bg)", + circleColor: "var(--progress-circle-bar-color)" +}), bs); +class Mr extends J { +} +w(Mr, "NAME", "table-sorter"), w(Mr, "Component", xh); +let Sh = class extends U { + constructor() { + super(...arguments); + w(this, "state", { checked: !1 }); + w(this, "handleOnClick", () => { + this.setState({ checked: !this.state.checked }); + }); + } + componentDidMount() { + this.setState({ checked: this.props.defaultChecked ?? !1 }); + } + render() { + const { + component: t, + className: s, + children: i, + text: o, + icon: r, + surffixIcon: l, + disabled: a, + defaultChecked: h, + onChange: c, + ...u + } = this.props, d = this.state.checked ? 1 : 0, f = t || "div", p = typeof r == "string" ? /* @__PURE__ */ b("i", { class: `icon ${r}` }) : r, g = typeof l == "string" ? /* @__PURE__ */ b("i", { class: `icon ${l}` }) : l, y = [ + /* @__PURE__ */ b("input", { onChange: c, type: "checkbox", value: d, checked: !!this.state.checked }), + /* @__PURE__ */ b("label", { children: [ + p, + o, + g + ] }) + ]; + return E( + f, + { + className: M("switch", s, { disabled: a }), + onClick: this.handleOnClick, + ...u + }, + ...y, + i + ); + } +}; +class Or extends J { +} +w(Or, "NAME", "switch"), w(Or, "Component", Sh); +function Eh(e) { + const n = typeof e == "string" ? document.querySelector(e) : e; + if (!n) + return !1; + if (n instanceof HTMLInputElement || n instanceof HTMLTextAreaElement) + return n.select(), !0; + if (window.getSelection) { + const t = window.getSelection(); + if (t) { + const s = document.createRange(); + return s.selectNodeContents(n), t.removeAllRanges(), t.addRange(s), !0; + } + } + return !1; +} +function Ch(e, n) { + const t = typeof e == "string" ? document.querySelector(e) : e; + if (!t) + return !1; + const s = t.getBoundingClientRect(), i = window.innerHeight || document.documentElement.clientHeight, o = window.innerWidth || document.documentElement.clientWidth; + if (n != null && n.fullyCheck) + return s.left >= 0 && s.top >= 0 && s.left + s.width <= o && s.top + s.height <= i; + const r = s.top <= i && s.top + s.height >= 0, l = s.left <= o && s.left + s.width >= 0; + return r && l; +} +const Ed = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ + __proto__: null, + classes: M, + getClassList: Ii, + isElementVisible: Ch, + selectText: Eh +}, Symbol.toStringTag, { value: "Module" })); +/*! js-cookie v3.0.1 | MIT */ +function ms(e) { + for (var n = 1; n < arguments.length; n++) { + var t = arguments[n]; + for (var s in t) + e[s] = t[s]; + } + return e; +} +var $h = { + read: function(e) { + return e[0] === '"' && (e = e.slice(1, -1)), e.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent); + }, + write: function(e) { + return encodeURIComponent(e).replace( + /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, + decodeURIComponent + ); + } +}; +function wo(e, n) { + function t(i, o, r) { + if (!(typeof document > "u")) { + r = ms({}, n, r), typeof r.expires == "number" && (r.expires = new Date(Date.now() + r.expires * 864e5)), r.expires && (r.expires = r.expires.toUTCString()), i = encodeURIComponent(i).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape); + var l = ""; + for (var a in r) + r[a] && (l += "; " + a, r[a] !== !0 && (l += "=" + r[a].split(";")[0])); + return document.cookie = i + "=" + e.write(o, i) + l; + } + } + function s(i) { + if (!(typeof document > "u" || arguments.length && !i)) { + for (var o = document.cookie ? document.cookie.split("; ") : [], r = {}, l = 0; l < o.length; l++) { + var a = o[l].split("="), h = a.slice(1).join("="); + try { + var c = decodeURIComponent(a[0]); + if (r[c] = e.read(h, c), i === c) + break; + } catch { + } + } + return i ? r[i] : r; + } + } + return Object.create( + { + set: t, + get: s, + remove: function(i, o) { + t( + i, + "", + ms({}, o, { + expires: -1 + }) + ); + }, + withAttributes: function(i) { + return wo(this.converter, ms({}, this.attributes, i)); + }, + withConverter: function(i) { + return wo(ms({}, this.converter, i), this.attributes); + } + }, + { + attributes: { value: Object.freeze(n) }, + converter: { value: Object.freeze(e) } + } + ); +} +var Rh = wo($h, { path: "/" }); +window.$ && Object.assign(window.$, { cookie: Rh }); +var Ec = function(e, n, t, s) { + var i; + n[0] = 0; + for (var o = 1; o < n.length; o++) { + var r = n[o++], l = n[o] ? (n[0] |= r ? 1 : 2, t[n[o++]]) : n[++o]; + r === 3 ? s[0] = l : r === 4 ? s[1] = Object.assign(s[1] || {}, l) : r === 5 ? (s[1] = s[1] || {})[n[++o]] = l : r === 6 ? s[1][n[++o]] += l + "" : r ? (i = e.apply(l, Ec(e, l, t, ["", null])), s.push(i), l[0] ? n[0] |= 2 : (n[o - 2] = 0, n[o] = i)) : s.push(l); + } + return s; +}, Pr = /* @__PURE__ */ new Map(); +function Cc(e) { + var n = Pr.get(this); + return n || (n = /* @__PURE__ */ new Map(), Pr.set(this, n)), (n = Ec(this, n.get(e) || (n.set(e, n = function(t) { + for (var s, i, o = 1, r = "", l = "", a = [0], h = function(d) { + o === 1 && (d || (r = r.replace(/^\s*\n\s*|\s*\n\s*$/g, ""))) ? a.push(0, d, r) : o === 3 && (d || r) ? (a.push(3, d, r), o = 2) : o === 2 && r === "..." && d ? a.push(4, d, 0) : o === 2 && r && !d ? a.push(5, 0, !0, r) : o >= 5 && ((r || !d && o === 5) && (a.push(o, 0, r, i), o = 6), d && (a.push(o, d, 0, i), o = 6)), r = ""; + }, c = 0; c < t.length; c++) { + c && (o === 1 && h(), h(c)); + for (var u = 0; u < t[c].length; u++) + s = t[c][u], o === 1 ? s === "<" ? (h(), a = [a], o = 3) : r += s : o === 4 ? r === "--" && s === ">" ? (o = 1, r = "") : r = s + r[0] : l ? s === l ? l = "" : r += s : s === '"' || s === "'" ? l = s : s === ">" ? (h(), o = 1) : o && (s === "=" ? (o = 5, i = r, r = "") : s === "/" && (o < 5 || t[c][u + 1] === ">") ? (h(), o === 3 && (a = a[0]), o = a, (a = a[0]).push(2, 0, o), o = 0) : s === " " || s === " " || s === ` +` || s === "\r" ? (h(), o = 2) : r += s), o === 3 && r === "!--" && (o = 4, a = a[0]); + } + return h(), a; + }(e)), n), arguments, [])).length > 1 ? n : n[0]; +} +var kh = Cc.bind(E); +Object.assign(window, { htm: Cc, html: kh, preact: Ia }); +var Wn, Zt, vt, Ve, qe, Es; +const Jo = class { + /** + * Create new store instance + * @param name Name of store + * @param type Store type + */ + constructor(n, t = "local") { + x(this, qe); + x(this, Wn, void 0); + x(this, Zt, void 0); + x(this, vt, void 0); + x(this, Ve, void 0); + R(this, Wn, t), R(this, Zt, `ZUI_STORE:${n ?? us()}`), R(this, vt, t === "local" ? localStorage : sessionStorage); + } + /** + * Get store type + */ + get type() { + return m(this, Wn); + } + /** + * Get session type store instance + */ + get session() { + return this.type === "session" ? this : (m(this, Ve) || R(this, Ve, new Jo(m(this, Zt), "session")), m(this, Ve)); + } + /** + * Get value from store + * @param key Key to get + * @param defaultValue default value to return if key is not found + * @returns Value of key or defaultValue if key is not found + */ + get(n, t) { + const s = m(this, vt).getItem(N(this, qe, Es).call(this, n)); + return typeof s == "string" ? JSON.parse(s) : s ?? t; + } + /** + * Set key-value pair in store + * @param key Key to set + * @param value Value to set + */ + set(n, t) { + if (t == null) + return this.remove(n); + m(this, vt).setItem(N(this, qe, Es).call(this, n), JSON.stringify(t)); + } + /** + * Remove key-value pair from store + * @param key Key to remove + */ + remove(n) { + m(this, vt).removeItem(N(this, qe, Es).call(this, n)); + } + /** + * Iterate all key-value pairs in store + * @param callback Callback function to call for each key-value pair in the store + */ + each(n) { + for (let t = 0; t < m(this, vt).length; t++) { + const s = m(this, vt).key(t); + if (s != null && s.startsWith(m(this, Zt))) { + const i = m(this, vt).getItem(s); + typeof i == "string" && n(s.substring(m(this, Zt).length + 1), JSON.parse(i)); + } + } + } + /** + * Get all key values in store + * @returns All key-value pairs in the store + */ + getAll() { + const n = {}; + return this.each((t, s) => { + n[t] = s; + }), n; + } +}; +let js = Jo; +Wn = new WeakMap(), Zt = new WeakMap(), vt = new WeakMap(), Ve = new WeakMap(), qe = new WeakSet(), Es = function(n) { + return `${m(this, Zt)}:${n}`; +}; +const Th = new js("DEFAULT"); +function Ah(e, n = "local") { + return new js(e, n); +} +Object.assign(Th, { create: Ah }); +const W = qu, qo = window.document; +let gs, Yt; +const Nh = /)<[^<]*)*<\/script>/gi, Lh = /^(?:text|application)\/javascript/i, Mh = /^(?:text|application)\/xml/i, $c = "application/json", Rc = "text/html", Oh = /^\s*$/, vo = qo.createElement("a"); +vo.href = window.location.href; +function Ph(e, n, t) { + const s = new CustomEvent(n, { detail: t }); + return W(e).trigger(s, t), !s.defaultPrevented; +} +function Re(e, n, t, s) { + if (e.global) + return Ph(n || qo, t, s); +} +W.active = 0; +function Dh(e) { + e.global && W.active++ === 0 && Re(e, null, "ajaxStart"); +} +function Hh(e) { + e.global && !--W.active && Re(e, null, "ajaxStop"); +} +function Ih(e, n) { + const t = n.context; + if (n.beforeSend.call(t, e, n) === !1 || Re(n, t, "ajaxBeforeSend", [e, n]) === !1) + return !1; + Re(n, t, "ajaxSend", [e, n]); +} +function jh(e, n, t) { + const s = t.context, i = "success"; + t.success.call(s, e, i, n), Re(t, s, "ajaxSuccess", [n, t, e]), kc(i, n, t); +} +function ys(e, n, t, s) { + const i = s.context; + s.error.call(i, t, n, e), Re(s, i, "ajaxError", [t, s, e || n]), kc(n, t, s); +} +function kc(e, n, t) { + const s = t.context; + t.complete.call(s, n, e), Re(t, s, "ajaxComplete", [n, t]), Hh(t); +} +function Wh(e, n, t) { + if (t.dataFilter == Jt) + return e; + const s = t.context; + return t.dataFilter.call(s, e, n); +} +function Jt() { +} +W.ajaxSettings = { + // Default type of request + type: "GET", + // Callback that is executed before request + beforeSend: Jt, + // Callback that is executed if the request succeeds + success: Jt, + // Callback that is executed the the server drops error + error: Jt, + // Callback that is executed on request complete (both: error and success) + complete: Jt, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: !0, + // Transport + xhr: function() { + return new window.XMLHttpRequest(); + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: "text/javascript, application/javascript, application/x-javascript", + json: $c, + xml: "application/xml, text/xml", + html: Rc, + text: "text/plain" + }, + // Whether the request is to another domain + crossDomain: !1, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: !0, + // Whether the browser should be allowed to cache GET responses + cache: !0, + //Used to handle the raw response data of XMLHttpRequest. + //This is a pre-filtering function to sanitize the response. + //The sanitized response should be returned + dataFilter: Jt +}; +function Fh(e) { + return e && (e = e.split(";", 2)[0]), e && (e == Rc ? "html" : e == $c ? "json" : Lh.test(e) ? "script" : Mh.test(e) && "xml") || "text"; +} +function Tc(e, n) { + return n == "" ? e : (e + "&" + n).replace(/[&?]{1,2}/, "?"); +} +function Bh(e) { + e.processData && e.data && typeof e.data != "string" && (e.data = W.param(e.data, e.traditional)), e.data && (!e.type || e.type.toUpperCase() == "GET" || e.dataType == "jsonp") && (e.url = Tc(e.url, e.data), e.data = void 0); +} +W.ajax = function(e) { + var p; + const n = W.extend({}, e || {}); + let t, s; + for (gs in W.ajaxSettings) + n[gs] === void 0 && (n[gs] = W.ajaxSettings[gs]); + Dh(n), n.crossDomain || (t = qo.createElement("a"), t.href = n.url, t.href = t.href, n.crossDomain = vo.protocol + "//" + vo.host != t.protocol + "//" + t.host), n.url || (n.url = window.location.toString()), (s = n.url.indexOf("#")) > -1 && (n.url = n.url.slice(0, s)), Bh(n); + let i = n.dataType; + /\?.+=\?/.test(n.url) && (i = "jsonp"), (n.cache === !1 || (!e || e.cache !== !0) && (i == "script" || i == "jsonp")) && (n.url = Tc(n.url, "_=" + Date.now())); + let r = n.accepts[i]; + const l = {}, a = function(g, y) { + l[g.toLowerCase()] = [g, y]; + }, h = /^([\w-]+:)\/\//.test(n.url) ? RegExp.$1 : window.location.protocol, c = n.xhr(), u = c.setRequestHeader; + let d; + if (n.crossDomain || a("X-Requested-With", "XMLHttpRequest"), a("Accept", r || "*/*"), r = n.mimeType, r && (r.indexOf(",") > -1 && (r = r.split(",", 2)[0]), (p = c.overrideMimeType) == null || p.call(c, r)), (n.contentType || n.contentType !== !1 && n.data && n.type.toUpperCase() != "GET") && a("Content-Type", n.contentType || "application/x-www-form-urlencoded"), n.headers) + for (Yt in n.headers) + a(Yt, n.headers[Yt]); + if (c.setRequestHeader = a, c.onreadystatechange = function() { + if (c.readyState == 4) { + c.onreadystatechange = Jt, clearTimeout(d); + let g, y = !1; + if (c.status >= 200 && c.status < 300 || c.status == 304 || c.status == 0 && h == "file:") { + if (i = i || Fh(n.mimeType || c.getResponseHeader("content-type")), c.responseType == "arraybuffer" || c.responseType == "blob") + g = c.response; + else { + g = c.responseText; + try { + g = Wh(g, i, n), i == "xml" ? g = c.responseXML : i == "json" && (g = Oh.test(g) ? null : JSON.parse(g)); + } catch (_) { + y = _; + } + if (y) + return ys(y, "parsererror", c, n); + } + jh(g, c, n); + } else + ys(c.statusText || null, c.status ? "error" : "abort", c, n); + } + }, Ih(c, n) === !1) + return c.abort(), ys(null, "abort", c, n), c; + const f = "async" in n ? n.async : !0; + if (c.open(n.type, n.url, f, n.username, n.password), n.xhrFields) + for (Yt in n.xhrFields) + c[Yt] = n.xhrFields[Yt]; + for (Yt in l) + u.apply(c, l[Yt]); + return n.timeout > 0 && (d = setTimeout(function() { + c.onreadystatechange = Jt, c.abort(), ys(null, "timeout", c, n); + }, n.timeout)), c.send(n.data ? n.data : null), c; +}; +function qi(e, n, t, s) { + return W.isFunction(n) && (s = t, t = n, n = void 0), W.isFunction(t) || (s = t, t = void 0), { + url: e, + data: n, + success: t, + dataType: s + }; +} +W.get = function(e, n, t, s) { + return W.ajax(qi(e, n, t, s)); +}; +W.post = function(e, n, t, s) { + const i = qi(e, n, t, s); + return W.ajax(Object.assign(i, { type: "POST" })); +}; +W.getJSON = function(e, n, t, s) { + const i = qi(e, n, t, s); + return i.dataType = "json", W.ajax(i); +}; +W.fn.load = function(e, n, t) { + if (!this.length) + return this; + const s = e.split(/\s/); + let i; + const o = qi(e, n, t), r = o.success; + return s.length > 1 && (o.url = s[0], i = s[1]), o.success = (l, ...a) => { + this.html(i ? W("
    ").html(l.replace(Nh, "")).find(i) : l), r == null || r.call(this, l, ...a); + }, W.ajax(o), this; +}; +const Dr = encodeURIComponent; +function Ac(e, n, t, s) { + const i = W.isArray(n), o = W.isPlainObject(n); + W.each(n, function(r, l) { + const a = Array.isArray(l) ? "array" : typeof l; + s && (r = t ? s : s + "[" + (o || a == "object" || a == "array" ? r : "") + "]"), !s && i ? e.add(l.name, l.value) : a == "array" || !t && a == "object" ? Ac(e, l, t, r) : e.add(r, l); + }); +} +W.param = function(e, n) { + const t = []; + return t.add = function(s, i) { + W.isFunction(i) && (i = i()), i == null && (i = ""), this.push(Dr(s) + "=" + Dr(i)); + }, Ac(t, e, n), t.join("&").replace(/%20/g, "+"); +}; +const Cd = Object.assign(W.ajax, { + get: W.get, + post: W.post, + getJSON: W.getJSON, + param: W.param, + ajaxSettings: W.ajaxSettings +}), $d = new Hi(); +function zh(e) { + if (e.indexOf("#") === 0 && (e = e.slice(1)), e.length === 3 && (e = e[0] + e[0] + e[1] + e[1] + e[2] + e[2]), e.length !== 6) + throw new Error(`Invalid HEX color "${e}".`); + return [ + parseInt(e.slice(0, 2), 16), + // r + parseInt(e.slice(2, 4), 16), + // g + parseInt(e.slice(4, 6), 16) + // b + ]; +} +function Uh(e) { + const [n, t, s] = typeof e == "string" ? zh(e) : e; + return n * 0.299 + t * 0.587 + s * 0.114 > 186; +} +function Hr(e, n) { + return Uh(e) ? (n == null ? void 0 : n.dark) ?? "#333333" : (n == null ? void 0 : n.light) ?? "#ffffff"; +} +function Ir(e, n = 255) { + return Math.min(Math.max(e, 0), n); +} +function Vh(e, n, t) { + e = e % 360 / 360, n = Ir(n), t = Ir(t); + const s = t <= 0.5 ? t * (n + 1) : t + n - t * n, i = t * 2 - s, o = (r) => (r = r < 0 ? r + 1 : r > 1 ? r - 1 : r, r * 6 < 1 ? i + (s - i) * r * 6 : r * 2 < 1 ? s : r * 3 < 2 ? i + (s - i) * (2 / 3 - r) * 6 : i); + return [ + o(e + 1 / 3) * 255, + o(e) * 255, + o(e - 1 / 3) * 255 + ]; +} +function qh(e) { + let n = 0; + if (typeof e != "string" && (e = String(e)), e && e.length) + for (let t = 0; t < e.length; ++t) + n += (t + 1) * e.charCodeAt(t); + return n; +} +function Gh(e, n) { + return /^[\u4e00-\u9fa5\s]+$/.test(e) ? e = e.length <= n ? e : e.substring(e.length - n) : /^[A-Za-z\d\s]+$/.test(e) ? e = e[0].toUpperCase() : e = e.length <= n ? e : e.substring(0, n), e; +} +let Nc = class extends U { + render() { + const { + className: n, + style: t, + size: s = "", + circle: i, + rounded: o, + background: r, + foreColor: l, + text: a, + code: h, + maxTextLength: c = 2, + src: u, + hueDistance: d = 43, + saturation: f = 0.4, + lightness: p = 0.6, + children: g, + ...y + } = this.props, _ = ["avatar", n], v = { ...t, background: r, color: l }; + let S = 32; + s && (typeof s == "number" ? (v.width = `${s}px`, v.height = `${s}px`, v.fontSize = `${Math.max(12, Math.round(s / 2))}px`, S = s) : (_.push(`size-${s}`), S = { xs: 20, sm: 24, lg: 48, xl: 80 }[s])), i ? _.push("circle") : o && (typeof o == "number" ? v.borderRadius = `${o}px` : _.push(`rounded-${o}`)); + let $; + if (u) + _.push("has-img"), $ = /* @__PURE__ */ b("img", { className: "avatar-img", src: u, alt: a }); + else if (a != null && a.length) { + const T = Gh(a, c); + if (_.push("has-text", `has-text-${T.length}`), r) + !l && r && (v.color = Hr(r)); + else { + const L = h ?? a, O = (typeof L == "number" ? L : qh(L)) * d % 360; + if (v.background = `hsl(${O},${f * 100}%,${p * 100}%)`, !l) { + const k = Vh(O, f, p); + v.color = Hr(k); + } + } + let D; + S && S < 14 * T.length && (D = { transform: `scale(${S / (14 * T.length)})`, whiteSpace: "nowrap" }), $ = /* @__PURE__ */ b("div", { "data-actualSize": S, className: "avatar-text", style: D, children: T }); + } + return /* @__PURE__ */ b( + "div", + { + className: M(_), + style: v, + ...y, + children: [ + $, + g + ] + } + ); + } +}; +class jr extends J { +} +w(jr, "NAME", "avatar"), w(jr, "Component", Nc); +class Wr extends J { +} +w(Wr, "NAME", "btngroup"), w(Wr, "Component", vc); +function Lc(e, n, t) { + if (t) { + e.setAttribute("class", M(n)); + return; + } + Ii(e.getAttribute("class"), n).forEach(([s, i]) => { + e.classList.toggle(s, i); + }); +} +function gn(e, n, t) { + if (typeof n == "object") + return Object.entries(n).forEach(([s, i]) => { + gn(e, s, i); + }); + t !== void 0 && (e.style[n] = typeof t == "number" ? `${t}px` : t); +} +function Ws(e, n, t) { + if (typeof n == "object") + return Object.entries(n).forEach(([s, i]) => { + Ws(e, s, i); + }); + t !== void 0 && (t === null ? e.removeAttribute(n) : e.setAttribute(n, t)); +} +var ve, Fn, te, Js, Ge, Cs; +const rt = class extends kt { + constructor() { + super(...arguments); + x(this, Ge); + x(this, ve, 0); + x(this, Fn, void 0); + x(this, te, void 0); + x(this, Js, (t) => { + const s = t.target; + (s.closest(rt.DISMISS_SELECTOR) || this.options.backdrop === !0 && !s.closest(".modal-dialog") && s.closest(".modal")) && this.hide(); + }); + } + get modalElement() { + return this.element; + } + get isShown() { + return this.modalElement.classList.contains(rt.CLASS_SHOW); + } + get dialog() { + return this.modalElement.querySelector(".modal-dialog"); + } + afterInit() { + if (this.on("click", m(this, Js)), this.options.responsive && typeof ResizeObserver < "u") { + const { dialog: t } = this; + if (t) { + const s = new ResizeObserver(() => { + if (!this.isShown) + return; + const i = t.clientWidth, o = t.clientHeight; + (!m(this, te) || m(this, te)[0] !== i || m(this, te)[1] !== o) && (R(this, te, [i, o]), this.layout()); + }); + s.observe(t), R(this, Fn, s); + } + } + this.options.show && this.show(); + } + destroy() { + var t; + super.destroy(), (t = m(this, Fn)) == null || t.disconnect(); + } + show(t) { + if (this.isShown) + return !1; + this.setOptions(t); + const { modalElement: s } = this, { animation: i, backdrop: o, className: r, style: l } = this.options; + return Lc(s, [{ + "modal-trans": i, + "modal-no-backdrop": !o + }, rt.CLASS_SHOW, r]), gn(s, { + zIndex: `${rt.zIndex++}`, + ...l + }), this.layout(), this.emit("show", this), N(this, Ge, Cs).call(this, () => { + s.classList.add(rt.CLASS_SHOWN), N(this, Ge, Cs).call(this, () => { + this.emit("shown", this); + }); + }, 50), !0; + } + hide() { + return this.isShown ? (this.modalElement.classList.remove(rt.CLASS_SHOWN), this.emit("hide", this), N(this, Ge, Cs).call(this, () => { + this.modalElement.classList.remove(rt.CLASS_SHOW), this.emit("hidden", this); + }), !0) : !1; + } + layout(t, s) { + if (!this.isShown) + return; + const { dialog: i } = this; + if (!i) + return; + s = s ?? this.options.size, Ws(i, "data-size", null); + const o = { width: null, height: null }; + typeof s == "object" ? (o.width = s.width, o.height = s.height) : typeof s == "string" && ["md", "sm", "lg", "full"].includes(s) ? Ws(i, "data-size", s) : s && (o.width = s), gn(i, o), t = t ?? this.options.position ?? "fit"; + const r = i.clientWidth, l = i.clientHeight; + R(this, te, [r, l]), typeof t == "function" && (t = t({ width: r, height: l })); + const a = { + top: null, + left: null, + bottom: null, + right: null, + alignSelf: "center" + }; + typeof t == "number" ? (a.alignSelf = "flex-start", a.top = t) : typeof t == "object" && t ? (a.alignSelf = "flex-start", Object.assign(a, t)) : t === "fit" ? (a.alignSelf = "flex-start", a.top = `${Math.max(0, Math.floor((window.innerHeight - l) / 3))}px`) : t === "bottom" ? a.alignSelf = "flex-end" : t === "top" ? a.alignSelf = "flex-start" : t !== "center" && typeof t == "string" && (a.alignSelf = "flex-start", a.top = t), gn(i, a), gn(this.modalElement, "justifyContent", a.left ? "flex-start" : "center"); + } + static query(t) { + if (t === void 0 ? t = document.querySelector(`.modal.${rt.CLASS_SHOW}`) : typeof t == "string" && (t = document.querySelector(t)), !!t) + return rt.get(t); + } + static hide(t) { + var s; + (s = rt.query(t)) == null || s.hide(); + } + static show(t) { + var s; + (s = rt.query(t)) == null || s.show(); + } +}; +let nt = rt; +ve = new WeakMap(), Fn = new WeakMap(), te = new WeakMap(), Js = new WeakMap(), Ge = new WeakSet(), Cs = function(t, s) { + m(this, ve) && (clearTimeout(m(this, ve)), R(this, ve, 0)), t && (this.options.animation ? R(this, ve, window.setTimeout(t, s ?? this.options.transTime)) : t()); +}, w(nt, "NAME", "Modal"), w(nt, "EVENTS", !0), w(nt, "DEFAULT", { + position: "fit", + show: !0, + keyboard: !0, + animation: !0, + backdrop: !0, + responsive: !0, + transTime: 300 +}), w(nt, "CLASS_SHOW", "show"), w(nt, "CLASS_SHOWN", "in"), w(nt, "DISMISS_SELECTOR", '[data-dismiss="modal"]'), w(nt, "zIndex", 2e3); +A(window).on("resize", () => { + nt.all.forEach((e) => { + const n = e; + n.isShown && n.options.responsive && n.layout(); + }); +}); +A(document).on("zui.modal.hide", (e, n) => { + nt.hide(n == null ? void 0 : n.target); +}); +class Mc extends U { + componentDidMount() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !0 }); + } + componentDidUpdate() { + var n; + (n = this.props.afterRender) == null || n.call(this, { firstRender: !1 }); + } + componentWillUnmount() { + var n; + (n = this.props.beforeDestroy) == null || n.call(this); + } + renderHeader() { + const { + header: n, + title: t + } = this.props; + return it(n) ? n : n === !1 || !t ? null : /* @__PURE__ */ b("div", { className: "modal-header", children: /* @__PURE__ */ b("div", { className: "modal-title", children: t }) }); + } + renderActions() { + const { + actions: n, + closeBtn: t + } = this.props; + return !t && !n ? null : it(n) ? n : /* @__PURE__ */ b("div", { className: "modal-actions", children: [ + n ? /* @__PURE__ */ b(ae, { ...n }) : null, + t ? /* @__PURE__ */ b("button", { type: "button", class: "btn square ghost", "data-dismiss": "modal", children: /* @__PURE__ */ b("span", { class: "close" }) }) : null + ] }); + } + renderBody() { + const { + body: n + } = this.props; + return n ? it(n) ? n : /* @__PURE__ */ b("div", { className: "modal-body", children: n }) : null; + } + renderFooter() { + const { + footer: n, + footerActions: t + } = this.props; + return it(n) ? n : n === !1 || !t ? null : /* @__PURE__ */ b("div", { className: "modal-footer", children: t ? /* @__PURE__ */ b(ae, { ...t }) : null }); + } + render() { + const { + className: n, + style: t, + children: s + } = this.props; + return /* @__PURE__ */ b("div", { className: M("modal-dialog", n), style: t, children: /* @__PURE__ */ b("div", { className: "modal-content", children: [ + this.renderHeader(), + this.renderActions(), + this.renderBody(), + s, + this.renderFooter() + ] }) }); + } +} +w(Mc, "defaultProps", { closeBtn: !0 }); +var Bn, Ke, zn; +class Kh extends U { + constructor() { + super(...arguments); + x(this, Bn, cn()); + x(this, Ke, void 0); + w(this, "state", {}); + x(this, zn, () => { + var i, o; + const t = (o = (i = m(this, Bn).current) == null ? void 0 : i.contentWindow) == null ? void 0 : o.document; + if (!t) + return; + let s = m(this, Ke); + s == null || s.disconnect(), s = new ResizeObserver(() => { + const r = t.body, l = t.documentElement, a = Math.ceil(Math.max(r.scrollHeight, r.offsetHeight, l.offsetHeight)); + this.setState({ height: a }); + }), s.observe(t.body), s.observe(t.documentElement), R(this, Ke, s); + }); + } + componentDidMount() { + m(this, zn).call(this); + } + componentWillUnmount() { + var t; + (t = m(this, Ke)) == null || t.disconnect(); + } + render() { + const { url: t } = this.props; + return /* @__PURE__ */ b( + "iframe", + { + className: "modal-iframe", + style: this.state, + src: t, + ref: m(this, Bn), + onLoad: m(this, zn) + } + ); + } +} +Bn = new WeakMap(), Ke = new WeakMap(), zn = new WeakMap(); +function Yh(e, n) { + const { custom: t, title: s, content: i } = n; + return { + body: i, + title: s, + ...typeof t == "function" ? t() : t + }; +} +async function Xh(e, n) { + const { dataType: t = "html", url: s, request: i, custom: o, title: r, replace: l = !0 } = n, h = await (await fetch(s, i)).text(); + if (t !== "html") + try { + const c = JSON.parse(h); + return { + title: r, + ...o, + ...c + }; + } catch { + } + return n.replace !== !1 && t === "html" ? [h] : { + title: r, + ...o, + body: t === "html" ? /* @__PURE__ */ b("div", { className: "modal-body", dangerouslySetInnerHTML: { __html: h } }) : h + }; +} +async function Jh(e, n) { + const { url: t, custom: s, title: i } = n; + return { + title: i, + ...s, + body: /* @__PURE__ */ b(Kh, { url: t }) + }; +} +const Qh = { + custom: Yh, + ajax: Xh, + iframe: Jh +}; +var Un, Vn, xt, Ye, $s, Qs, Oc, qn, xo; +const kn = class extends nt { + constructor() { + super(...arguments); + x(this, Ye); + x(this, Qs); + x(this, qn); + x(this, Un, void 0); + x(this, Vn, void 0); + x(this, xt, void 0); + } + get id() { + return m(this, Vn); + } + get loading() { + return this.modalElement.classList.contains(kn.LOADING_CLASS); + } + get modalElement() { + let t = m(this, Un); + if (!t) { + const { id: s } = this; + t = this.element.querySelector(`#${s}`), t || (t = document.createElement("div"), Ws(t, { + id: s, + style: this.options.style + }), Lc(t, ["modal modal-async", this.options.className]), this.element.appendChild(t)), R(this, Un, t); + } + return t; + } + afterInit() { + super.afterInit(), R(this, Vn, this.options.id || `modal-${us()}`); + } + show(t) { + return super.show(t) ? (this.buildDialog(), !0) : !1; + } + render(t) { + super.render(t), this.buildDialog(); + } + async buildDialog() { + if (this.loading) + return !1; + m(this, xt) && clearTimeout(m(this, xt)); + const { modalElement: t, options: s } = this, { type: i, loadTimeout: o } = s, r = Qh[i]; + if (!r) + return console.warn(`Modal: Cannot build modal with type "${i}"`), !1; + t.classList.add(kn.LOADING_CLASS), await N(this, Qs, Oc).call(this), o && R(this, xt, window.setTimeout(() => { + R(this, xt, 0), N(this, qn, xo).call(this, this.options.timeoutTip); + }, o)); + const l = await r(t, s); + return l === !1 ? await N(this, qn, xo).call(this, this.options.failedTip) : l && typeof l == "object" && await N(this, Ye, $s).call(this, l), m(this, xt) && (clearTimeout(m(this, xt)), R(this, xt, 0)), t.classList.remove(kn.LOADING_CLASS), !0; + } +}; +let yn = kn; +Un = new WeakMap(), Vn = new WeakMap(), xt = new WeakMap(), Ye = new WeakSet(), $s = function(t) { + return new Promise((s) => { + if (Array.isArray(t)) + return this.modalElement.innerHTML = t[0], s(); + const { afterRender: i, ...o } = t; + t = { + afterRender: (r) => { + this.layout(), i == null || i(r), s(); + }, + ...o + }, cs( + /* @__PURE__ */ b(Mc, { ...t }), + this.modalElement + ); + }); +}, Qs = new WeakSet(), Oc = function() { + const { loadingText: t } = this.options; + return N(this, Ye, $s).call(this, { + body: /* @__PURE__ */ b("div", { className: "modal-loading-indicator", children: [ + /* @__PURE__ */ b("span", { className: "spinner" }), + t ? /* @__PURE__ */ b("span", { className: "modal-loading-text", children: t }) : null + ] }) + }); +}, qn = new WeakSet(), xo = function(t) { + if (t) + return N(this, Ye, $s).call(this, { + body: /* @__PURE__ */ b("div", { className: "modal-load-failed", children: t }) + }); +}, w(yn, "LOADING_CLASS", "loading"), w(yn, "DEFAULT", { + ...nt.DEFAULT, + loadTimeout: 1e4 +}); +var ee, Zs, Pc, ti, Dc, ei, Hc; +class Cn extends kt { + constructor() { + super(...arguments); + x(this, Zs); + x(this, ti); + x(this, ei); + x(this, ee, void 0); + } + get modal() { + return m(this, ee); + } + get container() { + const { container: t } = this.options; + return typeof t == "string" ? document.querySelector(t) : t instanceof HTMLElement ? t : document.body; + } + show() { + return N(this, ti, Dc).call(this).show(); + } + hide() { + var t; + (t = m(this, ee)) == null || t.hide(); + } +} +ee = new WeakMap(), Zs = new WeakSet(), Pc = function() { + const { + container: t, + ...s + } = this.options, i = s, o = this.element.getAttribute("href") || ""; + return i.type || (i.target || o[0] === "#" ? i.type = "static" : i.type = i.type || (i.url || o ? "ajax" : "custom")), !i.url && (i.type === "iframe" || i.type === "ajax") && o[0] !== "#" && (i.url = o), i; +}, ti = new WeakSet(), Dc = function() { + const t = N(this, Zs, Pc).call(this); + let s = m(this, ee); + return s ? s.setOptions(t) : t.type === "static" ? (s = new nt(N(this, ei, Hc).call(this), t), R(this, ee, s)) : (s = new yn(this.container, t), R(this, ee, s)), s; +}, ei = new WeakSet(), Hc = function() { + let t = this.options.target; + if (!t) { + const { element: s } = this; + if (s.tagName === "A") { + const i = s.getAttribute("href"); + i != null && i.startsWith("#") && (t = i); + } + } + return this.container.querySelector(t || ".modal"); +}, w(Cn, "NAME", "ModalTrigger"), w(Cn, "EVENTS", !0), w(Cn, "TOGGLE_SELECTOR", '[data-toggle="modal"]'); +window.addEventListener("click", (e) => { + var s; + const n = e.target, t = (s = n.closest) == null ? void 0 : s.call(n, Cn.TOGGLE_SELECTOR); + if (t) { + const i = Cn.ensure(t); + i && i.show(); + } +}); +var ao; +let Zh = (ao = class extends ji { + beforeRender() { + const n = super.beforeRender(); + return n.className = M(n.className, n.type ? `nav-${n.type}` : "", { + "nav-stacked": n.stacked + }), n; + } +}, w(ao, "NAME", "nav"), ao); +class Fr extends J { +} +w(Fr, "NAME", "nav"), w(Fr, "Component", Zh); +function Mn(e, n) { + const t = e.pageTotal || Math.ceil(e.recTotal / e.recPerPage); + return typeof n == "string" && (n === "first" ? n = 1 : n === "last" ? n = t : n === "prev" ? n = e.page - 1 : n === "next" ? n = e.page + 1 : n === "current" ? n = e.page : n = Number.parseInt(n, 10)), n = n !== void 0 ? Math.max(1, Math.min(n < 0 ? t + n : n, t)) : e.page, { + ...e, + pageTotal: t, + page: n + }; +} +function tf({ + key: e, + type: n, + btnType: t, + page: s, + format: i, + pagerInfo: o, + linkCreator: r, + ...l +}) { + const a = Mn(o, s); + return l.text === void 0 && !l.icon && i && (l.text = typeof i == "function" ? i(a) : tt(i, a)), l.url === void 0 && r && (l.url = typeof r == "function" ? r(a) : tt(r, a)), l.disabled === void 0 && (l.disabled = s !== void 0 && a.page === o.page), /* @__PURE__ */ b(Tt, { type: t, ...l }); +} +const Pt = 24 * 60 * 60 * 1e3, at = (e) => e ? (e instanceof Date || (typeof e == "string" && (e = e.trim(), /^\d+$/.test(e) && (e = Number.parseInt(e, 10))), typeof e == "number" && e < 1e10 && (e *= 1e3), e = new Date(e)), e) : /* @__PURE__ */ new Date(), hs = (e, n = /* @__PURE__ */ new Date()) => (e = at(e), n = at(n), e.getFullYear() === n.getFullYear() && e.getMonth() === n.getMonth() && e.getDate() === n.getDate()), Br = (e, n = /* @__PURE__ */ new Date()) => at(e).getFullYear() === at(n).getFullYear(), ef = (e, n = /* @__PURE__ */ new Date()) => (e = at(e), n = at(n), e.getFullYear() === n.getFullYear() && e.getMonth() === n.getMonth()), Td = (e, n = /* @__PURE__ */ new Date()) => { + e = at(e), n = at(n); + const t = 1e3 * 60 * 60 * 24, s = Math.floor(e.getTime() / t), i = Math.floor(n.getTime() / t); + return Math.floor((s + 4) / 7) === Math.floor((i + 4) / 7); +}, Ad = (e, n) => hs(at(n), e), Nd = (e, n) => hs(at(n).getTime() - Pt, e), Ld = (e, n) => hs(at(n).getTime() + Pt, e), Md = (e, n) => hs(at(n).getTime() - 2 * Pt, e), So = (e, n = "yyyy-MM-dd hh:mm") => { + e = at(e); + const t = { + "M+": e.getMonth() + 1, + "d+": e.getDate(), + "h+": e.getHours(), + "H+": e.getHours() % 12, + "m+": e.getMinutes(), + "s+": e.getSeconds(), + "S+": e.getMilliseconds() + }; + return /(y+)/i.test(n) && (n = n.replace(RegExp.$1, `${e.getFullYear()}`.substring(4 - RegExp.$1.length))), Object.keys(t).forEach((s) => { + if (new RegExp(`(${s})`).test(n)) { + const i = `${t[s]}`; + n = n.replace(RegExp.$1, RegExp.$1.length === 1 ? i : `00${i}`.substring(i.length)); + } + }), n; +}, Od = (e, n, t) => { + const s = { + full: "yyyy-M-d", + month: "M-d", + day: "d", + str: "{0} ~ {1}", + ...t + }, i = So(e, Br(e) ? s.month : s.full); + if (hs(e, n)) + return i; + const o = So(n, Br(e, n) ? ef(e, n) ? s.day : s.month : s.full); + return s.str.replace("{0}", i).replace("{1}", o); +}, Pd = (e) => { + const n = (/* @__PURE__ */ new Date()).getTime(); + switch (e) { + case "oneWeek": + return n - Pt * 7; + case "oneMonth": + return n - Pt * 31; + case "threeMonth": + return n - Pt * 31 * 3; + case "halfYear": + return n - Pt * 183; + case "oneYear": + return n - Pt * 365; + case "twoYear": + return n - 2 * (Pt * 365); + default: + return 0; + } +}, zr = (e, n, t = !0, s = Date.now()) => { + switch (n) { + case "year": + return e *= 365, zr(e, "day", t, s); + case "quarter": + e *= 3; + break; + case "month": + return e *= 30, zr(e, "day", t, s); + case "week": + e *= 7; + break; + case "day": + e *= 24; + break; + case "hour": + e *= 60; + break; + case "minute": + e *= 6e4; + break; + default: + e = 0; + } + return t ? s + e : s - e; +}; +function nf({ + key: e, + type: n, + page: t, + text: s = "", + pagerInfo: i, + children: o, + ...r +}) { + const l = Mn(i, t); + return s = typeof s == "function" ? s(l) : tt(s, l), /* @__PURE__ */ b(Dl, { ...r, children: [ + o, + s + ] }); +} +function sf({ + key: e, + type: n, + btnType: t, + count: s = 12, + pagerInfo: i, + onClick: o, + linkCreator: r, + ...l +}) { + if (!i.pageTotal) + return; + const a = { ...l, square: !0 }, h = () => (a.text = "", a.icon = "icon-ellipsis-h", a.disabled = !0, /* @__PURE__ */ b(Tt, { type: t, ...a })), c = (d, f) => { + const p = []; + for (let g = d; g <= f; g++) { + a.text = g, delete a.icon, a.disabled = !1; + const y = Mn(i, g); + r && (a.url = typeof r == "function" ? r(y) : tt(r, y)), p.push(/* @__PURE__ */ b(Tt, { type: t, ...a, onClick: o })); + } + return p; + }; + let u = []; + return u = [...c(1, 1)], i.pageTotal <= 1 || (i.pageTotal <= s ? u = [...u, ...c(2, i.pageTotal)] : i.page < s - 2 ? u = [...u, ...c(2, s - 2), h(), ...c(i.pageTotal, i.pageTotal)] : i.page > i.pageTotal - s + 3 ? u = [...u, h(), ...c(i.pageTotal - s + 3, i.pageTotal)] : u = [...u, h(), ...c(i.page - Math.ceil((s - 4) / 2), i.page + Math.floor((s - 4) / 2)), h(), ...c(i.pageTotal, i.pageTotal)]), u; +} +function of({ + type: e, + pagerInfo: n, + linkCreator: t, + items: s = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 100, 200, 500, 1e3, 2e3], + dropdown: i = {}, + ...o +}) { + var l; + i.items = i.items ?? s.map((a) => { + const h = { ...n, recPerPage: a }; + return { + text: `${a}`, + url: typeof t == "function" ? t(h) : tt(t, h) + }; + }); + const { text: r = "" } = o; + return o.text = typeof r == "function" ? r(n) : tt(r, n), i.menu = { ...i.menu, className: M((l = i.menu) == null ? void 0 : l.className, "pager-size-menu") }, /* @__PURE__ */ b(wc, { type: "dropdown", dropdown: i, ...o }); +} +function rf({ + key: e, + page: n, + type: t, + btnType: s, + pagerInfo: i, + size: o, + onClick: r, + onChange: l, + linkCreator: a, + ...h +}) { + const c = { ...h }; + let u; + const d = (g) => { + var y; + u = Number((y = g.target) == null ? void 0 : y.value) || 1, u = u > i.pageTotal ? i.pageTotal : u; + }, f = (g) => { + if (!(g != null && g.target)) + return; + u = u <= i.pageTotal ? u : i.pageTotal; + const y = Mn(i, u); + l && !l({ info: y, event: g }) || (g.target.href = c.url = typeof a == "function" ? a(y) : tt(a, y)); + }, p = Mn(i, n || 0); + return c.url = typeof a == "function" ? a(p) : tt(a, p), /* @__PURE__ */ b("div", { className: M("input-group", "pager-goto-group", o ? `size-${o}` : ""), children: [ + /* @__PURE__ */ b("input", { type: "number", class: "form-control", max: i.pageTotal, min: "1", onInput: d }), + /* @__PURE__ */ b(Tt, { type: s, ...c, onClick: f }) + ] }); +} +var dn; +let Ic = (dn = class extends ae { + get pagerInfo() { + const { page: n = 1, recTotal: t = 0, recPerPage: s = 10 } = this.props; + return { page: n, recTotal: t, recPerPage: s, pageTotal: s ? Math.ceil(t / s) : 0 }; + } + isBtnItem(n) { + return n === "link" || n === "nav" || n === "size-menu" || n === "goto" || super.isBtnItem(n); + } + getItemRenderProps(n, t, s) { + const i = super.getItemRenderProps(n, t, s), o = t.type || "item"; + return o === "info" ? Object.assign(i, { pagerInfo: this.pagerInfo }) : (o === "link" || o === "size-menu" || o === "nav" || o === "goto") && Object.assign(i, { pagerInfo: this.pagerInfo, linkCreator: n.linkCreator }), i; + } +}, w(dn, "NAME", "pager"), w(dn, "defaultProps", { + gap: 1, + btnProps: { + btnType: "ghost", + size: "sm" + } +}), w(dn, "ItemComponents", { + ...ae.ItemComponents, + link: tf, + info: nf, + nav: sf, + "size-menu": of, + goto: rf +}), dn); +class Ur extends J { +} +w(Ur, "NAME", "pager"), w(Ur, "Component", Ic); +var ni; +class lf extends U { + constructor() { + super(...arguments); + x(this, ni, (t) => { + var r; + const { onDeselect: s, selections: i } = this.props, o = (r = t.target.closest(".picker-deselect-btn")) == null ? void 0 : r.dataset.idx; + o && s && (i != null && i.length) && (t.stopPropagation(), s([i[+o]], t)); + }); + } + render() { + const { + className: t, + style: s, + disabled: i, + placeholder: o, + focused: r, + selections: l = [], + onClick: a, + children: h + } = this.props; + let c; + return l.length ? c = /* @__PURE__ */ b("div", { className: "picker-multi-selections", children: l.map((u, d) => /* @__PURE__ */ b("div", { className: "picker-multi-selection", children: [ + u.text ?? u.value, + /* @__PURE__ */ b("div", { className: "picker-deselect-btn btn", onClick: m(this, ni), "data-idx": d, children: /* @__PURE__ */ b("span", { className: "close" }) }) + ] })) }) : c = /* @__PURE__ */ b("span", { className: "picker-select-placeholder", children: o }), /* @__PURE__ */ b( + "div", + { + className: M("picker-select picker-select-multi form-control", t, { disabled: i, focused: r }), + style: s, + onClick: a, + children: [ + c, + h, + /* @__PURE__ */ b("span", { class: "caret" }) + ] + } + ); + } +} +ni = new WeakMap(); +var si; +class cf extends U { + constructor() { + super(...arguments); + x(this, si, (t) => { + const { onDeselect: s, selections: i } = this.props; + s && (i != null && i.length) && (t.stopPropagation(), s(i, t)); + }); + } + render() { + const { + className: t, + style: s, + disabled: i, + placeholder: o, + focused: r, + selections: l = [], + onDeselect: a, + onClick: h, + children: c + } = this.props, [u] = l, d = u ? /* @__PURE__ */ b("span", { className: "picker-single-selection", children: u.text ?? u.value }) : /* @__PURE__ */ b("span", { className: "picker-select-placeholder", children: o }), f = u && a ? /* @__PURE__ */ b("button", { type: "button", className: "btn picker-deselect-btn", onClick: m(this, si), children: /* @__PURE__ */ b("span", { className: "close" }) }) : null; + return /* @__PURE__ */ b( + "div", + { + className: M("picker-select picker-select-single form-control", t, { disabled: i, focused: r }), + style: s, + onClick: h, + children: [ + d, + c, + f, + /* @__PURE__ */ b("span", { class: "caret" }) + ] + } + ); + } +} +si = new WeakMap(); +var ii, jc, Gn, oi, Kn, ri; +class af extends U { + constructor() { + super(...arguments); + x(this, ii); + w(this, "state", { keys: "", shown: !1 }); + x(this, Gn, (t) => { + var s; + (s = t.target) != null && s.closest(`#picker-menu-${this.props.id}`) || this.hide(); + }); + x(this, oi, ({ item: t }) => { + const s = this.props.items.find((i) => i.value === t.key); + s && this.props.onSelectItem(s); + }); + x(this, Kn, (t) => { + this.setState({ keys: t.target.value }); + }); + x(this, ri, () => { + this.setState({ keys: "" }); + }); + } + componentDidMount() { + document.addEventListener("click", m(this, Gn)), this.show(); + } + componentWillUnmount() { + document.removeEventListener("click", m(this, Gn)); + } + show() { + this.state.shown || this.setState({ shown: !0 }); + } + hide() { + this.state.shown && this.setState({ shown: !1 }, () => { + window.setTimeout(() => { + var t, s; + (s = (t = this.props).onRequestHide) == null || s.call(t); + }, 200); + }); + } + render() { + const { + id: t, + search: s, + className: i, + style: o = {}, + maxHeight: r, + maxWidth: l, + width: a, + menu: h, + searchHint: c + } = this.props, { shown: u, keys: d } = this.state, f = d.trim().length; + return /* @__PURE__ */ b("div", { className: M("picker-menu", i, { shown: u, "has-search": f }), id: `picker-menu-${t}`, style: { maxHeight: r, maxWidth: l, width: a, ...o }, children: [ + s ? /* @__PURE__ */ b("div", { className: "picker-menu-search", children: [ + /* @__PURE__ */ b("input", { className: "form-control picker-menu-search-input", type: "text", placeholder: c, value: d, onChange: m(this, Kn), onInput: m(this, Kn) }), + f ? /* @__PURE__ */ b("button", { type: "button", className: "btn picker-menu-search-clear", onClick: m(this, ri), children: /* @__PURE__ */ b("span", { className: "close" }) }) : /* @__PURE__ */ b("span", { className: "magnifier" }) + ] }) : null, + /* @__PURE__ */ b(oe, { className: "picker-menu-list", items: N(this, ii, jc).call(this), onClickItem: m(this, oi), ...h }) + ] }); + } +} +ii = new WeakSet(), jc = function() { + const { selections: t, items: s } = this.props, i = new Set(t), o = this.state.keys.toLowerCase().split(" ").filter((r) => r.length); + return s.reduce((r, l) => { + const { + value: a, + keys: h, + text: c, + ...u + } = l; + if (!o.length || o.every((d) => a.toLowerCase().includes(d) || (h == null ? void 0 : h.toLowerCase().includes(d)) || typeof c == "string" && c.toLowerCase().includes(d))) { + let d = c ?? a; + typeof d == "string" && o.length && (d = /* @__PURE__ */ b("span", { dangerouslySetInnerHTML: { __html: o.reduce((f, p) => f.replace(p, `${p}`), d) } })), r.push({ + key: a, + active: i.has(a), + text: d, + ...u + }); + } + return r; + }, []); +}, Gn = new WeakMap(), oi = new WeakMap(), Kn = new WeakMap(), ri = new WeakMap(); +function Vr(e) { + const n = /* @__PURE__ */ new Set(); + return e.reduce((t, s) => (n.has(s) || (n.add(s), t.push(s)), t), []); +} +var uo, Yn, Xn, Jn, Xe, Rs, Qn, Eo, li, Wc, ci, Fc, ai, ui, hi, fi, di, Bc; +let uf = (uo = class extends U { + constructor(t) { + super(t); + x(this, Xe); + x(this, Qn); + x(this, li); + x(this, ci); + x(this, di); + x(this, Yn, 0); + x(this, Xn, us()); + x(this, Jn, cn()); + x(this, ai, (t, s) => { + const { valueList: i } = this, o = new Set(t.map((l) => l.value)), r = i.filter((l) => !o.has(l)); + this.setState({ value: r.length ? r.join(this.props.valueSplitter ?? ",") : void 0 }); + }); + x(this, ui, (t) => { + console.log("#handleSelectClick", t), this.setState({ open: !0 }); + }); + x(this, hi, () => { + this.close(); + }); + x(this, fi, (t) => { + this.props.multi ? this.toggleValue(t.value) : this.setState({ value: t.value }, () => { + var s; + (s = m(this, Jn).current) == null || s.hide(); + }); + }); + this.state = { + value: N(this, li, Wc).call(this, t.defaultValue) ?? "", + open: !1, + loading: !1, + search: "", + items: Array.isArray(t.items) ? t.items : [] + }; + } + get value() { + return this.state.value; + } + get valueList() { + return N(this, Qn, Eo).call(this, this.state.value); + } + componentDidMount() { + var t; + (t = this.props.afterRender) == null || t.call(this, { firstRender: !0 }); + } + componentDidUpdate() { + var t; + (t = this.props.afterRender) == null || t.call(this, { firstRender: !1 }); + } + componentWillUnmount() { + var t; + (t = this.props.beforeDestroy) == null || t.call(this); + } + async loadItemList() { + let { items: t } = this.props; + if (typeof t == "function") { + const i = ++ir(this, Yn)._; + if (await N(this, Xe, Rs).call(this, { loading: !0, items: [] }), t = await t(), m(this, Yn) !== i) + return []; + } + const s = {}; + return Array.isArray(t) && this.state.items !== t && (s.items = t), this.state.loading && (s.loading = !1), Object.keys(s).length && await N(this, Xe, Rs).call(this, s), t; + } + getItemList() { + return this.state.items; + } + getItemMap() { + return this.getItemList().reduce((t, s) => (t[s.value] = s, t), {}); + } + getItemByValue(t) { + return this.getItemList().find((s) => s.value === t); + } + getSelections() { + const t = this.getItemMap(); + return this.valueList.map((s) => t[s] || { value: s }); + } + async toggle(t) { + if (t === void 0) + t = !this.state.open; + else if (t === this.state.open) + return; + await N(this, Xe, Rs).call(this, { open: t }), t && this.loadItemList(); + } + open() { + return this.toggle(!0); + } + close() { + return this.toggle(!1); + } + toggleValue(t, s) { + const { valueList: i } = this, o = i.indexOf(t); + s !== !!o && (o > -1 ? i.splice(o, 1) : i.push(t), this.setState({ value: i.join(this.props.valueSplitter ?? ",") })); + } + render() { + const { + className: t, + style: s, + children: i, + multi: o + } = this.props, r = o ? lf : cf; + return /* @__PURE__ */ b("div", { className: M("picker", t), style: s, id: `picker-${m(this, Xn)}`, children: [ + /* @__PURE__ */ b(r, { ...N(this, ci, Fc).call(this) }), + i, + this.state.open ? /* @__PURE__ */ b(af, { ...N(this, di, Bc).call(this), ref: m(this, Jn) }) : null + ] }); + } +}, Yn = new WeakMap(), Xn = new WeakMap(), Jn = new WeakMap(), Xe = new WeakSet(), Rs = function(t) { + return new Promise((s) => { + this.setState(t, s); + }); +}, Qn = new WeakSet(), Eo = function(t) { + return typeof t == "string" ? Vr(t.split(this.props.valueSplitter ?? ",")) : Array.isArray(t) ? Vr(t) : []; +}, li = new WeakSet(), Wc = function(t) { + const s = N(this, Qn, Eo).call(this, t); + return s.length ? s.join(this.props.valueSplitter ?? ",") : void 0; +}, ci = new WeakSet(), Fc = function() { + const { placeholder: t, disabled: s } = this.props, { open: i } = this.state; + return { + focused: i, + placeholder: t, + disabled: s, + selections: this.getSelections(), + onClick: m(this, ui), + onDeselect: m(this, ai) + }; +}, ai = new WeakMap(), ui = new WeakMap(), hi = new WeakMap(), fi = new WeakMap(), di = new WeakSet(), Bc = function() { + const { search: t, menuClass: s, menuWidth: i, menuStyle: o, menuMaxHeight: r, menuMaxWidth: l } = this.props, { items: a } = this.state; + return { + id: m(this, Xn), + items: a, + selections: this.valueList, + search: t === !0 || typeof t == "number" && t <= a.length, + style: o, + className: s, + width: i, + maxHeight: r, + maxWidth: l, + onRequestHide: m(this, hi), + onSelectItem: m(this, fi) + }; +}, w(uo, "defaultProps", { + container: "body", + valueSplitter: ",", + search: !0, + menuWidth: "auto", + menuMaxHeight: 400 +}), uo); +class qr extends J { +} +w(qr, "NAME", "picker"), w(qr, "Component", uf); +class Gr extends J { +} +w(Gr, "NAME", "toolbar"), w(Gr, "Component", ae); +function fs(e) { + return e.split("-")[1]; +} +function Go(e) { + return e === "y" ? "height" : "width"; +} +function Oe(e) { + return e.split("-")[0]; +} +function Gi(e) { + return ["top", "bottom"].includes(Oe(e)) ? "x" : "y"; +} +function Kr(e, n, t) { + let { reference: s, floating: i } = e; + const o = s.x + s.width / 2 - i.width / 2, r = s.y + s.height / 2 - i.height / 2, l = Gi(n), a = Go(l), h = s[a] / 2 - i[a] / 2, c = l === "x"; + let u; + switch (Oe(n)) { + case "top": + u = { x: o, y: s.y - i.height }; + break; + case "bottom": + u = { x: o, y: s.y + s.height }; + break; + case "right": + u = { x: s.x + s.width, y: r }; + break; + case "left": + u = { x: s.x - i.width, y: r }; + break; + default: + u = { x: s.x, y: s.y }; + } + switch (fs(n)) { + case "start": + u[l] -= h * (t && c ? -1 : 1); + break; + case "end": + u[l] += h * (t && c ? -1 : 1); + } + return u; +} +const hf = async (e, n, t) => { + const { placement: s = "bottom", strategy: i = "absolute", middleware: o = [], platform: r } = t, l = o.filter(Boolean), a = await (r.isRTL == null ? void 0 : r.isRTL(n)); + let h = await r.getElementRects({ reference: e, floating: n, strategy: i }), { x: c, y: u } = Kr(h, s, a), d = s, f = {}, p = 0; + for (let g = 0; g < l.length; g++) { + const { name: y, fn: _ } = l[g], { x: v, y: S, data: $, reset: T } = await _({ x: c, y: u, initialPlacement: s, placement: d, strategy: i, middlewareData: f, rects: h, platform: r, elements: { reference: e, floating: n } }); + c = v ?? c, u = S ?? u, f = { ...f, [y]: { ...f[y], ...$ } }, T && p <= 50 && (p++, typeof T == "object" && (T.placement && (d = T.placement), T.rects && (h = T.rects === !0 ? await r.getElementRects({ reference: e, floating: n, strategy: i }) : T.rects), { x: c, y: u } = Kr(h, d, a)), g = -1); + } + return { x: c, y: u, placement: d, strategy: i, middlewareData: f }; +}; +function zc(e) { + return typeof e != "number" ? function(n) { + return { top: 0, right: 0, bottom: 0, left: 0, ...n }; + }(e) : { top: e, right: e, bottom: e, left: e }; +} +function Fs(e) { + return { ...e, top: e.y, left: e.x, right: e.x + e.width, bottom: e.y + e.height }; +} +async function ff(e, n) { + var t; + n === void 0 && (n = {}); + const { x: s, y: i, platform: o, rects: r, elements: l, strategy: a } = e, { boundary: h = "clippingAncestors", rootBoundary: c = "viewport", elementContext: u = "floating", altBoundary: d = !1, padding: f = 0 } = n, p = zc(f), g = l[d ? u === "floating" ? "reference" : "floating" : u], y = Fs(await o.getClippingRect({ element: (t = await (o.isElement == null ? void 0 : o.isElement(g))) == null || t ? g : g.contextElement || await (o.getDocumentElement == null ? void 0 : o.getDocumentElement(l.floating)), boundary: h, rootBoundary: c, strategy: a })), _ = u === "floating" ? { ...r.floating, x: s, y: i } : r.reference, v = await (o.getOffsetParent == null ? void 0 : o.getOffsetParent(l.floating)), S = await (o.isElement == null ? void 0 : o.isElement(v)) && await (o.getScale == null ? void 0 : o.getScale(v)) || { x: 1, y: 1 }, $ = Fs(o.convertOffsetParentRelativeRectToViewportRelativeRect ? await o.convertOffsetParentRelativeRectToViewportRelativeRect({ rect: _, offsetParent: v, strategy: a }) : _); + return { top: (y.top - $.top + p.top) / S.y, bottom: ($.bottom - y.bottom + p.bottom) / S.y, left: (y.left - $.left + p.left) / S.x, right: ($.right - y.right + p.right) / S.x }; +} +const df = Math.min, pf = Math.max; +function mf(e, n, t) { + return pf(e, df(n, t)); +} +const gf = (e) => ({ name: "arrow", options: e, async fn(n) { + const { element: t, padding: s = 0 } = e || {}, { x: i, y: o, placement: r, rects: l, platform: a } = n; + if (t == null) + return {}; + const h = zc(s), c = { x: i, y: o }, u = Gi(r), d = Go(u), f = await a.getDimensions(t), p = u === "y" ? "top" : "left", g = u === "y" ? "bottom" : "right", y = l.reference[d] + l.reference[u] - c[u] - l.floating[d], _ = c[u] - l.reference[u], v = await (a.getOffsetParent == null ? void 0 : a.getOffsetParent(t)); + let S = v ? u === "y" ? v.clientHeight || 0 : v.clientWidth || 0 : 0; + S === 0 && (S = l.floating[d]); + const $ = y / 2 - _ / 2, T = h[p], D = S - f[d] - h[g], L = S / 2 - f[d] / 2 + $, O = mf(T, L, D), k = fs(r) != null && L != O && l.reference[d] / 2 - (L < T ? h[p] : h[g]) - f[d] / 2 < 0; + return { [u]: c[u] - (k ? L < T ? T - L : D - L : 0), data: { [u]: O, centerOffset: L - O } }; +} }), yf = ["top", "right", "bottom", "left"]; +yf.reduce((e, n) => e.concat(n, n + "-start", n + "-end"), []); +const _f = { left: "right", right: "left", bottom: "top", top: "bottom" }; +function Bs(e) { + return e.replace(/left|right|bottom|top/g, (n) => _f[n]); +} +function bf(e, n, t) { + t === void 0 && (t = !1); + const s = fs(e), i = Gi(e), o = Go(i); + let r = i === "x" ? s === (t ? "end" : "start") ? "right" : "left" : s === "start" ? "bottom" : "top"; + return n.reference[o] > n.floating[o] && (r = Bs(r)), { main: r, cross: Bs(r) }; +} +const wf = { start: "end", end: "start" }; +function io(e) { + return e.replace(/start|end/g, (n) => wf[n]); +} +const vf = function(e) { + return e === void 0 && (e = {}), { name: "flip", options: e, async fn(n) { + var t; + const { placement: s, middlewareData: i, rects: o, initialPlacement: r, platform: l, elements: a } = n, { mainAxis: h = !0, crossAxis: c = !0, fallbackPlacements: u, fallbackStrategy: d = "bestFit", fallbackAxisSideDirection: f = "none", flipAlignment: p = !0, ...g } = e, y = Oe(s), _ = Oe(r) === r, v = await (l.isRTL == null ? void 0 : l.isRTL(a.floating)), S = u || (_ || !p ? [Bs(r)] : function(j) { + const P = Bs(j); + return [io(j), P, io(P)]; + }(r)); + u || f === "none" || S.push(...function(j, P, V, F) { + const G = fs(j); + let I = function(K, bt, de) { + const pe = ["left", "right"], me = ["right", "left"], Lt = ["top", "bottom"], Ne = ["bottom", "top"]; + switch (K) { + case "top": + case "bottom": + return de ? bt ? me : pe : bt ? pe : me; + case "left": + case "right": + return bt ? Lt : Ne; + default: + return []; + } + }(Oe(j), V === "start", F); + return G && (I = I.map((K) => K + "-" + G), P && (I = I.concat(I.map(io)))), I; + }(r, p, f, v)); + const $ = [r, ...S], T = await ff(n, g), D = []; + let L = ((t = i.flip) == null ? void 0 : t.overflows) || []; + if (h && D.push(T[y]), c) { + const { main: j, cross: P } = bf(s, o, v); + D.push(T[j], T[P]); + } + if (L = [...L, { placement: s, overflows: D }], !D.every((j) => j <= 0)) { + var O; + const j = (((O = i.flip) == null ? void 0 : O.index) || 0) + 1, P = $[j]; + if (P) + return { data: { index: j, overflows: L }, reset: { placement: P } }; + let V = "bottom"; + switch (d) { + case "bestFit": { + var k; + const F = (k = L.map((G) => [G, G.overflows.filter((I) => I > 0).reduce((I, K) => I + K, 0)]).sort((G, I) => G[1] - I[1])[0]) == null ? void 0 : k[0].placement; + F && (V = F); + break; + } + case "initialPlacement": + V = r; + } + if (s !== V) + return { reset: { placement: V } }; + } + return {}; + } }; +}, xf = function(e) { + return e === void 0 && (e = 0), { name: "offset", options: e, async fn(n) { + const { x: t, y: s } = n, i = await async function(o, r) { + const { placement: l, platform: a, elements: h } = o, c = await (a.isRTL == null ? void 0 : a.isRTL(h.floating)), u = Oe(l), d = fs(l), f = Gi(l) === "x", p = ["left", "top"].includes(u) ? -1 : 1, g = c && f ? -1 : 1, y = typeof r == "function" ? r(o) : r; + let { mainAxis: _, crossAxis: v, alignmentAxis: S } = typeof y == "number" ? { mainAxis: y, crossAxis: 0, alignmentAxis: null } : { mainAxis: 0, crossAxis: 0, alignmentAxis: null, ...y }; + return d && typeof S == "number" && (v = d === "end" ? -1 * S : S), f ? { x: v * g, y: _ * p } : { x: _ * p, y: v * g }; + }(n, e); + return { x: t + i.x, y: s + i.y, data: i }; + } }; +}; +function pt(e) { + var n; + return ((n = e.ownerDocument) == null ? void 0 : n.defaultView) || window; +} +function Rt(e) { + return pt(e).getComputedStyle(e); +} +function ue(e) { + return Vc(e) ? (e.nodeName || "").toLowerCase() : ""; +} +let _s; +function Uc() { + if (_s) + return _s; + const e = navigator.userAgentData; + return e && Array.isArray(e.brands) ? (_s = e.brands.map((n) => n.brand + "/" + n.version).join(" "), _s) : navigator.userAgent; +} +function Gt(e) { + return e instanceof pt(e).HTMLElement; +} +function _t(e) { + return e instanceof pt(e).Element; +} +function Vc(e) { + return e instanceof pt(e).Node; +} +function Yr(e) { + return typeof ShadowRoot > "u" ? !1 : e instanceof pt(e).ShadowRoot || e instanceof ShadowRoot; +} +function Ki(e) { + const { overflow: n, overflowX: t, overflowY: s, display: i } = Rt(e); + return /auto|scroll|overlay|hidden|clip/.test(n + s + t) && !["inline", "contents"].includes(i); +} +function Sf(e) { + return ["table", "td", "th"].includes(ue(e)); +} +function Co(e) { + const n = /firefox/i.test(Uc()), t = Rt(e), s = t.backdropFilter || t.WebkitBackdropFilter; + return t.transform !== "none" || t.perspective !== "none" || !!s && s !== "none" || n && t.willChange === "filter" || n && !!t.filter && t.filter !== "none" || ["transform", "perspective"].some((i) => t.willChange.includes(i)) || ["paint", "layout", "strict", "content"].some((i) => { + const o = t.contain; + return o != null && o.includes(i); + }); +} +function qc() { + return !/^((?!chrome|android).)*safari/i.test(Uc()); +} +function Ko(e) { + return ["html", "body", "#document"].includes(ue(e)); +} +const Xr = Math.min, $n = Math.max, zs = Math.round; +function Gc(e) { + const n = Rt(e); + let t = parseFloat(n.width), s = parseFloat(n.height); + const i = e.offsetWidth, o = e.offsetHeight, r = zs(t) !== i || zs(s) !== o; + return r && (t = i, s = o), { width: t, height: s, fallback: r }; +} +function Kc(e) { + return _t(e) ? e : e.contextElement; +} +const Yc = { x: 1, y: 1 }; +function Pe(e) { + const n = Kc(e); + if (!Gt(n)) + return Yc; + const t = n.getBoundingClientRect(), { width: s, height: i, fallback: o } = Gc(n); + let r = (o ? zs(t.width) : t.width) / s, l = (o ? zs(t.height) : t.height) / i; + return r && Number.isFinite(r) || (r = 1), l && Number.isFinite(l) || (l = 1), { x: r, y: l }; +} +function ke(e, n, t, s) { + var i, o; + n === void 0 && (n = !1), t === void 0 && (t = !1); + const r = e.getBoundingClientRect(), l = Kc(e); + let a = Yc; + n && (s ? _t(s) && (a = Pe(s)) : a = Pe(e)); + const h = l ? pt(l) : window, c = !qc() && t; + let u = (r.left + (c && ((i = h.visualViewport) == null ? void 0 : i.offsetLeft) || 0)) / a.x, d = (r.top + (c && ((o = h.visualViewport) == null ? void 0 : o.offsetTop) || 0)) / a.y, f = r.width / a.x, p = r.height / a.y; + if (l) { + const g = pt(l), y = s && _t(s) ? pt(s) : s; + let _ = g.frameElement; + for (; _ && s && y !== g; ) { + const v = Pe(_), S = _.getBoundingClientRect(), $ = getComputedStyle(_); + S.x += (_.clientLeft + parseFloat($.paddingLeft)) * v.x, S.y += (_.clientTop + parseFloat($.paddingTop)) * v.y, u *= v.x, d *= v.y, f *= v.x, p *= v.y, u += S.x, d += S.y, _ = pt(_).frameElement; + } + } + return { width: f, height: p, top: d, right: u + f, bottom: d + p, left: u, x: u, y: d }; +} +function le(e) { + return ((Vc(e) ? e.ownerDocument : e.document) || window.document).documentElement; +} +function Yi(e) { + return _t(e) ? { scrollLeft: e.scrollLeft, scrollTop: e.scrollTop } : { scrollLeft: e.pageXOffset, scrollTop: e.pageYOffset }; +} +function Xc(e) { + return ke(le(e)).left + Yi(e).scrollLeft; +} +function Ef(e, n, t) { + const s = Gt(n), i = le(n), o = ke(e, !0, t === "fixed", n); + let r = { scrollLeft: 0, scrollTop: 0 }; + const l = { x: 0, y: 0 }; + if (s || !s && t !== "fixed") + if ((ue(n) !== "body" || Ki(i)) && (r = Yi(n)), Gt(n)) { + const a = ke(n, !0); + l.x = a.x + n.clientLeft, l.y = a.y + n.clientTop; + } else + i && (l.x = Xc(i)); + return { x: o.left + r.scrollLeft - l.x, y: o.top + r.scrollTop - l.y, width: o.width, height: o.height }; +} +function On(e) { + if (ue(e) === "html") + return e; + const n = e.assignedSlot || e.parentNode || (Yr(e) ? e.host : null) || le(e); + return Yr(n) ? n.host : n; +} +function Jr(e) { + return Gt(e) && Rt(e).position !== "fixed" ? e.offsetParent : null; +} +function Qr(e) { + const n = pt(e); + let t = Jr(e); + for (; t && Sf(t) && Rt(t).position === "static"; ) + t = Jr(t); + return t && (ue(t) === "html" || ue(t) === "body" && Rt(t).position === "static" && !Co(t)) ? n : t || function(s) { + let i = On(s); + for (; Gt(i) && !Ko(i); ) { + if (Co(i)) + return i; + i = On(i); + } + return null; + }(e) || n; +} +function Jc(e) { + const n = On(e); + return Ko(n) ? e.ownerDocument.body : Gt(n) && Ki(n) ? n : Jc(n); +} +function Rn(e, n) { + var t; + n === void 0 && (n = []); + const s = Jc(e), i = s === ((t = e.ownerDocument) == null ? void 0 : t.body), o = pt(s); + return i ? n.concat(o, o.visualViewport || [], Ki(s) ? s : []) : n.concat(s, Rn(s)); +} +function Zr(e, n, t) { + return n === "viewport" ? Fs(function(s, i) { + const o = pt(s), r = le(s), l = o.visualViewport; + let a = r.clientWidth, h = r.clientHeight, c = 0, u = 0; + if (l) { + a = l.width, h = l.height; + const d = qc(); + (d || !d && i === "fixed") && (c = l.offsetLeft, u = l.offsetTop); + } + return { width: a, height: h, x: c, y: u }; + }(e, t)) : _t(n) ? function(s, i) { + const o = ke(s, !0, i === "fixed"), r = o.top + s.clientTop, l = o.left + s.clientLeft, a = Gt(s) ? Pe(s) : { x: 1, y: 1 }, h = s.clientWidth * a.x, c = s.clientHeight * a.y, u = l * a.x, d = r * a.y; + return { top: d, left: u, right: u + h, bottom: d + c, x: u, y: d, width: h, height: c }; + }(n, t) : Fs(function(s) { + var i; + const o = le(s), r = Yi(s), l = (i = s.ownerDocument) == null ? void 0 : i.body, a = $n(o.scrollWidth, o.clientWidth, l ? l.scrollWidth : 0, l ? l.clientWidth : 0), h = $n(o.scrollHeight, o.clientHeight, l ? l.scrollHeight : 0, l ? l.clientHeight : 0); + let c = -r.scrollLeft + Xc(s); + const u = -r.scrollTop; + return Rt(l || o).direction === "rtl" && (c += $n(o.clientWidth, l ? l.clientWidth : 0) - a), { width: a, height: h, x: c, y: u }; + }(le(e))); +} +const Cf = { getClippingRect: function(e) { + let { element: n, boundary: t, rootBoundary: s, strategy: i } = e; + const o = t === "clippingAncestors" ? function(h, c) { + const u = c.get(h); + if (u) + return u; + let d = Rn(h).filter((y) => _t(y) && ue(y) !== "body"), f = null; + const p = Rt(h).position === "fixed"; + let g = p ? On(h) : h; + for (; _t(g) && !Ko(g); ) { + const y = Rt(g), _ = Co(g); + (p ? _ || f : _ || y.position !== "static" || !f || !["absolute", "fixed"].includes(f.position)) ? f = y : d = d.filter((v) => v !== g), g = On(g); + } + return c.set(h, d), d; + }(n, this._c) : [].concat(t), r = [...o, s], l = r[0], a = r.reduce((h, c) => { + const u = Zr(n, c, i); + return h.top = $n(u.top, h.top), h.right = Xr(u.right, h.right), h.bottom = Xr(u.bottom, h.bottom), h.left = $n(u.left, h.left), h; + }, Zr(n, l, i)); + return { width: a.right - a.left, height: a.bottom - a.top, x: a.left, y: a.top }; +}, convertOffsetParentRelativeRectToViewportRelativeRect: function(e) { + let { rect: n, offsetParent: t, strategy: s } = e; + const i = Gt(t), o = le(t); + if (t === o) + return n; + let r = { scrollLeft: 0, scrollTop: 0 }, l = { x: 1, y: 1 }; + const a = { x: 0, y: 0 }; + if ((i || !i && s !== "fixed") && ((ue(t) !== "body" || Ki(o)) && (r = Yi(t)), Gt(t))) { + const h = ke(t); + l = Pe(t), a.x = h.x + t.clientLeft, a.y = h.y + t.clientTop; + } + return { width: n.width * l.x, height: n.height * l.y, x: n.x * l.x - r.scrollLeft * l.x + a.x, y: n.y * l.y - r.scrollTop * l.y + a.y }; +}, isElement: _t, getDimensions: function(e) { + return Gc(e); +}, getOffsetParent: Qr, getDocumentElement: le, getScale: Pe, async getElementRects(e) { + let { reference: n, floating: t, strategy: s } = e; + const i = this.getOffsetParent || Qr, o = this.getDimensions; + return { reference: Ef(n, await i(t), s), floating: { x: 0, y: 0, ...await o(t) } }; +}, getClientRects: (e) => Array.from(e.getClientRects()), isRTL: (e) => Rt(e).direction === "rtl" }; +function $f(e, n, t, s) { + s === void 0 && (s = {}); + const { ancestorScroll: i = !0, ancestorResize: o = !0, elementResize: r = !0, animationFrame: l = !1 } = s, a = i && !l, h = a || o ? [..._t(e) ? Rn(e) : e.contextElement ? Rn(e.contextElement) : [], ...Rn(n)] : []; + h.forEach((f) => { + a && f.addEventListener("scroll", t, { passive: !0 }), o && f.addEventListener("resize", t); + }); + let c, u = null; + if (r) { + let f = !0; + u = new ResizeObserver(() => { + f || t(), f = !1; + }), _t(e) && !l && u.observe(e), _t(e) || !e.contextElement || l || u.observe(e.contextElement), u.observe(n); + } + let d = l ? ke(e) : null; + return l && function f() { + const p = ke(e); + !d || p.x === d.x && p.y === d.y && p.width === d.width && p.height === d.height || t(), d = p, c = requestAnimationFrame(f); + }(), t(), () => { + var f; + h.forEach((p) => { + a && p.removeEventListener("scroll", t), o && p.removeEventListener("resize", t); + }), (f = u) == null || f.disconnect(), u = null, l && cancelAnimationFrame(c); + }; +} +const Rf = (e, n, t) => { + const s = /* @__PURE__ */ new Map(), i = { platform: Cf, ...t }, o = { ...i.platform, _c: s }; + return hf(e, n, { ...i, platform: o }); +}; +var Je, Qe, Ze, xe, et, pi, Zn, ts, $o, mi, Qc, gi, Zc, yi, ta, _i, ea, bi, na, wi, sa, vi, ia, tn, xi, oa; +const _e = class extends kt { + constructor() { + super(...arguments); + x(this, ts); + x(this, mi); + x(this, gi); + x(this, yi); + x(this, _i); + x(this, bi); + x(this, wi); + x(this, vi); + x(this, xi); + x(this, Je, !1); + x(this, Qe, void 0); + x(this, Ze, 0); + x(this, xe, void 0); + x(this, et, void 0); + x(this, pi, void 0); + x(this, Zn, void 0); + w(this, "hideLater", () => { + m(this, tn).call(this), R(this, Ze, window.setTimeout(this.hide.bind(this), 100)); + }); + x(this, tn, () => { + clearTimeout(m(this, Ze)), R(this, Ze, 0); + }); + } + get isShown() { + var t; + return (t = m(this, xe)) == null ? void 0 : t.classList.contains(_e.CLASS_SHOW); + } + get tooltip() { + return m(this, xe) || N(this, gi, Zc).call(this); + } + get trigger() { + return m(this, pi) || this.element; + } + get isHover() { + return this.options.trigger === "hover"; + } + get elementShowClass() { + return `with-${_e.NAME}-show`; + } + get isDynamic() { + return this.options.title; + } + init() { + const { element: t } = this; + t !== document.body && !t.hasAttribute("data-toggle") && t.setAttribute("data-toggle", "tooltip"); + } + show(t) { + return this.setOptions(t), !m(this, Je) && this.isHover && N(this, xi, oa).call(this), this.options.animation && this.tooltip.classList.add("fade"), this.element.classList.add(this.elementShowClass), this.tooltip.classList.add(_e.CLASS_SHOW), N(this, wi, sa).call(this), !0; + } + hide() { + var t, s; + return (t = m(this, Zn)) == null || t.call(this), this.element.classList.remove(this.elementShowClass), (s = m(this, xe)) == null || s.classList.remove(_e.CLASS_SHOW), !0; + } + toggle(t) { + return this.isShown ? this.hide() : this.show(t); + } + destroy() { + m(this, Je) && (this.element.removeEventListener("mouseleave", this.hideLater), this.tooltip.removeEventListener("mouseenter", m(this, tn)), this.tooltip.removeEventListener("mouseleave", this.hideLater)), super.destroy(); + } + static clear(t) { + t instanceof Event && (t = { event: t }); + const { exclude: s } = t || {}, i = this.getAll().entries(), o = new Set(s || []); + for (const [r, l] of i) + o.has(r) || l.hide(); + } +}; +let ht = _e; +Je = new WeakMap(), Qe = new WeakMap(), Ze = new WeakMap(), xe = new WeakMap(), et = new WeakMap(), pi = new WeakMap(), Zn = new WeakMap(), ts = new WeakSet(), $o = function() { + const { arrow: t } = this.options; + return typeof t == "number" ? t : 8; +}, mi = new WeakSet(), Qc = function() { + const t = N(this, ts, $o).call(this); + return R(this, et, document.createElement("div")), m(this, et).style.position = this.options.strategy, m(this, et).style.width = `${t}px`, m(this, et).style.height = `${t}px`, m(this, et).style.transform = "rotate(45deg)", m(this, et); +}, gi = new WeakSet(), Zc = function() { + var i; + const t = _e.TOOLTIP_CLASS; + let s; + if (this.isDynamic) { + s = document.createElement("div"); + const o = this.options.className ? this.options.className.split(" ") : []; + let r = [t, this.options.type || ""]; + r = r.concat(o), s.classList.add(...r), s[this.options.html ? "innerHTML" : "innerText"] = this.options.title || ""; + } else if (this.element) { + const o = this.element.getAttribute("href") ?? this.element.dataset.target; + if (o != null && o.startsWith("#") && (s = document.querySelector(o)), !s) { + const r = this.element.nextElementSibling; + r != null && r.classList.contains(t) ? s = r : s = (i = this.element.parentNode) == null ? void 0 : i.querySelector(`.${t}`); + } + } + if (this.options.arrow && (s == null || s.append(N(this, mi, Qc).call(this))), !s) + throw new Error("Tooltip: Cannot find tooltip element"); + return s.style.width = "max-content", s.style.position = "absolute", s.style.top = "0", s.style.left = "0", document.body.appendChild(s), R(this, xe, s), s; +}, yi = new WeakSet(), ta = function() { + var r; + const t = N(this, ts, $o).call(this), { strategy: s, placement: i } = this.options, o = { + middleware: [xf(t), vf()], + strategy: s, + placement: i + }; + return this.options.arrow && m(this, et) && ((r = o.middleware) == null || r.push(gf({ element: m(this, et) }))), o; +}, _i = new WeakSet(), ea = function(t) { + return { + top: "bottom", + right: "left", + bottom: "top", + left: "right" + }[t]; +}, bi = new WeakSet(), na = function(t) { + return t === "bottom" ? { + borderBottomStyle: "none", + borderRightStyle: "none" + } : t === "top" ? { + borderTopStyle: "none", + borderLeftStyle: "none" + } : t === "left" ? { + borderBottomStyle: "none", + borderLeftStyle: "none" + } : { + borderTopStyle: "none", + borderRightStyle: "none" + }; +}, wi = new WeakSet(), sa = function() { + const t = N(this, yi, ta).call(this), s = N(this, vi, ia).call(this); + R(this, Zn, $f(s, this.tooltip, () => { + Rf(s, this.tooltip, t).then(({ x: i, y: o, middlewareData: r, placement: l }) => { + Object.assign(this.tooltip.style, { + left: `${i}px`, + top: `${o}px` + }); + const a = l.split("-")[0], h = N(this, _i, ea).call(this, a); + if (r.arrow && m(this, et)) { + const { x: c, y: u } = r.arrow; + Object.assign(m(this, et).style, { + left: c != null ? `${c}px` : "", + top: u != null ? `${u}px` : "", + [h]: `${-m(this, et).offsetWidth / 2}px`, + background: "inherit", + border: "inherit", + ...N(this, bi, na).call(this, a) + }); + } + }); + })); +}, vi = new WeakSet(), ia = function() { + return m(this, Qe) || R(this, Qe, { + getBoundingClientRect: () => { + const { element: t } = this; + if (t instanceof MouseEvent) { + const { clientX: s, clientY: i } = t; + return { + width: 0, + height: 0, + top: i, + right: s, + bottom: i, + left: s + }; + } + return t instanceof HTMLElement ? t.getBoundingClientRect() : t; + }, + contextElement: this.element + }), m(this, Qe); +}, tn = new WeakMap(), xi = new WeakSet(), oa = function() { + const { tooltip: t } = this; + t.addEventListener("mouseenter", m(this, tn)), t.addEventListener("mouseleave", this.hideLater), this.element.addEventListener("mouseleave", this.hideLater), R(this, Je, !0); +}, w(ht, "NAME", "tooltip"), w(ht, "TOOLTIP_CLASS", "tooltip"), w(ht, "CLASS_SHOW", "show"), w(ht, "MENU_SELECTOR", '[data-toggle="tooltip"]:not(.disabled):not(:disabled)'), w(ht, "DEFAULT", { + animation: !0, + placement: "top", + strategy: "absolute", + trigger: "hover", + type: "darker", + arrow: !0 +}); +document.addEventListener("click", function(e) { + var s; + const n = e.target, t = (s = n.closest) == null ? void 0 : s.call(n, ht.MENU_SELECTOR); + if (t) { + const i = ht.ensure(t); + i.options.trigger === "click" && i.toggle(); + } else + ht.clear({ event: e }); +}); +document.addEventListener("mouseover", function(e) { + var i; + const n = e.target, t = (i = n.closest) == null ? void 0 : i.call(n, ht.MENU_SELECTOR); + if (!t) + return; + const s = ht.ensure(t); + s.isHover && s.show(); +}); +let kf = class extends U { + constructor() { + super(...arguments); + w(this, "handleItemClick", (t) => { + const { onClickItem: s, changeActiveKey: i } = this.props; + s && s(t); + const { item: o } = t; + o.items || i && i(o.key); + }); + } + render() { + const { items: t, activeClass: s, activeIcon: i, activeKey: o, defaultNestedShow: r = !0, isDropdownMenu: l = !1, ...a } = this.props; + return /* @__PURE__ */ E( + oe, + { + className: l ? "dropdown-menu" : "", + items: t, + activeClass: s, + activeKey: o, + activeIcon: i, + onClickItem: this.handleItemClick, + defaultNestedShow: r, + ...a + } + ); + } +}; +class tl extends J { +} +w(tl, "NAME", "MenuTree"), w(tl, "Component", kf); +var ut; +class _n extends kt { + constructor() { + super(...arguments); + x(this, ut, void 0); + } + init() { + const { element: t } = this; + t !== document.body && !t.hasAttribute("data-toggle") && t.setAttribute("data-toggle", "tab"); + } + showTarget() { + const t = this.element.getAttribute("href") || this.element.dataset.target || this.element.dataset.tab; + t != null && t.startsWith("#") && R(this, ut, document.querySelector(t)), this.addActive(this.element.closest(`.${this.constructor.NAV_CLASS}`), this.element.parentElement), m(this, ut) && (this.addActive(m(this, ut).parentElement, m(this, ut)), m(this, ut).dispatchEvent(new CustomEvent("show.zui3.tab"))); + } + show() { + const t = this.element.getAttribute("href") || this.element.dataset.target || this.element.dataset.tab; + t != null && t.startsWith("#") && R(this, ut, document.querySelector(t)), m(this, ut) && (this.addActive(m(this, ut).parentElement, m(this, ut)), this.addActive(this.element.closest(`.${this.constructor.NAV_CLASS}`), this.element.parentElement)); + } + addActive(t, s) { + const i = t.children; + Array.from(i).forEach((r) => { + r.classList.remove("active"), r.classList.contains("fade") && r.classList.remove("in"); + }), s.classList.add("active"), s.classList.contains("fade") && this.transition(s).then(function() { + s.dispatchEvent(new CustomEvent("shown.zui3.tab")); + }); + } + transition(t) { + return new Promise(function(s) { + setTimeout(() => { + t.classList.add("in"), s(); + }, 100); + }); + } +} +ut = new WeakMap(), w(_n, "NAME", "NavTabs"), w(_n, "NAV_CLASS", "nav-tabs"), w(_n, "EVENTS", !0), w(_n, "TOGGLE_SELECTOR", '[data-toggle="tab"]'); +document.addEventListener("click", (e) => { + e.target instanceof HTMLElement && (e.target.dataset.toggle === "tab" || e.target.getAttribute("data-tab")) && (e.preventDefault(), new _n(e.target).showTarget()); +}); +class Tf extends U { + constructor(t) { + super(t); + w(this, "handleChange", (t) => { + this.setState({ activeKey: t }); + }); + this.state = { + activeKey: t.activeKey ?? t.items[0].key + }; + } + render() { + const { items: t, className: s, contentClass: i } = this.props, { activeKey: o } = this.state; + return /* @__PURE__ */ b("div", { className: M("zui-tabs", s), children: [ + /* @__PURE__ */ b("ul", { className: "-flex -items-center", children: t.map(({ key: r, label: l, labelCount: a }) => /* @__PURE__ */ b("li", { className: M("-flex -items-center -gap-3", { active: o === r }), children: /* @__PURE__ */ b("a", { className: "-flex -h-8 -items-center -justify-center -gap-1 -px-4 -text-inherit", onClick: () => this.handleChange(r), children: [ + /* @__PURE__ */ b("span", { className: M({ "text-primary": o === r }), children: l }), + o === r ? /* @__PURE__ */ b("span", { className: "label circle gray", children: a }) : null + ] }) }, r)) }), + t.map((r) => { + const { key: l, content: a, isElm: h } = r; + return h ? /* @__PURE__ */ b( + "div", + { + dangerouslySetInnerHTML: { __html: a }, + className: M("-px-3", "-py-2", { "-hidden": o !== l }) + }, + l + ) : /* @__PURE__ */ b("div", { className: M(i, { "-hidden": o !== l }), children: a }, l); + }) + ] }); + } +} +class Af extends U { + constructor(t) { + super(t); + w(this, "handleChange", (t) => { + const s = t.target.value; + this.setState({ value: s }); + const { onChange: i } = this.props; + i && i(s); + }); + w(this, "handleClear", () => { + this.setState({ value: "" }); + const { onChange: t } = this.props; + t && t(""); + }); + this.state = { + value: t.defaultValue ?? "" + }; + } + render() { + const { type: t = "text", icon: s } = this.props, { value: i } = this.state, o = s ? /* @__PURE__ */ b("label", { className: "input-control-prefix", children: /* @__PURE__ */ b("i", { className: `icon icon-${s}` }) }) : null; + return /* @__PURE__ */ b("div", { className: "zui-input input-control has-prefix-icon", children: [ + o, + /* @__PURE__ */ b("input", { className: "form-control", type: t, value: i, onChange: this.handleChange }), + /* @__PURE__ */ b("span", { className: M("-absolute -w-8 -h-8 -right-0 -top-0 -flex -justify-center -items-center -cursor-pointer", { "-hidden": !i }), onClick: this.handleClear, children: /* @__PURE__ */ b("i", { className: "icon icon-close" }) }) + ] }); + } +} +var ho; +let Nf = (ho = class extends U { + constructor(t) { + super(t); + w(this, "handleChange", (t) => { + const { collapse: s } = this.state; + this.setState({ + searchValue: t, + collapse: !!t || s + }); + }); + w(this, "acount", (t) => { + let s = 0; + return t.forEach((i) => { + var o; + s += ((o = i.items) == null ? void 0 : o.length) || 0; + }), s; + }); + w(this, "filter", (t) => { + const s = [], { searchValue: i } = this.state; + return t.forEach((o) => { + const r = o.items.filter((l) => l.text.includes(i)); + r.length > 0 && s.push({ ...o, items: r }); + }), s; + }); + this.state = { + collapse: !0, + searchValue: "" + }; + } + render() { + const { involved: t, others: s, finished: i, involvedText: o, othersText: r, finishedBtnText: l, finishedText: a } = this.props, { collapse: h, searchValue: c } = this.state; + return /* @__PURE__ */ E("div", { className: "quick-menu", style: { width: h ? 250 : 500 } }, /* @__PURE__ */ E("div", { className: "-p-2" }, /* @__PURE__ */ E(Af, { onChange: this.handleChange, icon: "search" })), /* @__PURE__ */ E("main", { className: "-flex" }, /* @__PURE__ */ E("div", { className: "-flex -max-h-[350px] -flex-col -pl-2 -py-2", style: { flexBasis: h ? "100%" : "50%" } }, /* @__PURE__ */ E( + Tf, + { + className: "-flex -flex-col -max-h-full -overflow-hidden -grow", + contentClass: "-grow -overflow-y-scroll", + activeKey: 1, + items: [ + { + key: 1, + label: o, + labelCount: this.acount(t), + content: /* @__PURE__ */ E(oe, { defaultNestedShow: !0, items: c ? this.filter(t) : t }) + }, + { + key: 2, + label: r, + labelCount: this.acount(s), + content: /* @__PURE__ */ E(oe, { defaultNestedShow: !0, items: c ? this.filter(s) : s }) + } + ] + } + ), /* @__PURE__ */ E( + "div", + { + onClick: () => this.setState({ collapse: !h }), + className: `-py-2 -pr-2 -flex -justify-end -items-center -cursor-pointer ${c ? "-hidden" : ""}` + }, + /* @__PURE__ */ E("span", null, l), + /* @__PURE__ */ E("i", { className: `icon ${h ? "icon-angle-right" : "icon-angle-left"}` }) + )), h || c ? null : /* @__PURE__ */ E("div", { className: "-basis-1/2 -max-h-[350px] -overflow-y-auto -border-l-[1px] -border-solid -border-slate-200" }, /* @__PURE__ */ E(oe, { defaultNestedShow: !0, items: i }))), c ? /* @__PURE__ */ E("div", { className: "-max-h-[350px] -overflow-y-auto" }, /* @__PURE__ */ E("span", { className: "label gray size-lg -ml-2" }, a), /* @__PURE__ */ E(oe, { defaultNestedShow: !0, items: this.filter(i) })) : null); + } +}, w(ho, "NAME", "zui.searchForm"), ho); +class el extends J { +} +w(el, "NAME", "QuickMenu"), w(el, "Component", Nf); +const Lf = ({ + formConfig: e, + className: n, + fields: t, + operators: s, + savedQuery: i, + andOr: o, + formSession: r, + searchBtnText: l, + resetBtnText: a, + saveSearch: h, + savedQueryTitle: c, + onApplyQuery: u, + onDeleteQuery: d, + groupName: f, + handleSelect: p, + toggleMore: g, + toggleHistory: y, + resetForm: _, + submitForm: v, + actionURL: S, + module: $, + groupItems: T +}) => { + const L = [n, ...["search-form"]], O = [1, 2, 3], k = r ? r.groupAndOr : "", j = (P) => { + const V = r ? r[`andOr${P}`] : ""; + return /* @__PURE__ */ E("div", { class: [1, 4].includes(P) ? "search-group" : "search-group hidden", "data-id": P }, /* @__PURE__ */ E("div", { class: "group-name" }, [1, 4].includes(P) ? P === 1 ? f[0] : f[1] : /* @__PURE__ */ E("select", { class: "form-control", id: `andOr${P}`, name: `andOr${P}` }, o.map((F) => /* @__PURE__ */ E("option", { value: F.value, selected: V === F.value, title: F.value }, F.title)))), /* @__PURE__ */ E("div", { class: "group-select" }, /* @__PURE__ */ E("select", { class: "form-control field-select", id: `field${P}`, name: `field${P}`, onChange: p.bind(void 0) }, " ", t == null ? void 0 : t.map((F) => /* @__PURE__ */ E("option", { value: F.name, selected: !1, title: F.name, control: F.control }, F.label)))), /* @__PURE__ */ E("div", { class: "group-select" }, /* @__PURE__ */ E("select", { class: "form-control search-method", id: `operator${P}`, name: `operator${P}` }, s.map((F) => /* @__PURE__ */ E("option", { key: F.value, value: F.value, title: F.value }, F.title)))), /* @__PURE__ */ E("div", { class: "group-value" }, /* @__PURE__ */ E("input", { type: "text", class: "form-control value-input", value: t[P - 1].defaultValue, placeholder: t[P - 1].placeholder }), /* @__PURE__ */ E("select", { class: "form-control value-select hidden" }), /* @__PURE__ */ E("input", { type: "datetime-local", class: "form-control value-date hidden" }))); + }; + return /* @__PURE__ */ E( + "form", + { + id: "searchForm", + className: M(L), + ...e + }, + /* @__PURE__ */ E("div", { class: "search-form-content" }, /* @__PURE__ */ E("div", { class: "search-form-items" }, /* @__PURE__ */ E("div", { class: "search-col" }, O.map((P) => j(P))), /* @__PURE__ */ E("div", { class: "search-col" }, /* @__PURE__ */ E("select", { class: "form-control", id: "groupAndOr", name: "groupAndOr" }, o.map((P) => /* @__PURE__ */ E("option", { value: P.value, selected: k === P.value, title: P.value }, P.title)))), /* @__PURE__ */ E("div", { class: "search-col" }, O.map((P) => j(P + 3)))), /* @__PURE__ */ E("div", { class: "search-form-footer" }, /* @__PURE__ */ E("div", { class: "inline-block flex items-center justify-center" }, /* @__PURE__ */ E("button", { class: "btn primary btn-submit-form", type: "button", onClick: v }, l || "搜索"), /* @__PURE__ */ E("button", { class: "btn btn-reset-form", type: "button", onClick: _ }, a || "重置")), /* @__PURE__ */ E("div", { class: "save-bar" }, (h == null ? void 0 : h.hasPriv) && /* @__PURE__ */ E("a", { class: "btn save-query", ...h.config }, /* @__PURE__ */ E("i", { class: "icon icon-save" }), h.text || "保存搜索条件"), /* @__PURE__ */ E("a", { class: "btn toggle-more", onClick: g }, /* @__PURE__ */ E("i", { class: "icon icon-chevron-double-down" }))))), + /* @__PURE__ */ E("div", null, /* @__PURE__ */ E("button", { class: "btn search-toggle-btn", type: "button", onClick: y }, /* @__PURE__ */ E("i", { class: "icon icon-angle-left" }))), + /* @__PURE__ */ E("div", { class: "history-record hidden" }, /* @__PURE__ */ E("p", null, c), /* @__PURE__ */ E("div", { class: "labels" }, (i == null ? void 0 : i.length) && i.map((P) => { + if (P) + return /* @__PURE__ */ E("div", { class: "label-btn", "data-id": P.id }, /* @__PURE__ */ E("span", { class: "label lighter-pale bd-lighter", onClick: (V) => u(V, Number(P.id)) }, P.title, " ", P.hasPriv ? /* @__PURE__ */ E("i", { onClick: (V) => d(V, Number(P.id)), class: "icon icon-close" }) : "")); + }))), + S ? /* @__PURE__ */ E("input", { type: "hidden", name: "actionURL", value: S }) : "", + $ ? /* @__PURE__ */ E("input", { type: "hidden", name: "module", value: $ }) : "", + T ? /* @__PURE__ */ E("input", { type: "hidden", name: "groupItems", value: T }) : "" + ); +}; +var zt; +let Mf = (zt = class extends U { + componentDidMount() { + this.initForm(); + } + initForm() { + const { formSession: n } = this.props; + this.base.querySelectorAll(".search-form-content .search-group").forEach((s, i) => { + let o = {}; + const r = s.querySelector(".field-select"); + r && (r.value = (n ? n[r.id] : null) || this.props.fields[i].name, this.props.fields.forEach((a) => { + a.name == r.value && (o = JSON.parse(JSON.stringify(a))); + })), o.defaultValue = n ? n["value" + (i + 1)] : ""; + const l = s.querySelector(".search-method"); + l && (l.value = (n ? n[l.id] : null) || this.props.fields[i].operator || ""), this.toggleElement(s, o); + }); + } + toggleAttr(n, t) { + if (!n.classList.contains("hidden")) { + n.setAttribute("name", t), n.setAttribute("id", t); + return; + } + n.removeAttribute("name"), n.removeAttribute("id"); + } + toggleElement(n, t) { + const s = n.querySelector(".value-select"), i = n.querySelector(".value-input"), o = n.querySelector(".value-date"), r = n.querySelector(".search-method"); + if (t.operator, t.control === "select" && (s.innerHTML = "", t.values)) { + for (const c in t.values) { + const u = document.createElement("option"); + u.value = c, u.setAttribute("value", c), u.innerHTML = t.values[c], s.appendChild(u); + } + s.value = t.defaultValue || ""; + } + s.classList.toggle("hidden", t.control !== "select"), i.classList.toggle("hidden", t.control !== "input"), o == null || o.classList.toggle("hidden", t.control !== "date"), i.classList.contains("hidden") || (i.value = t.defaultValue || "", i.placeholder = t.placeholder || ""), o && !o.classList.contains("hidden") && (o.value = t.defaultValue || ""); + const l = n.dataset.id, a = n.querySelector(".group-value"); + if (!a) + return; + a.childNodes.forEach((c) => { + this.toggleAttr(c, `value${l}`); + }); + } + handleSelect(n) { + if (!n || !n.target) + return; + const t = n.target, i = this.props.fields.filter((r) => r.name === t.value)[0], o = t.closest(".search-group"); + this.toggleElement(o, i); + } + toggleElementDisplay(n, t, s, i) { + const o = t.classList.contains("hidden"), r = n.querySelector(".icon"); + r == null || r.classList.toggle(s, o), r == null || r.classList.toggle(i, !o); + } + toggleMore(n) { + if (!(n != null && n.target)) + return; + const t = n.target, i = t.closest(".search-form-content").querySelectorAll(".search-col .search-group + .search-group"); + i.forEach((o) => { + o.classList.toggle("hidden", !o.classList.contains("hidden")); + }), this.toggleElementDisplay(t, i[0], "icon-chevron-double-down", "icon-chevron-double-up"); + } + toggleHistory(n) { + var i; + if (!(n != null && n.target)) + return; + const t = n.target, s = (i = t.closest(zt.FORM_ID)) == null ? void 0 : i.querySelector(".history-record"); + s && (this.toggleElementDisplay(t, s, "icon-angle-right", "icon-angle-left"), s.classList.toggle("hidden", !s.classList.contains("hidden"))); + } + resetForm(n) { + if (!(n != null && n.target)) + return; + const s = n.target.closest(zt.FORM_ID); + if (!s) + return; + s.querySelectorAll('.group-value [id^="value"]:not(.hidden), #searchForm .group-value [id*=" value"]:not(.hidden)').forEach((o) => { + o.value = ""; + }); + } + submitForm(n) { + if (!(n != null && n.target)) + return; + const s = n.target.closest(zt.FORM_ID); + s && s.submit(); + } + onDeleteQuery(n, t) { + !n || !n.target || t && n.stopPropagation(); + } + onApplyQuery(n, t) { + if (!n || !n.target || !t) + return; + const { applyQueryURL: s } = this.props; + s && (location.href = s.replace("myQueryID", t.toString())); + } + render() { + const { submitForm: n, onApplyQuery: t, onDeleteQuery: s } = this.props; + return /* @__PURE__ */ E( + Lf, + { + ...this.props, + handleSelect: this.handleSelect.bind(this), + toggleMore: this.toggleMore.bind(this), + toggleHistory: this.toggleHistory.bind(this), + resetForm: this.resetForm.bind(this), + submitForm: n ? n.bind(this) : this.submitForm.bind(this), + onDeleteQuery: s ? s.bind(this) : this.onDeleteQuery.bind(this), + onApplyQuery: t ? t.bind(this) : this.onApplyQuery.bind(this) + } + ); + } +}, w(zt, "NAME", "zui.searchForm"), w(zt, "FORM_ID", "#searchForm"), zt); +class nl extends J { +} +w(nl, "NAME", "searchForm"), w(nl, "Component", Mf); +var Si, ra, Ei, la, Ci, ca; +class Of extends kt { + constructor() { + super(...arguments); + x(this, Si); + x(this, Ei); + x(this, Ci); + } + init() { + A(this.element).on("submit", this.onSubmit.bind(this)).on("input mousedown change", this.onInput.bind(this)); + } + enable(t = !0) { + A(this.element).toggleClass("loading", !t); + } + disable() { + this.enable(!1); + } + onInput(t) { + const s = A(t.target).closest(".has-error"); + s.length && (s.removeClass("has-error"), s.closest(".form-group").find(`#${s.attr("id")}Tip`).remove()); + } + onSubmit(t) { + var o; + t.preventDefault(); + const { element: s } = this, i = A.extend({}, this.options); + this.emit("before", { event: t, element: s, options: i }, !1), ((o = i.beforeSubmit) == null ? void 0 : o.call(i, t, s, i)) !== !1 && (this.disable(), N(this, Si, ra).call(this, new FormData(s)).finally(() => { + this.enable(); + })); + } + submit() { + this.element.submit(); + } + reset() { + this.element.reset(); + } +} +Si = new WeakSet(), ra = async function(t) { + var h, c; + const { element: s, options: i } = this, { beforeSend: o } = i; + if (o) { + const u = o(t); + u instanceof FormData && (t = u); + } + this.emit("send", { formData: t }, !1); + let r, l, a; + try { + const u = await fetch(i.url || s.action, { + method: s.method || "POST", + body: t, + credentials: "same-origin", + headers: { + "X-Requested-With": "XMLHttpRequest" + } + }); + l = await u.text(), u.ok ? (a = JSON.parse(l), (!a || typeof a != "object") && (r = new Error("Invalid json format"))) : r = new Error(u.statusText); + } catch (u) { + r = u; + } + r ? (this.emit("error", { error: r, responseText: l }, !1), (h = i.onError) == null || h.call(i, r, l)) : N(this, Ci, ca).call(this, a), this.emit("complete", { result: a, error: r }, !1), (c = i.onComplete) == null || c.call(i, a, r); +}, Ei = new WeakSet(), la = function(t) { + var i; + let s; + Object.entries(t).forEach(([o, r]) => { + Array.isArray(r) && (r = r.join("")); + const l = A(this.element).find(`#${o}`); + if (!l.length) + return; + l.addClass("has-error"); + const a = l.closest(".form-group"); + if (a.length) { + let h = A(`#${o}Tip`); + h.length || (h = A(`
    `).appendTo(a)), h.empty().text(r); + } + s || (s = l); + }), s && ((i = s[0]) == null || i.focus()); +}, Ci = new WeakSet(), ca = function(t) { + var o, r; + const { options: s } = this, { message: i } = t; + if (t.result === "success") { + if (this.emit("success", { result: t }, !1), ((o = s.onSuccess) == null ? void 0 : o.call(s, t)) === !1) + return; + typeof i == "string" && i.length && A(document).trigger("zui.messager.show", { content: i, type: "success" }); + const { closeModal: l } = s; + l && A(document).trigger("zui.modal.hide", { target: l }); + const a = t.callback || s.callback; + if (typeof a == "string") { + const c = a.indexOf("("), u = (c > 0 ? a.substr(0, c) : a).split("."); + let d = window, f = u[0]; + u.length > 1 && (f = u[1], u[0] === "top" ? d = window.top : u[0] === "parent" && (d = window.parent)); + const p = d == null ? void 0 : d[f]; + if (typeof p == "function") { + let g = []; + return c > 0 && a[a.length - 1] == ")" && (g = JSON.parse("[" + a.substring(c + 1, a.length - 1) + "]")), g.push(t), p.apply(this, g); + } + } else + a && typeof a == "object" && (a.target ? window[a.target] : window)[a.name].apply(this, Array.isArray(a.params) ? a.params : [a.params]); + const h = t.locate || s.locate; + h && A(document).trigger("zui.locate", h); + } else { + if (this.emit("fail", { result: t }, !1), ((r = s.onFail) == null ? void 0 : r.call(s, t)) === !1) + return; + typeof i == "string" && i.length ? A(document).trigger("zui.messager.show", { content: i }) : typeof i == "object" && i && N(this, Ei, la).call(this, i); + } +}, w(Of, "NAME", "ajaxform"); +var Se, Ee; +class sl extends U { + constructor(t) { + super(t); + x(this, Se, 0); + x(this, Ee, null); + w(this, "_handleWheel", (t) => { + const { wheelContainer: s } = this.props, i = t.target; + if (!(!i || !s) && (typeof s == "string" && i.closest(s) || typeof s == "object")) { + const o = (this.props.type === "horz" ? t.deltaX : t.deltaY) * (this.props.wheelSpeed ?? 1); + this.scrollOffset(o) && t.preventDefault(); + } + }); + w(this, "_handleMouseMove", (t) => { + const { dragStart: s } = this.state; + s && (m(this, Se) && cancelAnimationFrame(m(this, Se)), R(this, Se, requestAnimationFrame(() => { + const i = this.props.type === "horz" ? t.clientX - s.x : t.clientY - s.y; + this.scroll(s.offset + i * this.props.scrollSize / this.props.clientSize), R(this, Se, 0); + })), t.preventDefault()); + }); + w(this, "_handleMouseUp", () => { + this.state.dragStart && this.setState({ + dragStart: !1 + }); + }); + w(this, "_handleMouseDown", (t) => { + this.state.dragStart || this.setState({ dragStart: { x: t.clientX, y: t.clientY, offset: this.scrollPos } }), t.stopPropagation(); + }); + w(this, "_handleClick", (t) => { + const s = t.currentTarget; + if (!s) + return; + const i = s.getBoundingClientRect(), { type: o, clientSize: r, scrollSize: l } = this.props, a = (o === "horz" ? t.clientX - i.left : t.clientY - i.top) - this.barSize / 2; + this.scroll(a * l / r), t.preventDefault(); + }); + this.state = { + scrollPos: this.props.defaultScrollPos ?? 0, + dragStart: !1 + }; + } + get scrollPos() { + return this.props.scrollPos ?? this.state.scrollPos; + } + get controlled() { + return this.props.scrollPos !== void 0; + } + get maxScrollPos() { + const { scrollSize: t, clientSize: s } = this.props; + return Math.max(0, t - s); + } + get barSize() { + const { clientSize: t, scrollSize: s, size: i = 12, minBarSize: o = 3 * i } = this.props; + return Math.max(Math.round(t * t / s), o); + } + componentDidMount() { + document.addEventListener("mousemove", this._handleMouseMove), document.addEventListener("mouseup", this._handleMouseUp); + const { wheelContainer: t } = this.props; + t && (R(this, Ee, typeof t == "string" ? document : t.current), m(this, Ee).addEventListener("wheel", this._handleWheel, { passive: !1 })); + } + componentWillUnmount() { + document.removeEventListener("mousemove", this._handleMouseMove), document.removeEventListener("mouseup", this._handleMouseUp), m(this, Ee) && m(this, Ee).removeEventListener("wheel", this._handleWheel); + } + scroll(t) { + return t = Math.max(0, Math.min(Math.round(t), this.maxScrollPos)), t === this.scrollPos ? !1 : (this.controlled ? this._afterScroll(t) : this.setState({ + scrollPos: t + }, this._afterScroll.bind(this, t)), !0); + } + scrollOffset(t) { + return this.scroll(this.scrollPos + t); + } + _afterScroll(t) { + const { onScroll: s } = this.props; + s && s(t, this.props.type ?? "vert"); + } + render() { + const { + clientSize: t, + type: s, + size: i = 12, + className: o, + style: r, + left: l, + top: a, + bottom: h, + right: c + } = this.props, { maxScrollPos: u, scrollPos: d } = this, { dragStart: f } = this.state, p = { + left: l, + top: a, + bottom: h, + right: c, + ...r + }, g = {}; + return s === "horz" ? (p.height = i, p.width = t, g.width = this.barSize, g.left = Math.round(Math.min(u, d) * (t - g.width) / u)) : (p.width = i, p.height = t, g.height = this.barSize, g.top = Math.round(Math.min(u, d) * (t - g.height) / u)), /* @__PURE__ */ b( + "div", + { + className: M("scrollbar", o, { + "is-vert": s === "vert", + "is-horz": s === "horz", + "is-dragging": f + }), + style: p, + onMouseDown: this._handleClick, + children: /* @__PURE__ */ b( + "div", + { + className: "scrollbar-bar", + style: g, + onMouseDown: this._handleMouseDown + } + ) + } + ); + } +} +Se = new WeakMap(), Ee = new WeakMap(); +function il(e, n, t) { + return e && (n && (e = Math.max(n, e)), t && (e = Math.min(t, e))), e; +} +function aa({ col: e, className: n, height: t, row: s, onRenderCell: i, style: o, outerStyle: r, children: l, outerClass: a, ...h }) { + var O; + const c = { + left: e.left, + width: e.realWidth, + height: t, + ...r + }, { align: u, border: d } = e.setting, f = { + justifyContent: u ? u === "left" ? "start" : u === "right" ? "end" : u : void 0, + ...e.setting.cellStyle, + ...o + }, p = ["dtable-cell", a, e.setting.className, { + "has-border-left": d === !0 || d === "left", + "has-border-right": d === !0 || d === "right" + }], g = ["dtable-cell-content", n], y = [l ?? ((O = s.data) == null ? void 0 : O[e.name]) ?? ""], _ = i ? i(y, { row: s, col: e }, E) : y, v = [], S = [], $ = {}, T = {}; + let D = "div"; + _ == null || _.forEach((k) => { + if (typeof k == "object" && k && !it(k) && ("html" in k || "className" in k || "style" in k || "attrs" in k || "children" in k || "tagName" in k)) { + const j = k.outer ? v : S; + k.html ? j.push(/* @__PURE__ */ b("div", { className: M("dtable-cell-html", k.className), style: k.style, dangerouslySetInnerHTML: { __html: k.html }, ...k.attrs ?? {} })) : (k.style && Object.assign(k.outer ? c : f, k.style), k.className && (k.outer ? p : g).push(k.className), k.children && j.push(k.children), k.attrs && Object.assign(k.outer ? $ : T, k.attrs)), k.tagName && !k.outer && (D = k.tagName); + } else + S.push(k); + }); + const L = D; + return /* @__PURE__ */ b( + "div", + { + className: M(p), + style: c, + "data-col": e.name, + ...h, + ...$, + children: [ + S.length > 0 && /* @__PURE__ */ b(L, { className: M(g), style: f, ...T, children: S }), + v + ] + } + ); +} +function oo({ row: e, className: n, top: t = 0, left: s = 0, width: i, height: o, cols: r, CellComponent: l = aa, onRenderCell: a }) { + return /* @__PURE__ */ b("div", { className: M("dtable-cells", n), style: { top: t, left: s, width: i, height: o }, children: r.map((h) => h.visible ? /* @__PURE__ */ b( + l, + { + col: h, + row: e, + onRenderCell: a + }, + h.name + ) : null) }); +} +function ua({ + row: e, + className: n, + top: t, + height: s, + fixedLeftCols: i, + fixedRightCols: o, + scrollCols: r, + fixedLeftWidth: l, + scrollWidth: a, + scrollColsWidth: h, + fixedRightWidth: c, + scrollLeft: u, + CellComponent: d = aa, + onRenderCell: f, + style: p, + ...g +}) { + let y = null; + i != null && i.length && (y = /* @__PURE__ */ b( + oo, + { + className: "dtable-fixed-left", + cols: i, + width: l, + row: e, + CellComponent: d, + onRenderCell: f + } + )); + let _ = null; + r != null && r.length && (_ = /* @__PURE__ */ b( + oo, + { + className: "dtable-flexable", + cols: r, + left: l - u, + width: Math.max(a, h), + row: e, + CellComponent: d, + onRenderCell: f + } + )); + let v = null; + o != null && o.length && (v = /* @__PURE__ */ b( + oo, + { + className: "dtable-fixed-right", + cols: o, + left: l + a, + width: c, + row: e, + CellComponent: d, + onRenderCell: f + } + )); + const S = { top: t, height: s, lineHeight: `${s - 2}px`, ...p }; + return /* @__PURE__ */ b( + "div", + { + className: M("dtable-row", n), + style: S, + "data-id": e.id, + ...g, + children: [ + y, + _, + v + ] + } + ); +} +function Pf({ height: e, onRenderRow: n, ...t }) { + const s = { + height: e, + ...t, + row: { id: "HEADER", index: -1, top: 0 }, + className: "dtable-in-header", + top: 0 + }; + if (n) { + const i = n({ props: s }, E); + i && Object.assign(s, i); + } + return /* @__PURE__ */ b("div", { className: "dtable-header", style: { height: e }, children: /* @__PURE__ */ b(ua, { ...s }) }); +} +function Df({ + className: e, + style: n, + top: t, + rows: s, + height: i, + rowHeight: o, + scrollTop: r, + onRenderRow: l, + ...a +}) { + return n = { ...n, top: t, height: i }, /* @__PURE__ */ b("div", { className: M("dtable-rows", e), style: n, children: s.map((h) => { + const c = { + className: `dtable-row-${h.index % 2 ? "odd" : "even"}`, + row: h, + top: h.top - r, + height: o, + ...a + }, u = l == null ? void 0 : l({ props: c, row: h }, E); + return u && Object.assign(c, u), /* @__PURE__ */ b(ua, { ...c }); + }) }); +} +const Us = /* @__PURE__ */ new Map(), Vs = []; +function ha(e, n) { + const { name: t } = e; + if (!(n != null && n.override) && Us.has(t)) + throw new Error(`DTable: Plugin with name ${t} already exists`); + Us.set(t, e), n != null && n.buildIn && !Vs.includes(t) && Vs.push(t); +} +function Nt(e, n) { + ha(e, n); + const t = (s) => { + if (!s) + return e; + const { defaultOptions: i, ...o } = e; + return { + ...o, + defaultOptions: { ...i, ...s } + }; + }; + return t.plugin = e, t; +} +function fa(e) { + return Us.delete(e); +} +function Hf(e) { + if (typeof e == "string") { + const n = Us.get(e); + return n || console.warn(`DTable: Cannot found plugin "${e}"`), n; + } + if (typeof e == "function" && "plugin" in e) + return e.plugin; + if (typeof e == "object") + return e; + console.warn("DTable: Invalid plugin", e); +} +function da(e, n, t) { + return n.forEach((s) => { + var o; + if (!s) + return; + const i = Hf(s); + i && (t.has(i.name) || ((o = i.plugins) != null && o.length && da(e, i.plugins, t), e.push(i), t.add(i.name))); + }), e; +} +function If(e = [], n = !0) { + return n && Vs.length && e.unshift(...Vs), e != null && e.length ? da([], e, /* @__PURE__ */ new Set()) : []; +} +function ol() { + return { + cols: [], + data: [], + rowKey: "id", + width: "100%", + height: "auto", + rowHeight: 35, + defaultColWidth: 80, + minColWidth: 20, + maxColWidth: 9999, + header: !0, + footer: !1, + headerHeight: 0, + footerHeight: 0, + rowHover: !0, + colHover: !1, + cellHover: !1, + bordered: !1, + striped: !0, + responsive: !1, + scrollbarHover: !0, + horzScrollbarPos: "outside" + }; +} +var ws, Ce, en, ne, St, se, Q, gt, Et, nn, es, ns, Wt, sn, on, $i, pa, Ri, ma, ki, ga, Ti, ya, ss, Ro, Ai, Ni, is, os, Li, Mi, Oi, _a, Pi, ba, Di, wa; +let jf = (ws = class extends U { + constructor(t) { + super(t); + x(this, $i); + x(this, Ri); + x(this, ki); + x(this, Ti); + x(this, ss); + x(this, Oi); + x(this, Pi); + x(this, Di); + w(this, "ref", cn()); + x(this, Ce, 0); + x(this, en, void 0); + x(this, ne, !1); + x(this, St, void 0); + x(this, se, void 0); + x(this, Q, []); + x(this, gt, void 0); + x(this, Et, /* @__PURE__ */ new Map()); + x(this, nn, {}); + x(this, es, void 0); + x(this, ns, []); + w(this, "updateLayout", () => { + m(this, Ce) && cancelAnimationFrame(m(this, Ce)), R(this, Ce, requestAnimationFrame(() => { + R(this, gt, void 0), this.forceUpdate(), R(this, Ce, 0); + })); + }); + x(this, Wt, (t, s) => { + s = s || t.type; + const i = m(this, Et).get(s); + if (i != null && i.length) { + for (const o of i) + if (o.call(this, t) === !1) { + t.stopPropagation(), t.preventDefault(); + break; + } + } + }); + x(this, sn, (t) => { + m(this, Wt).call(this, t, `window_${t.type}`); + }); + x(this, on, (t) => { + m(this, Wt).call(this, t, `document_${t.type}`); + }); + x(this, Ai, (t, s) => { + if (this.options.onRenderRow) { + const i = this.options.onRenderRow.call(this, t, s); + i && Object.assign(t.props, i); + } + return m(this, Q).forEach((i) => { + if (i.onRenderRow) { + const o = i.onRenderRow.call(this, t, s); + o && Object.assign(t.props, o); + } + }), t.props; + }); + x(this, Ni, (t, s) => (this.options.onRenderHeaderRow && (t.props = this.options.onRenderHeaderRow.call(this, t, s)), m(this, Q).forEach((i) => { + i.onRenderHeaderRow && (t.props = i.onRenderHeaderRow.call(this, t, s)); + }), t.props)); + x(this, is, (t, s, i) => { + const { row: o, col: r } = s; + t[0] = this.getCellValue(o, r); + const l = o.id === "HEADER" ? "onRenderHeaderCell" : "onRenderCell"; + return r.setting[l] && (t = r.setting[l].call(this, t, s, i)), this.options[l] && (t = this.options[l].call(this, t, s, i)), m(this, Q).forEach((a) => { + a[l] && (t = a[l].call(this, t, s, i)); + }), t; + }); + x(this, os, (t, s) => { + s === "horz" ? this.scroll({ scrollLeft: t }) : this.scroll({ scrollTop: t }); + }); + x(this, Li, (t) => { + var l, a, h, c, u; + const s = this.getPointerInfo(t); + if (!s) + return; + const { rowID: i, colName: o, cellElement: r } = s; + if (i === "HEADER") + r && ((l = this.options.onHeaderCellClick) == null || l.call(this, t, { colName: o, element: r }), m(this, Q).forEach((d) => { + var f; + (f = d.onHeaderCellClick) == null || f.call(this, t, { colName: o, element: r }); + })); + else { + const { rowElement: d } = s, f = this.layout.visibleRows.find((p) => p.id === i); + if (r) { + if (((a = this.options.onCellClick) == null ? void 0 : a.call(this, t, { colName: o, rowID: i, rowInfo: f, element: r, rowElement: d })) === !0) + return; + for (const p of m(this, Q)) + if (((h = p.onCellClick) == null ? void 0 : h.call(this, t, { colName: o, rowID: i, rowInfo: f, element: r, rowElement: d })) === !0) + return; + } + if (((c = this.options.onRowClick) == null ? void 0 : c.call(this, t, { rowID: i, rowInfo: f, element: d })) === !0) + return; + for (const p of m(this, Q)) + if (((u = p.onRowClick) == null ? void 0 : u.call(this, t, { rowID: i, rowInfo: f, element: d })) === !0) + return; + } + }); + x(this, Mi, (t) => { + const s = t.key.toLowerCase(); + if (["pageup", "pagedown", "home", "end"].includes(s)) + return !this.scroll({ to: s.replace("page", "") }); + }); + R(this, en, t.id ?? `dtable-${us(10)}`), this.state = { scrollTop: 0, scrollLeft: 0, renderCount: 0 }, R(this, se, Object.freeze(If(t.plugins))), m(this, se).forEach((s) => { + var l; + const { methods: i, data: o, state: r } = s; + i && Object.entries(i).forEach(([a, h]) => { + typeof h == "function" && Object.assign(this, { [a]: h.bind(this) }); + }), o && Object.assign(m(this, nn), o.call(this)), r && Object.assign(this.state, r.call(this)), (l = s.onCreate) == null || l.call(this, s); + }); + } + get options() { + var t; + return ((t = m(this, gt)) == null ? void 0 : t.options) || m(this, St) || ol(); + } + get plugins() { + return m(this, Q); + } + get layout() { + return m(this, gt); + } + get id() { + return m(this, en); + } + get data() { + return m(this, nn); + } + get parent() { + var t; + return this.props.parent ?? ((t = this.ref.current) == null ? void 0 : t.parentElement); + } + componentWillReceiveProps() { + R(this, St, void 0); + } + componentDidMount() { + if (m(this, ne) ? this.forceUpdate() : N(this, ss, Ro).call(this), m(this, Q).forEach((t) => { + let { events: s } = t; + s && (typeof s == "function" && (s = s.call(this)), Object.entries(s).forEach(([i, o]) => { + o && this.on(i, o); + })); + }), this.on("click", m(this, Li)), this.on("keydown", m(this, Mi)), this.options.responsive) { + if (typeof ResizeObserver < "u") { + const { parent: t } = this; + if (t) { + const s = new ResizeObserver(this.updateLayout); + s.observe(t), R(this, es, s); + } + } + this.on("window_resize", this.updateLayout); + } + m(this, Q).forEach((t) => { + var s; + (s = t.onMounted) == null || s.call(this); + }); + } + componentDidUpdate() { + m(this, ne) ? N(this, ss, Ro).call(this) : m(this, Q).forEach((t) => { + var s; + (s = t.onUpdated) == null || s.call(this); + }); + } + componentWillUnmount() { + var s; + (s = m(this, es)) == null || s.disconnect(); + const { current: t } = this.ref; + if (t) + for (const i of m(this, Et).keys()) + i.startsWith("window_") ? window.removeEventListener(i.replace("window_", ""), m(this, sn)) : i.startsWith("document_") ? document.removeEventListener(i.replace("document_", ""), m(this, on)) : t.removeEventListener(i, m(this, Wt)); + m(this, Q).forEach((i) => { + var o; + (o = i.onUnmounted) == null || o.call(this); + }), m(this, se).forEach((i) => { + var o; + (o = i.onDestory) == null || o.call(this); + }), R(this, nn, {}), m(this, Et).clear(); + } + on(t, s, i) { + var r; + i && (t = `${i}_${t}`); + const o = m(this, Et).get(t); + o ? o.push(s) : (m(this, Et).set(t, [s]), t.startsWith("window_") ? window.addEventListener(t.replace("window_", ""), m(this, sn)) : t.startsWith("document_") ? document.addEventListener(t.replace("document_", ""), m(this, on)) : (r = this.ref.current) == null || r.addEventListener(t, m(this, Wt))); + } + off(t, s, i) { + var l; + i && (t = `${i}_${t}`); + const o = m(this, Et).get(t); + if (!o) + return; + const r = o.indexOf(s); + r >= 0 && o.splice(r, 1), o.length || (m(this, Et).delete(t), t.startsWith("window_") ? window.removeEventListener(t.replace("window_", ""), m(this, sn)) : t.startsWith("document_") ? document.removeEventListener(t.replace("document_", ""), m(this, on)) : (l = this.ref.current) == null || l.removeEventListener(t, m(this, Wt))); + } + emitCustomEvent(t, s) { + m(this, Wt).call(this, s instanceof Event ? s : new CustomEvent(t, { detail: s }), t); + } + scroll(t, s) { + const { scrollLeft: i, scrollTop: o, rowsHeightTotal: r, rowsHeight: l, rowHeight: a, colsInfo: { scrollWidth: h, scrollColsWidth: c } } = this.layout, { to: u } = t; + let { scrollLeft: d, scrollTop: f } = t; + if (u === "up" || u === "down") + f = o + (u === "down" ? 1 : -1) * Math.floor(l / a) * a; + else if (u === "left" || u === "right") + d = i + (u === "right" ? 1 : -1) * h; + else if (u === "home") + f = 0; + else if (u === "end") + f = r - l; + else if (u === "left-begin") + d = 0; + else if (u === "right-end") + d = c - h; + else { + const { offsetLeft: g, offsetTop: y } = t; + typeof g == "number" && (d = i + g), typeof y == "number" && (d = o + y); + } + const p = {}; + return typeof d == "number" && (d = Math.max(0, Math.min(d, c - h)), d !== i && (p.scrollLeft = d)), typeof f == "number" && (f = Math.max(0, Math.min(f, r - l)), f !== o && (p.scrollTop = f)), Object.keys(p).length ? (this.setState(p, () => { + var g; + (g = this.options.onScroll) == null || g.call(this, p), s == null || s.call(this, !0); + }), !0) : (s == null || s.call(this, !1), !1); + } + getColInfo(t) { + if (t === void 0) + return; + if (typeof t == "object") + return t; + const { colsMap: s, colsList: i } = this.layout; + return typeof t == "number" ? i[t] : s[t]; + } + getRowInfo(t) { + if (t === void 0) + return; + if (typeof t == "object") + return t; + if (t === -1 || t === "HEADER") + return { id: "HEADER", index: -1, top: 0 }; + const { rows: s, rowsMap: i } = this.layout; + return typeof t == "number" ? s[t] : i[t]; + } + getCellValue(t, s) { + var a; + const i = typeof t == "object" ? t : this.getRowInfo(t); + if (!i) + return; + const o = typeof s == "object" ? s : this.getColInfo(s); + if (!o) + return; + let r = i.id === "HEADER" ? o.setting.title : (a = i.data) == null ? void 0 : a[o.name]; + const { cellValueGetter: l } = this.options; + return l && (r = l.call(this, i, o, r)), r; + } + getRowInfoByIndex(t) { + return this.layout.rows[t]; + } + update(t = {}, s) { + if (!m(this, St)) + return; + typeof t == "function" && (s = t, t = {}); + const { dirtyType: i, state: o } = t; + if (i === "layout") + R(this, gt, void 0); + else if (i === "options") { + if (R(this, St, void 0), !m(this, gt)) + return; + R(this, gt, void 0); + } + this.setState(o ?? ((r) => ({ renderCount: r.renderCount + 1 })), s); + } + getPointerInfo(t) { + const s = t.target; + if (!s || s.closest(".no-cell-event")) + return; + const i = s.closest(".dtable-cell"); + if (!i) + return; + const o = i.closest(".dtable-row"); + if (!o) + return; + const r = i == null ? void 0 : i.getAttribute("data-col"), l = o == null ? void 0 : o.getAttribute("data-id"); + if (!(typeof r != "string" || typeof l != "string")) + return { + cellElement: i, + rowElement: o, + colName: r, + rowID: l, + target: s + }; + } + i18n(t, s, i) { + return as(m(this, ns), t, s, i, this.options.lang) ?? `{i18n:${t}}`; + } + render() { + const t = N(this, Di, wa).call(this), { className: s, rowHover: i, colHover: o, cellHover: r, bordered: l, striped: a, scrollbarHover: h } = this.options, c = { width: t == null ? void 0 : t.width, height: t == null ? void 0 : t.height }, u = ["dtable", s, { + "dtable-hover-row": i, + "dtable-hover-col": o, + "dtable-hover-cell": r, + "dtable-bordered": l, + "dtable-striped": a, + "dtable-scrolled-down": ((t == null ? void 0 : t.scrollTop) ?? 0) > 0, + "scrollbar-hover": h + }], d = []; + return t && m(this, Q).forEach((f) => { + var g; + const p = (g = f.onRender) == null ? void 0 : g.call(this, t); + p && (p.style && Object.assign(c, p.style), p.className && u.push(p.className), p.children && d.push(p.children)); + }), /* @__PURE__ */ b( + "div", + { + id: m(this, en), + className: M(u), + style: c, + ref: this.ref, + tabIndex: -1, + children: [ + t && N(this, $i, pa).call(this, t), + t && N(this, Ri, ma).call(this, t), + t && N(this, ki, ga).call(this, t), + t && N(this, Ti, ya).call(this, t) + ] + } + ); + } +}, Ce = new WeakMap(), en = new WeakMap(), ne = new WeakMap(), St = new WeakMap(), se = new WeakMap(), Q = new WeakMap(), gt = new WeakMap(), Et = new WeakMap(), nn = new WeakMap(), es = new WeakMap(), ns = new WeakMap(), Wt = new WeakMap(), sn = new WeakMap(), on = new WeakMap(), $i = new WeakSet(), pa = function(t) { + const { header: s, colsInfo: i, headerHeight: o, scrollLeft: r } = t; + if (!s) + return null; + if (s === !0) + return /* @__PURE__ */ b( + Pf, + { + scrollLeft: r, + height: o, + onRenderCell: m(this, is), + onRenderRow: m(this, Ni), + ...i + } + ); + const l = Array.isArray(s) ? s : [s]; + return /* @__PURE__ */ b( + yo, + { + className: "dtable-header", + style: { height: o }, + renders: l, + generateArgs: [t], + generatorThis: this + } + ); +}, Ri = new WeakSet(), ma = function(t) { + const { headerHeight: s, rowsHeight: i, visibleRows: o, rowHeight: r, colsInfo: l, scrollLeft: a, scrollTop: h } = t; + return /* @__PURE__ */ b( + Df, + { + top: s, + height: i, + rows: o, + rowHeight: r, + scrollLeft: a, + scrollTop: h, + onRenderCell: m(this, is), + onRenderRow: m(this, Ai), + ...l + } + ); +}, ki = new WeakSet(), ga = function(t) { + const { footer: s } = t; + if (!s) + return null; + const i = typeof s == "function" ? s.call(this, t) : Array.isArray(s) ? s : [s]; + return /* @__PURE__ */ b( + yo, + { + className: "dtable-footer", + style: { height: t.footerHeight, top: t.rowsHeight + t.headerHeight }, + renders: i, + generateArgs: [t], + generatorThis: this, + generators: t.footerGenerators + } + ); +}, Ti = new WeakSet(), ya = function(t) { + const s = [], { scrollLeft: i, colsInfo: o, scrollTop: r, rowsHeight: l, rowsHeightTotal: a, footerHeight: h } = t, { scrollColsWidth: c, scrollWidth: u } = o, { scrollbarSize: d = 12, horzScrollbarPos: f } = this.options; + return c > u && s.push( + /* @__PURE__ */ b( + sl, + { + type: "horz", + scrollPos: i, + scrollSize: c, + clientSize: u, + onScroll: m(this, os), + left: o.fixedLeftWidth, + bottom: (f === "inside" ? 0 : -d) + h, + size: d, + wheelContainer: this.ref + }, + "horz" + ) + ), a > l && s.push( + /* @__PURE__ */ b( + sl, + { + type: "vert", + scrollPos: r, + scrollSize: a, + clientSize: l, + onScroll: m(this, os), + right: 0, + size: d, + top: t.headerHeight, + wheelContainer: this.ref + }, + "vert" + ) + ), s.length ? s : null; +}, ss = new WeakSet(), Ro = function() { + var t; + R(this, ne, !1), (t = this.options.afterRender) == null || t.call(this), m(this, Q).forEach((s) => { + var i; + return (i = s.afterRender) == null ? void 0 : i.call(this); + }); +}, Ai = new WeakMap(), Ni = new WeakMap(), is = new WeakMap(), os = new WeakMap(), Li = new WeakMap(), Mi = new WeakMap(), Oi = new WeakSet(), _a = function() { + if (m(this, St)) + return !1; + const s = { ...ol(), ...m(this, se).reduce((i, o) => { + const { defaultOptions: r } = o; + return r && Object.assign(i, r), i; + }, {}), ...this.props }; + return R(this, St, s), R(this, Q, m(this, se).reduce((i, o) => { + const { when: r, options: l } = o; + return (!r || r(s)) && (i.push(o), l && Object.assign(s, typeof l == "function" ? l.call(this, s) : l)), i; + }, [])), R(this, ns, [this.options.i18n, ...this.plugins.map((i) => i.i18n)].filter(Boolean)), !0; +}, Pi = new WeakSet(), ba = function() { + var Qo, Zo; + const { plugins: t } = this; + let s = m(this, St); + const i = { + flex: /* @__PURE__ */ b("div", { style: "flex:auto" }), + divider: /* @__PURE__ */ b("div", { style: "width:1px;margin:var(--space);background:var(--color-border);height:50%" }) + }; + t.forEach((H) => { + var Mt; + const Y = (Mt = H.beforeLayout) == null ? void 0 : Mt.call(this, s); + Y && (s = { ...s, ...Y }), Object.assign(i, H.footer); + }); + const { defaultColWidth: o, minColWidth: r, maxColWidth: l } = s, a = [], h = [], c = [], u = {}, d = [], f = []; + let p = 0, g = 0, y = 0; + s.cols.forEach((H) => { + if (H.hidden) + return; + const { + name: Y, + type: Mt = "", + fixed: Ot = !1, + flex: ge = !1, + width: un = o, + minWidth: hn = r, + maxWidth: Xi = l, + ...Ta + } = H, B = { + name: Y, + type: Mt, + setting: { + name: Y, + type: Mt, + fixed: Ot, + flex: ge, + width: un, + minWidth: hn, + maxWidth: Xi, + ...Ta + }, + flex: Ot ? 0 : ge === !0 ? 1 : typeof ge == "number" ? ge : 0, + left: 0, + width: il(un, hn, Xi), + realWidth: 0, + visible: !0, + index: d.length + }; + t.forEach((tr) => { + var er, nr; + const ds = (er = tr.colTypes) == null ? void 0 : er[Mt]; + if (ds) { + const sr = typeof ds == "function" ? ds(B) : ds; + sr && Object.assign(B.setting, sr); + } + (nr = tr.onAddCol) == null || nr.call(this, B); + }), B.width = il(B.setting.width ?? B.width, B.setting.minWidth ?? hn, B.setting.maxWidth ?? Xi), B.realWidth = B.realWidth || B.width, Ot === "left" ? (B.left = p, p += B.width, a.push(B)) : Ot === "right" ? (B.left = g, g += B.width, h.push(B)) : (B.left = y, y += B.width, c.push(B)), B.flex && f.push(B), d.push(B), u[B.name] = B; + }); + let _ = s.width, v = 0; + const S = p + y + g; + if (typeof _ == "function" && (_ = _.call(this, S)), _ === "auto") + v = S; + else if (_ === "100%") { + const { parent: H } = this; + if (H) + v = H.clientWidth; + else { + v = 0, R(this, ne, !0); + return; + } + } else + v = _ ?? 0; + const { data: $, rowKey: T = "id", rowHeight: D } = s, L = [], O = (H, Y, Mt) => { + var ge, un; + const Ot = { data: Mt ?? { [T]: H }, id: H, index: L.length, top: 0 }; + if (Mt || (Ot.lazy = !0), L.push(Ot), ((ge = s.onAddRow) == null ? void 0 : ge.call(this, Ot, Y)) !== !1) { + for (const hn of t) + if (((un = hn.onAddRow) == null ? void 0 : un.call(this, Ot, Y)) === !1) + return; + } + }; + if (typeof $ == "number") + for (let H = 0; H < $; H++) + O(`${H}`, H); + else + Array.isArray($) && $.forEach((H, Y) => { + typeof H == "object" ? O(`${H[T] ?? ""}`, Y, H) : O(`${H ?? ""}`, Y); + }); + let k = L; + const j = {}; + if (s.onAddRows) { + const H = s.onAddRows.call(this, k); + H && (k = H); + } + for (const H of t) { + const Y = (Qo = H.onAddRows) == null ? void 0 : Qo.call(this, k); + Y && (k = Y); + } + k.forEach((H, Y) => { + j[H.id] = H, H.index = Y, H.top = H.index * D; + }); + const { header: P, footer: V } = s, F = P ? s.headerHeight || D : 0, G = V ? s.footerHeight || D : 0; + let I = s.height, K = 0; + const bt = k.length * D, de = F + G + bt; + if (typeof I == "function" && (I = I.call(this, de)), I === "auto") + K = de; + else if (typeof I == "object") + K = Math.min(I.max, Math.max(I.min, de)); + else if (I === "100%") { + const { parent: H } = this; + if (H) + K = H.clientHeight; + else { + K = 0, R(this, ne, !0); + return; + } + } else + K = I; + const pe = K - F - G, me = v - p - g, Lt = { + options: s, + allRows: L, + width: v, + height: K, + rows: k, + rowsMap: j, + rowHeight: D, + rowsHeight: pe, + rowsHeightTotal: bt, + header: P, + footer: V, + footerGenerators: i, + headerHeight: F, + footerHeight: G, + colsMap: u, + colsList: d, + flexCols: f, + colsInfo: { + fixedLeftCols: a, + fixedRightCols: h, + scrollCols: c, + fixedLeftWidth: p, + scrollWidth: me, + scrollColsWidth: y, + fixedRightWidth: g + } + }, Ne = (Zo = s.onLayout) == null ? void 0 : Zo.call(this, Lt); + Ne && Object.assign(Lt, Ne), t.forEach((H) => { + if (H.onLayout) { + const Y = H.onLayout.call(this, Lt); + Y && Object.assign(Lt, Y); + } + }), R(this, gt, Lt); +}, Di = new WeakSet(), wa = function() { + (N(this, Oi, _a).call(this) || !m(this, gt)) && N(this, Pi, ba).call(this); + const { layout: t } = this; + if (!t) + return; + let { scrollLeft: s } = this.state; + const { flexCols: i, colsInfo: { scrollCols: o, scrollWidth: r, scrollColsWidth: l } } = t; + if (i.length) { + const S = r - l; + if (S > 0) { + const $ = i.reduce((D, L) => D + L.flex, 0); + let T = 0; + i.forEach((D) => { + const L = Math.min(S - T, Math.ceil(S * (D.flex / $))); + D.realWidth = L + D.width, T += D.realWidth; + }); + } else + i.forEach(($) => { + $.realWidth = $.width; + }); + } + s = Math.min(Math.max(0, l - r), s); + let a = 0; + o.forEach((S) => { + S.left = a, a += S.realWidth, S.visible = S.left + S.realWidth >= s && S.left <= s + r; + }); + const { rowsHeightTotal: h, rowsHeight: c, rows: u, rowHeight: d } = t, f = Math.min(Math.max(0, h - c), this.state.scrollTop), p = Math.floor(f / d), g = f + c, y = Math.min(u.length, Math.ceil(g / d)), _ = [], { rowDataGetter: v } = this.options; + for (let S = p; S < y; S++) { + const $ = u[S]; + $.lazy && v && ($.data = v([$.id])[0], $.lazy = !1), _.push($); + } + return t.visibleRows = _, t.scrollTop = f, t.scrollLeft = s, t; +}, w(ws, "addPlugin", ha), w(ws, "removePlugin", fa), ws); +function rl(e, n) { + n !== void 0 ? e.data.hoverCol = n : n = e.data.hoverCol; + const { current: t } = e.ref; + if (!t) + return; + const s = "dtable-col-hover"; + t.querySelectorAll(`.${s}`).forEach((i) => i.classList.remove(s)), typeof n == "string" && n.length && t.querySelectorAll(`.dtable-cell[data-col="${n}"]`).forEach((i) => i.classList.add(s)); +} +const Wf = { + name: "col-hover", + defaultOptions: { + colHover: !1 + }, + when: (e) => !!e.colHover, + events: { + mouseover(e) { + var i; + const { colHover: n } = this.options; + if (!n) + return; + const t = (i = e.target) == null ? void 0 : i.closest(".dtable-cell"); + if (!t || n === "header" && !t.closest(".dtable-header")) + return; + const s = (t == null ? void 0 : t.getAttribute("data-col")) ?? !1; + rl(this, s); + }, + mouseleave() { + rl(this, !1); + } + } +}, Ff = Nt(Wf, { buildIn: !0 }); +function Bf(e, n) { + var r, l; + typeof e == "boolean" && (n = e, e = void 0); + const t = this.state.checkedRows, s = {}, { canRowCheckable: i } = this.options, o = (a, h) => { + i && !i.call(this, a) || !!t[a] === h || (h ? t[a] = !0 : delete t[a], s[a] = h); + }; + if (e === void 0 ? (n === void 0 && (n = !va.call(this)), (r = this.layout) == null || r.allRows.forEach(({ id: a }) => { + o(a, !!n); + })) : (Array.isArray(e) || (e = [e]), e.forEach((a) => { + o(a, n ?? !t[a]); + })), Object.keys(s).length) { + const a = (l = this.options.beforeCheckRows) == null ? void 0 : l.call(this, e, s, t); + a && Object.keys(a).forEach((h) => { + a[h] ? t[h] = !0 : delete t[h]; + }), this.setState({ checkedRows: { ...t } }, () => { + var h; + (h = this.options.onCheckChange) == null || h.call(this, s); + }); + } + return s; +} +function zf(e) { + return this.state.checkedRows[e] ?? !1; +} +function va() { + var t, s; + const e = this.getChecks().length, { canRowCheckable: n } = this.options; + return n ? e === ((t = this.layout) == null ? void 0 : t.allRows.reduce((i, o) => i + (n.call(this, o.id) ? 1 : 0), 0)) : e === ((s = this.layout) == null ? void 0 : s.allRows.length); +} +function Uf() { + return Object.keys(this.state.checkedRows); +} +const Vf = { + name: "checkable", + defaultOptions: { checkable: !0 }, + when: (e) => !!e.checkable, + state() { + return { checkedRows: {} }; + }, + methods: { + toggleCheckRows: Bf, + isRowChecked: zf, + isAllRowChecked: va, + getChecks: Uf + }, + i18n: { + zh_cn: { + checkedCountInfo: "已选择 {selected} 项", + totalCountInfo: "共 {total} 项" + }, + en: { + checkedCountInfo: "Selected {selected} items", + totalCountInfo: "Total {total} items" + } + }, + footer: { + checkbox() { + const e = this.isAllRowChecked(); + return [ + /* @__PURE__ */ b("div", { style: { padding: "0 calc(3 * var(--space))", display: "flex", alignItems: "center" }, onClick: () => this.toggleCheckRows(), children: /* @__PURE__ */ b("input", { type: "checkbox", checked: e }) }) + ]; + }, + checkedInfo(e, n) { + const t = this.getChecks().length, s = []; + return t && s.push(this.i18n("checkedCountInfo", { selected: t })), s.push(this.i18n("totalCountInfo", { total: n.allRows.length })), [ + /* @__PURE__ */ b("div", { children: s.join(", ") }) + ]; + } + }, + onRenderCell(e, { row: n, col: t }) { + var l; + const { id: s } = n, { canRowCheckable: i } = this.options; + if (i && !i.call(this, s)) + return e; + const { checkbox: o } = t.setting; + if (typeof o == "function" ? o.call(this, s) : o) { + const a = this.isRowChecked(s), h = ((l = this.options.checkboxRender) == null ? void 0 : l.call(this, a, s)) ?? /* @__PURE__ */ b("input", { type: "checkbox", checked: a }); + e.unshift(h), e.push({ className: "has-checkbox" }); + } + return e; + }, + onRenderHeaderCell(e, { row: n, col: t }) { + var r; + const { id: s } = n, { checkbox: i } = t.setting; + if (typeof i == "function" ? i.call(this, s) : i) { + const l = this.isAllRowChecked(), a = ((r = this.options.checkboxRender) == null ? void 0 : r.call(this, l, s)) ?? /* @__PURE__ */ b("input", { type: "checkbox", checked: l }); + e.unshift(a), e.push({ className: "has-checkbox" }); + } + return e; + }, + onRenderRow({ props: e, row: n }) { + if (this.isRowChecked(n.id)) + return { className: M(e.className, "is-checked") }; + }, + onHeaderCellClick(e) { + const n = e.target; + if (!n) + return; + const t = n.closest('input[type="checkbox"],.dtable-checkbox'); + t && (this.toggleCheckRows(t.checked), e.stopPropagation()); + }, + onRowClick(e, { rowID: n }) { + const t = e.target; + if (!t) + return; + (t.closest('input[type="checkbox"],.dtable-checkbox') || this.options.checkOnClickRow) && this.toggleCheckRows(n); + } +}, qf = Nt(Vf); +var xa = /* @__PURE__ */ ((e) => (e.unknown = "", e.collapsed = "collapsed", e.expanded = "expanded", e.hidden = "hidden", e.normal = "normal", e))(xa || {}); +function ko(e) { + const n = this.data.nestedMap.get(e); + if (!n || n.state !== "") + return n ?? { state: "normal", level: -1 }; + if (!n.parent && !n.children) + return n.state = "normal", n; + const t = this.state.collapsedRows, s = n.children && t && t[e]; + let i = !1, { parent: o } = n; + for (; o; ) { + const r = ko.call(this, o); + if (r.state !== "expanded") { + i = !0; + break; + } + o = r.parent; + } + return n.state = i ? "hidden" : s ? "collapsed" : n.children ? "expanded" : "normal", n.level = n.parent ? ko.call(this, n.parent).level + 1 : 0, n; +} +function Gf(e, n) { + let t = this.state.collapsedRows ?? {}; + const { nestedMap: s } = this.data; + if (e === "HEADER") + if (n === void 0 && (n = !Sa.call(this)), n) { + const i = s.entries(); + for (const [o, r] of i) + r.state === "expanded" && (t[o] = !0); + } else + t = {}; + else { + const i = Array.isArray(e) ? e : [e]; + n === void 0 && (n = !t[i[0]]), i.forEach((o) => { + const r = s.get(o); + n && (r != null && r.children) ? t[o] = !0 : delete t[o]; + }); + } + this.update({ + dirtyType: "layout", + state: { collapsedRows: { ...t } } + }, () => { + var i; + (i = this.options.onNestedChange) == null || i.call(this); + }); +} +function Sa() { + const e = this.data.nestedMap.values(); + for (const n of e) + if (n.state === "expanded") + return !1; + return !0; +} +function Ea(e, n = 0, t, s = 0) { + var i; + t || (t = [...e.keys()]); + for (const o of t) { + const r = e.get(o); + r && (r.level === s && (r.order = n++), (i = r.children) != null && i.length && (n = Ea(e, n, r.children, s + 1))); + } + return n; +} +function Ca(e, n, t, s) { + const i = e.getNestedRowInfo(n); + return !i || i.state === "" || !i.children || i.children.forEach((o) => { + s[o] = t, Ca(e, o, t, s); + }), i; +} +function $a(e, n, t, s, i) { + var l; + const o = e.getNestedRowInfo(n); + if (!o || o.state === "") + return; + ((l = o.children) == null ? void 0 : l.every((a) => { + const h = !!(s[a] !== void 0 ? s[a] : i[a]); + return t === h; + })) && (s[n] = t), o.parent && $a(e, o.parent, t, s, i); +} +const Kf = { + name: "nested", + defaultOptions: { + nested: !0, + nestedParentKey: "parent", + asParentKey: "asParent", + nestedIndent: 20, + canSortTo(e, n) { + const { nestedMap: t } = this.data, s = t.get(e.id), i = t.get(n.id); + return (s == null ? void 0 : s.parent) === (i == null ? void 0 : i.parent); + }, + beforeCheckRows(e, n, t) { + if (!this.options.checkable || !(e != null && e.length)) + return; + const s = {}; + return Object.entries(n).forEach(([i, o]) => { + const r = Ca(this, i, o, s); + r != null && r.parent && $a(this, r.parent, o, s, t); + }), s; + } + }, + when: (e) => !!e.nested, + data() { + return { nestedMap: /* @__PURE__ */ new Map() }; + }, + methods: { + toggleRow: Gf, + isAllCollapsed: Sa, + getNestedRowInfo: ko + }, + beforeLayout() { + this.data.nestedMap.clear(); + }, + onAddRow(e) { + var i, o; + const { nestedMap: n } = this.data, t = (i = e.data) == null ? void 0 : i[this.options.nestedParentKey ?? "parent"], s = n.get(e.id) ?? { + state: "", + level: 0 + }; + if (s.parent = t, (o = e.data) != null && o[this.options.asParentKey ?? "asParent"] && (s.children = []), n.set(e.id, s), t) { + let r = n.get(t); + r || (r = { + state: "", + level: 0 + }, n.set(t, r)), r.children || (r.children = []), r.children.push(e.id); + } + }, + onAddRows(e) { + return e = e.filter( + (n) => this.getNestedRowInfo(n.id).state !== "hidden" + /* hidden */ + ), Ea(this.data.nestedMap), e.sort((n, t) => { + const s = this.getNestedRowInfo(n.id), i = this.getNestedRowInfo(t.id), o = (s.order ?? 0) - (i.order ?? 0); + return o === 0 ? n.index - t.index : o; + }), e; + }, + onRenderCell(e, { col: n, row: t }) { + var l; + const { id: s, data: i } = t, { nestedToggle: o } = n.setting, r = this.getNestedRowInfo(s); + if (o && (r.children || r.parent) && e.unshift(((l = this.options.onRenderNestedToggle) == null ? void 0 : l.call(this, r, s, n, i)) ?? /* @__PURE__ */ b("a", { role: "button", className: `dtable-nested-toggle state${r.children ? "" : " is-no-child"}`, children: /* @__PURE__ */ b("span", { className: "toggle-icon" }) })), r.level) { + let { nestedIndent: a = o } = n.setting; + a && (a === !0 && (a = this.options.nestedIndent ?? 12), e.unshift(/* @__PURE__ */ b("div", { className: "dtable-nested-indent", style: { width: a * r.level + "px" } }))); + } + return e; + }, + onRenderHeaderCell(e, { row: n, col: t }) { + var i; + const { id: s } = n; + return t.setting.nestedToggle && e.unshift(((i = this.options.onRenderNestedToggle) == null ? void 0 : i.call(this, void 0, s, t, void 0)) ?? /* @__PURE__ */ b("a", { type: "button", className: "dtable-nested-toggle state", children: /* @__PURE__ */ b("span", { className: "toggle-icon" }) })), e; + }, + onRenderRow({ props: e, row: n }) { + const t = this.getNestedRowInfo(n.id); + return { + className: M(e.className, `is-${t.state}`), + "data-parent": t.parent + }; + }, + onRenderHeaderRow({ props: e }) { + return e.className = M(e.className, `is-${this.isAllCollapsed() ? "collapsed" : "expanded"}`), e; + }, + onHeaderCellClick(e) { + const n = e.target; + if (!(!n || !n.closest(".dtable-nested-toggle"))) + return this.toggleRow("HEADER"), !0; + }, + onCellClick(e, { rowID: n }) { + const t = e.target; + if (!(!t || !this.getNestedRowInfo(n).children || !t.closest(".dtable-nested-toggle"))) + return this.toggleRow(n), !0; + } +}, Yf = Nt(Kf); +const Xf = { + name: "rich", + colTypes: { + html: { + onRenderCell(e) { + return e[0] = { + html: e[0] + }, e; + } + }, + link: { + onRenderCell(e, { col: n, row: t }) { + const { linkTemplate: s = "", linkProps: i } = n.setting, o = tt(s, t.data); + return e[0] = /* @__PURE__ */ b("a", { href: o, ...i, children: e[0] }), e; + } + }, + avatar: { + onRenderCell(e, { col: n, row: t }) { + const { data: s } = t, { avatarWithName: i, avatarClass: o = "size-xs circle", avatarKey: r = `${n.name}Avatar` } = n.setting, l = /* @__PURE__ */ b("div", { className: `avatar ${o} flex-none`, children: /* @__PURE__ */ b("img", { src: s ? s[r] : "" }) }); + return i ? e.unshift(l) : e[0] = l, e; + } + }, + circleProgress: { + align: "center", + onRenderCell(e, { col: n }) { + const { circleSize: t = 24, circleBorderSize: s = 1, circleBgColor: i = "var(--color-border)", circleColor: o = "var(--color-success-500)" } = n.setting, r = (t - s) / 2, l = t / 2, a = e[0]; + return e[0] = /* @__PURE__ */ b("svg", { width: t, height: t, children: [ + /* @__PURE__ */ b("circle", { cx: l, cy: l, r, "stroke-width": s, stroke: i, fill: "transparent" }), + /* @__PURE__ */ b("circle", { cx: l, cy: l, r, "stroke-width": s, stroke: o, fill: "transparent", "stroke-linecap": "round", "stroke-dasharray": Math.PI * r * 2, "stroke-dashoffset": Math.PI * r * 2 * (100 - a) / 100, style: { transformOrigin: "center", transform: "rotate(-90deg)" } }), + /* @__PURE__ */ b("text", { x: l, y: l + s, "dominant-baseline": "middle", "text-anchor": "middle", style: { fontSize: `${r}px` }, children: Math.round(a) }) + ] }), e; + } + }, + actionButtons: { + onRenderCell(e, { col: n, row: t }) { + var l; + const s = (l = t.data) == null ? void 0 : l[n.name]; + if (!s) + return e; + const { actionBtnTemplate: i = '', actionBtnData: o = {}, actionBtnClass: r = "btn text-primary square size-sm ghost" } = n.setting; + return [{ + html: s.map((a) => { + typeof a == "string" && (a = { action: a }); + const h = o[a.action]; + return h && (a = { className: r, ...h, ...a }), tt(i, a); + }).join(" ") + }]; + } + }, + format: { + onRenderCell(e, { col: n }) { + let { format: t } = n.setting; + if (!t) + return e; + typeof t == "string" && (t = { type: "text", format: t }); + const { format: s, type: i } = t, o = e[0]; + return typeof s == "function" ? e[0] = i === "html" ? { html: s(o) } : s(o) : i === "datetime" ? e[0] = So(o, s) : i === "html" ? e[0] = { html: tt(s, o) } : e[0] = tt(s, o), e; + } + } + } +}, Jf = Nt(Xf, { buildIn: !0 }), Qf = { + name: "sort-type", + onRenderHeaderCell(e, { col: n }) { + const { sortType: t } = n.setting; + if (t) { + const { sortLink: s = this.options.sortLink, sortAttrs: i } = n.setting, o = t === !0 ? "none" : t; + if (e.push( + /* @__PURE__ */ b("div", { className: `dtable-sort dtable-sort-${o}` }), + { outer: !0, attrs: { "data-sort": o } } + ), s) { + const r = typeof s == "function" ? s.call(this, n, o) : s; + e.push( + { tagName: "a", attrs: { href: r, ...i } } + ); + } + } + return e; + } +}, Zf = Nt(Qf, { buildIn: !0 }), td = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ + __proto__: null, + NestedRowState: xa, + checkable: qf, + colHover: Ff, + nested: Yf, + rich: Jf, + sortType: Zf +}, Symbol.toStringTag, { value: "Module" })); +class fn extends J { +} +w(fn, "NAME", "dtable"), w(fn, "Component", jf), w(fn, "definePlugin", Nt), w(fn, "removePlugin", fa), w(fn, "plugins", td); +function ed(e) { + const [n, t] = e.split(":"), s = n[0] === "-" ? { name: n.substring(1), disabled: !0 } : { name: n }; + return t != null && t.length && (s.type = "dropdown", s.items = t.split(",").reduce((i, o) => (o = o.trim(), o.length && i.push(o[0] === "-" ? { name: o.substring(1), disabled: !0 } : { name: o }), i), [])), s; +} +const nd = (e, n) => { + var t; + return e.url && (e.url = tt(e.url, n.row.data)), (t = e.dropdown) != null && t.items && (e.dropdown.items = e.dropdown.items.map((s) => (s.url && (s.url = tt(s.url, n.row.data)), s))), e; +}, sd = { + name: "actions", + colTypes: { + actions: { + onRenderCell(e, n) { + var c; + const { row: t, col: s } = n; + let i = (c = t.data) == null ? void 0 : c[s.name]; + if (typeof i == "string" && (i = i.split("|")), !(i != null && i.length)) + return e; + const { actionsSetting: o, actionsMap: r, actionsCreator: l = this.options.actionsCreator, actionItemCreator: a = this.options.actionItemCreator || nd } = s.setting, h = { + items: (l == null ? void 0 : l(n)) ?? i.map((u) => { + if (u = typeof u == "string" ? ed(u) : u, !u) + return; + const { name: d, items: f, ...p } = u; + if (r && d && (Object.assign(p, r[d], { ...p }), typeof p.buildProps == "function")) { + const { buildProps: g } = p; + delete p.buildProps, Object.assign(p, g(e, n)); + } + if (f && p.type === "dropdown") { + const { dropdown: g = {} } = p; + g.menu = { + className: "menu-dtable-actions", + items: f.reduce((y, _) => { + const v = typeof _ == "string" ? { name: _ } : { ..._ }; + return v != null && v.name && (r && "name" in v && Object.assign(v, r[v.name], { ...v }), y.push(v)), y; + }, []) + }, p.dropdown = g; + } + return a ? a(p, n) : p; + }).filter(Boolean), + btnProps: { size: "sm", className: "text-primary" }, + ...o + }; + return e[0] = /* @__PURE__ */ b(ae, { ...h }), e; + } + } + } +}, id = Nt(sd), od = { + name: "toolbar", + footer: { + toolbar() { + const { footToolbar: e } = this.options; + return [e ? /* @__PURE__ */ b(ae, { ...e }) : null]; + } + } +}, rd = Nt(od), ld = { + name: "pager", + footer: { + pager() { + const { footPager: e } = this.options; + return [e ? /* @__PURE__ */ b(Ic, { ...e }) : null]; + } + } +}, cd = Nt(ld); +const ad = { + name: "zentao", + plugins: ["checkable", "nested", id, rd, cd], + defaultOptions: { + footer: ["checkbox", "checkedInfo"], + colHover: !1, + rowHeight: 36, + filterable: !0, + striped: !1, + responsive: !0, + checkable: !1, + nested: !1, + height: (e) => { + var n, t; + return Math.min(e, window.innerHeight - 1 - (((n = document.getElementById("header")) == null ? void 0 : n.clientHeight) ?? 0) - (((t = document.getElementById("mainMenu")) == null ? void 0 : t.clientHeight) ?? 0)); + } + }, + colTypes: { + status: { + width: 80, + align: "center", + sortType: !0, + onRenderCell(e, { col: n, row: t }) { + var r, l; + const s = (r = t.data) == null ? void 0 : r[n.name]; + let i, o; + return typeof s == "string" ? (i = s, o = (l = n.setting.statusMap) == null ? void 0 : l[s]) : typeof s == "object" && s && ({ name: i, label: o } = s), e[0] = /* @__PURE__ */ E("span", { class: `${n.setting.statusClassPrefix ?? "status-"}${i}` }, o ?? i), e; + } + }, + avatarBtn: { + width: 100, + sortType: !0, + onRenderCell(e, { col: n, row: t }) { + const { data: s } = t, i = s ? s[n.name] : void 0; + if (!(i != null && i.length)) + return e; + const { avatarClass: o = "circle", avatarKey: r = `${n.name}Avatar`, avatarSetting: l, avatarCodeKey: a, avatarNameKey: h = `${n.name}Name`, avatarBtnProps: c } = n.setting, u = (s ? s[h] : i) || e[0], d = { + size: "xs", + className: M(o, l == null ? void 0 : l.className, "flex-none"), + src: s ? s[r] : void 0, + text: u, + code: a ? s ? s[a] : void 0 : i, + ...l + }, f = typeof c == "function" ? c(e, n, t) : c || {}; + return e[0] = /* @__PURE__ */ E("button", { type: "button", className: "btn btn-avatar", ...f }, /* @__PURE__ */ E(Nc, { ...d }), /* @__PURE__ */ E("div", null, u)), e; + } + } + }, + onRenderCell(e, { row: n, col: t }) { + const { iconRender: s } = t.setting; + if (typeof s != "function") + return e; + const i = s(n); + return i && e.unshift(typeof i == "object" ? /* @__PURE__ */ E("i", { ...i }) : /* @__PURE__ */ E("i", { className: i })), e; + } +}, Fd = Nt(ad, { buildIn: !0 }); +function Ra(e) { + e = e || location.search, e[0] === "?" && (e = e.substring(1)); + try { + return JSON.parse('{"' + decodeURI(e).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}'); + } catch { + return {}; + } +} +function ud(e) { + if (!e) + return { url: e }; + const { config: n } = window; + if (/^https?:\/\//.test(e)) { + const a = window.location.origin; + if (!e.includes(a)) + return { external: !0, url: e }; + e = e.substring((a + n.webRoot).length); + } + const t = e.split("#"), s = t[0].split("?"), i = s[1], o = i ? Ra(i) : {}; + let r = s[0]; + const l = { + url: e, + isOnlyBody: o.onlybody === "yes", + vars: [], + hash: t[1] || "", + params: o, + tid: o.tid || "" + }; + if (n.requestType === "GET") { + l.moduleName = o[n.moduleVar] || "index", l.methodName = o[n.methodVar] || "index", l.viewType = o[n.viewVar] || n.defaultView; + for (const a in o) + a !== n.moduleVar && a !== n.methodVar && a !== n.viewVar && a !== "onlybody" && a !== "tid" && l.vars.push([a, o[a]]); + } else { + let a = r.lastIndexOf("/"); + a === r.length - 1 && (r = r.substring(0, a), a = r.lastIndexOf("/")), a >= 0 && (r = r.substring(a + 1)); + const h = r.lastIndexOf("."); + h >= 0 ? (l.viewType = r.substring(h + 1), r = r.substring(0, h)) : l.viewType = n.defaultView; + const c = r.split(n.requestFix); + if (l.moduleName = c[0] || "index", l.methodName = c[1] || "index", c.length > 2) + for (let u = 2; u < c.length; u++) + l.vars.push(["", c[u]]), o["$" + (u - 1)] = c[u]; + } + return l; +} +function ka(e, n, t, s, i, o, r, l) { + if (typeof e == "object") + return ka(e.moduleName, e.methodName, e.vars, e.viewType, e.isOnlyBody, e.hash, e.tid, e.params); + l && l.isOnlyBody !== void 0 && i === void 0 && (i = !!l.isOnlyBody); + const a = window.config; + if (s || (s = a.defaultView), i || (i = !1), t) { + typeof t == "string" && (t = t.split("&")); + for (let u = 0; u < t.length; u++) { + const d = t[u]; + if (typeof d == "string") { + const f = d.split("="); + t[u] = [f.shift(), f.join("=")]; + } + } + } + const h = [], c = a.requestType === "GET"; + if (c) { + if (h.push(a.router, "?", a.moduleVar, "=", e, "&", a.methodVar, "=", n), t) + for (let u = 0; u < t.length; u++) + h.push("&", t[u][0], "=", t[u][1]); + h.push("&", a.viewVar, "=", s); + } else { + if (a.requestType == "PATH_INFO" && h.push(a.webRoot, e, a.requestFix, n), a.requestType == "PATH_INFO2" && h.push(a.webRoot, "index.php/", e, a.requestFix, n), t) + for (let u = 0; u < t.length; u++) + h.push(a.requestFix + t[u][1]); + h.push(".", s); + } + return (a.onlybody === "yes" || i) && h.push(c ? "&" : "?", "onlybody=yes"), l && Object.keys(l).forEach((u) => { + const d = l[u]; + u === "tid" || u === "isOnlyBody" || u[0] === "$" || h.push(!c && !h.includes("?") ? "?" : "&", u, "=", d); + }), r && a.tabSession && h.push(!c && !h.includes("?") ? "?" : "&", "tid=", r), typeof o == "string" && h.push(o.startsWith("#") ? "" : "#", o), h.join(""); +} +const hd = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ + __proto__: null, + createLink: ka, + parseLink: ud, + parseUrlParams: Ra +}, Symbol.toStringTag, { value: "Module" })), ro = /* @__PURE__ */ new Map(); +function Bd(e, n, t) { + const { zui: s } = window; + ro.size || Object.keys(s).forEach((o) => { + o[0] === o[0].toUpperCase() && ro.set(o.toLowerCase(), s[o]); + }); + const i = ro.get(e.toLowerCase()); + return i ? new i(n, t) : null; +} +window.$ && Object.assign(window.$, hd); +export { + A as $, + mr as ActionMenu, + yr as ActionMenuNested, + Of as AjaxForm, + jr as Avatar, + Wr as BtnGroup, + _r as Button, + lt as ContextMenu, + fn as DTable, + st as Dropdown, + Hi as EventBus, + br as Menu, + tl as MenuTree, + mn as Messager, + nt as Modal, + Cn as ModalTrigger, + Fr as Nav, + _n as NavTabs, + Ur as Pager, + qr as Picker, + Mr as ProgressCircle, + el as QuickMenu, + nl as SearchForm, + Or as Switch, + Pt as TIME_DAY, + Gr as Toolbar, + ht as Tooltip, + Va as addI18nMap, + Cd as ajax, + Ed as browser, + $d as bus, + zr as calculateTimestamp, + qu as cash, + ro as componentsMap, + pd as convertBytes, + Bd as create, + at as createDate, + dd as formatBytes, + So as formatDate, + Od as formatDateSpan, + tt as formatString, + za as getLangCode, + Pd as getTimeBeforeDesc, + as as i18n, + Md as isDBY, + Qi as isObject, + hs as isSameDay, + ef as isSameMonth, + Td as isSameWeek, + Br as isSameYear, + Ad as isToday, + Ld as isTomorrow, + Nd as isYesterday, + go as mergeDeep, + mo as nativeEvents, + Ua as setLangCode, + Th as store, + Fd as zentao, + ad as zentaoPlugin +}; diff --git a/www/js/zui3/zui.zentao.umd.cjs b/www/js/zui3/zui.zentao.umd.cjs new file mode 100644 index 0000000000..66ec4543b8 --- /dev/null +++ b/www/js/zui3/zui.zentao.umd.cjs @@ -0,0 +1,3 @@ +(function(E,F){typeof exports=="object"&&typeof module<"u"?F(exports):typeof define=="function"&&define.amd?define(["exports"],F):(E=typeof globalThis<"u"?globalThis:E||self,F(E.zui={}))})(this,function(E){var Ft,zt,Fn,xe,ys,sa,Ut,Ge,wt,Vt,or,zn,At,Ke,rr,ue,Ye,Un,Vn,ri,ha,li,fa,Xe,Je,Qe,ci,da,qn,Ze,tn,en,to,Se,nn,qt,ai,pa,ui,ma,hi,Gn,he,Nt,sn,on,eo,Ee,Kn,fe,fi,rn,no,Yn,ln,Xn,Jn,Qn,Lt,cn,so,di,ga,Zn,mr,de,pi,ya,mi,_a,gi,ba,ur,es,yi,_i,bi,wa,ns,wi,ss,vi,hr,is,os,rs,an,io,ls,gr,xi,va,Si,xa,Ei,Ci,$i,ki,Ti,Sa,un,hn,fn,Ce,ut,Ri,cs,as,yr,Ai,Ea,Ni,Ca,Li,$a,Mi,ka,Oi,Ta,Pi,Ra,Di,Aa,dn,Hi,Na,yt,fr,Gt,Ii,La,ji,Ma,Wi,Oa,ke,Te,Bi,Re,pn,pe,Mt,me,nt,vt,Ot,mn,us,hs,Kt,gn,yn,Fi,Pa,zi,Da,Ui,Ha,Vi,Ia,fs,_r,qi,Gi,ds,ps,Ki,Yi,Xi,ja,Ji,Wa,Qi,Ba;"use strict";var _d=Object.defineProperty;var bd=(E,F,Y)=>F in E?_d(E,F,{enumerable:!0,configurable:!0,writable:!0,value:Y}):E[F]=Y;var w=(E,F,Y)=>(bd(E,typeof F!="symbol"?F+"":F,Y),Y),pr=(E,F,Y)=>{if(!F.has(E))throw TypeError("Cannot "+Y)};var m=(E,F,Y)=>(pr(E,F,"read from private field"),Y?Y.call(E):F.get(E)),x=(E,F,Y)=>{if(F.has(E))throw TypeError("Cannot add the same private member more than once");F instanceof WeakSet?F.add(E):F.set(E,Y)},T=(E,F,Y,bn)=>(pr(E,F,"write to private field"),bn?bn.call(E,Y):F.set(E,Y),Y),ua=(E,F,Y,bn)=>({set _(br){T(E,F,br,Y)},get _(){return m(E,F,bn)}}),L=(E,F,Y)=>(pr(E,F,"access private method"),Y);const F="",Y="",bn="",br="",wd="";var wn,U,wr,rt,ge,vr,xr,oo,Sr,_s={},Er=[],Fa=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function Dt(e,n){for(var t in n)e[t]=n[t];return e}function Cr(e){var n=e.parentNode;n&&n.removeChild(e)}function C(e,n,t){var s,i,o,r={};for(o in n)o=="key"?s=n[o]:o=="ref"?i=n[o]:r[o]=n[o];if(arguments.length>2&&(r.children=arguments.length>3?wn.call(arguments,2):t),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)r[o]===void 0&&(r[o]=e.defaultProps[o]);return vn(e,r,s,i,null)}function vn(e,n,t,s,i){var o={type:e,props:n,key:t,ref:s,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:i??++wr};return i==null&&U.vnode!=null&&U.vnode(o),o}function Oe(){return{current:null}}function xn(e){return e.children}function V(e,n){this.props=e,this.context=n}function Sn(e,n){if(n==null)return e.__?Sn(e.__,e.__.__k.indexOf(e)+1):null;for(var t;nn&&ge.sort(oo));bs.__r=0}function kr(e,n,t,s,i,o,r,l,a,h){var c,u,d,f,p,g,y,_=s&&s.__k||Er,v=_.length;for(t.__k=[],c=0;c0?vn(f.type,f.props,f.key,f.ref?f.ref:null,f.__v):f)!=null){if(f.__=t,f.__b=t.__b+1,(d=_[c])===null||d&&f.key==d.key&&f.type===d.type)_[c]=void 0;else for(u=0;u=0;n--)if((t=e.__k[n])&&(s=Nr(t)))return s}return null}function za(e,n,t,s,i){var o;for(o in t)o==="children"||o==="key"||o in n||ws(e,o,null,t[o],s);for(o in n)i&&typeof n[o]!="function"||o==="children"||o==="key"||o==="value"||o==="checked"||t[o]===n[o]||ws(e,o,n[o],t[o],s)}function Lr(e,n,t){n[0]==="-"?e.setProperty(n,t??""):e[n]=t==null?"":typeof t!="number"||Fa.test(n)?t:t+"px"}function ws(e,n,t,s,i){var o;t:if(n==="style")if(typeof t=="string")e.style.cssText=t;else{if(typeof s=="string"&&(e.style.cssText=s=""),s)for(n in s)t&&n in t||Lr(e.style,n,"");if(t)for(n in t)s&&t[n]===s[n]||Lr(e.style,n,t[n])}else if(n[0]==="o"&&n[1]==="n")o=n!==(n=n.replace(/Capture$/,"")),n=n.toLowerCase()in e?n.toLowerCase().slice(2):n.slice(2),e.l||(e.l={}),e.l[n+o]=t,t?s||e.addEventListener(n,o?Or:Mr,o):e.removeEventListener(n,o?Or:Mr,o);else if(n!=="dangerouslySetInnerHTML"){if(i)n=n.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(n!=="width"&&n!=="height"&&n!=="href"&&n!=="list"&&n!=="form"&&n!=="tabIndex"&&n!=="download"&&n in e)try{e[n]=t??"";break t}catch{}typeof t=="function"||(t==null||t===!1&&n[4]!=="-"?e.removeAttribute(n):e.setAttribute(n,t))}}function Mr(e){return this.l[e.type+!1](U.event?U.event(e):e)}function Or(e){return this.l[e.type+!0](U.event?U.event(e):e)}function lo(e,n,t,s,i,o,r,l,a){var h,c,u,d,f,p,g,y,_,v,S,k,N,H,M,P=n.type;if(n.constructor!==void 0)return null;t.__h!=null&&(a=t.__h,l=n.__e=t.__e,n.__h=null,o=[l]),(h=U.__b)&&h(n);try{t:if(typeof P=="function"){if(y=n.props,_=(h=P.contextType)&&s[h.__c],v=h?_?_.props.value:h.__:s,t.__c?g=(c=n.__c=t.__c).__=c.__E:("prototype"in P&&P.prototype.render?n.__c=c=new P(y,v):(n.__c=c=new V(y,v),c.constructor=P,c.render=Va),_&&_.sub(c),c.props=y,c.state||(c.state={}),c.context=v,c.__n=s,u=c.__d=!0,c.__h=[],c._sb=[]),c.__s==null&&(c.__s=c.state),P.getDerivedStateFromProps!=null&&(c.__s==c.state&&(c.__s=Dt({},c.__s)),Dt(c.__s,P.getDerivedStateFromProps(y,c.__s))),d=c.props,f=c.state,c.__v=n,u)P.getDerivedStateFromProps==null&&c.componentWillMount!=null&&c.componentWillMount(),c.componentDidMount!=null&&c.__h.push(c.componentDidMount);else{if(P.getDerivedStateFromProps==null&&y!==d&&c.componentWillReceiveProps!=null&&c.componentWillReceiveProps(y,v),!c.__e&&c.shouldComponentUpdate!=null&&c.shouldComponentUpdate(y,c.__s,v)===!1||n.__v===t.__v){for(n.__v!==t.__v&&(c.props=y,c.state=c.__s,c.__d=!1),c.__e=!1,n.__e=t.__e,n.__k=t.__k,n.__k.forEach(function(R){R&&(R.__=n)}),S=0;S2&&(r.children=arguments.length>3?wn.call(arguments,2):t),vn(e.type,r,s||e.key,i||e.ref,null)}function Ga(e,n){var t={__c:n="__cC"+Sr++,__:e,Consumer:function(s,i){return s.children(i)},Provider:function(s){var i,o;return this.getChildContext||(i=[],(o={})[n]=this,this.getChildContext=function(){return o},this.shouldComponentUpdate=function(r){this.props.value!==r.value&&i.some(function(l){l.__e=!0,ro(l)})},this.sub=function(r){i.push(r);var l=r.componentWillUnmount;r.componentWillUnmount=function(){i.splice(i.indexOf(r),1),l&&l.call(r)}}),s.children}};return t.Provider.__=t.Consumer.contextType=t}wn=Er.slice,U={__e:function(e,n,t,s){for(var i,o,r;n=n.__;)if((i=n.__c)&&!i.__)try{if((o=i.constructor)&&o.getDerivedStateFromError!=null&&(i.setState(o.getDerivedStateFromError(e)),r=i.__d),i.componentDidCatch!=null&&(i.componentDidCatch(e,s||{}),r=i.__d),r)return i.__E=i}catch(l){e=l}throw e}},wr=0,rt=function(e){return e!=null&&e.constructor===void 0},V.prototype.setState=function(e,n){var t;t=this.__s!=null&&this.__s!==this.state?this.__s:this.__s=Dt({},this.state),typeof e=="function"&&(e=e(Dt({},t),this.props)),e&&Dt(t,e),e!=null&&this.__v&&(n&&this._sb.push(n),ro(this))},V.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),ro(this))},V.prototype.render=xn,ge=[],xr=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,oo=function(e,n){return e.__v.__b-n.__v.__b},bs.__r=0,Sr=0;const Ka=Object.freeze(Object.defineProperty({__proto__:null,Component:V,Fragment:xn,cloneElement:qa,createContext:Ga,createElement:C,createRef:Oe,h:C,hydrate:Ir,get isValidElement(){return rt},get options(){return U},render:En,toChildArray:Rr},Symbol.toStringTag,{value:"Module"}));var Ya=0;function b(e,n,t,s,i,o){var r,l,a={};for(l in n)l=="ref"?r=n[l]:a[l]=n[l];var h={type:e,props:a,key:t,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:--Ya,__source:i,__self:o};if(typeof e=="function"&&(r=e.defaultProps))for(l in r)a[l]===void 0&&(a[l]=r[l]);return U.vnode&&U.vnode(h),h}class Xa{constructor(n=""){x(this,Ft,void 0);typeof n=="object"?T(this,Ft,n):T(this,Ft,document.appendChild(document.createComment(n)))}on(n,t,s){m(this,Ft).addEventListener(n,t,s)}once(n,t,s){m(this,Ft).addEventListener(n,t,{once:!0,...s})}off(n,t,s){m(this,Ft).removeEventListener(n,t,s)}emit(n){return m(this,Ft).dispatchEvent(n),n}}Ft=new WeakMap;const vs=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);class Cn extends Xa{on(n,t,s){super.on(n,t,s)}off(n,t,s){super.off(n,t,s)}once(n,t,s){super.once(n,t,s)}emit(n,t){return typeof n=="string"&&(vs.has(n)?(n=new Event(n),Object.assign(n,{detail:t})):n=new CustomEvent(n,{detail:t})),super.emit(Cn.createEvent(n,t))}static createEvent(n,t){return typeof n=="string"&&(vs.has(n)?(n=new Event(n),Object.assign(n,{detail:t})):n=new CustomEvent(n,{detail:t})),n}}class jr extends Cn{constructor(t="",s){super(t);x(this,xe);x(this,zt,new Map);x(this,Fn,void 0);T(this,Fn,s==null?void 0:s.customEventSuffix)}on(t,s,i){t=L(this,xe,ys).call(this,t),super.on(t,s,i),m(this,zt).set(s,[t,i])}off(t,s,i){t=L(this,xe,ys).call(this,t),super.off(t,s,i),m(this,zt).delete(s)}once(t,s,i){t=L(this,xe,ys).call(this,t);const o=r=>{s(r),m(this,zt).delete(o)};super.once(t,o,i),m(this,zt).set(o,[t,i])}emit(t,s){return typeof t=="string"&&(t=L(this,xe,ys).call(this,t)),super.emit(t,s)}offAll(){Array.from(m(this,zt).entries()).forEach(([t,[s,i]])=>{super.off(s,t,i)}),m(this,zt).clear()}}zt=new WeakMap,Fn=new WeakMap,xe=new WeakSet,ys=function(t){const s=m(this,Fn);return vs.has(t)||typeof s!="string"||t.endsWith(s)?t:`${t}${s}`};function Ja(e,n){if(e==null)return[e,void 0];typeof n=="string"&&(n=n.split("."));const t=n.join(".");let s=e;const i=[s];for(;typeof s=="object"&&s!==null&&n.length;){let o=n.shift(),r;const l=o.indexOf("[");if(l>0&&l{const i=t[s]??0;e=e.replace(new RegExp(`\\{${s}\\}`,"g"),`${i}`)}),e}for(let t=0;t(e[e.B=1]="B",e[e.KB=1024]="KB",e[e.MB=1048576]="MB",e[e.GB=1073741824]="GB",e[e.TB=1099511627776]="TB",e))(co||{});function Za(e,n=2,t=""){return Number.isNaN(e)?"?KB":(t||(e<1024?t="B":e<1048576?t="KB":e<1073741824?t="MB":e<1099511627776?t="GB":t="TB"),(e/co[t]).toFixed(n)+t)}const tu=e=>{const n=/^[0-9]*(B|KB|MB|GB|TB)$/;e=e.toUpperCase();const t=e.match(n);if(!t)return 0;const s=t[1];return e=e.replace(s,""),Number.parseInt(e,10)*co[s]};let ao=((sa=document.documentElement.getAttribute("lang"))==null?void 0:sa.toLowerCase())??"zh_cn",Qt;function Wr(){return ao}function Br(e){ao=e.toLowerCase()}function Fr(e,n){Qt||(Qt={}),typeof e=="string"&&(e={[e]:n??{}}),Ss(Qt,e)}function Pe(e,n,t,s,i,o){Array.isArray(e)?Qt&&e.unshift(Qt):e=Qt?[Qt,e]:[e],typeof t=="string"&&(o=i,i=s,s=t,t=void 0);const r=i||ao;let l;for(const a of e){if(!a)continue;const h=a[r];if(!h)continue;const c=o&&a===Qt?`${o}.${n}`:n;if(l=Qa(h,c),l!==void 0)break}return l===void 0?s:t?st(l,...Array.isArray(t)?t:[t]):l}Pe.addLang=Fr,Pe.getCode=Wr,Pe.setCode=Br;function eu(e){return Object.fromEntries(Object.entries(e).map(([n,t])=>{if(typeof t=="string")try{t=JSON.parse(t)}catch{}return[n,t]}))}const uo=new Map;class xt{constructor(n,t){x(this,Ut,void 0);x(this,Ge,void 0);x(this,wt,void 0);n=typeof n=="string"?document.querySelector(n):n,this.constructor.EVENTS&&T(this,wt,new jr(n,{customEventSuffix:`.${this.constructor.KEY}`})),T(this,Ut,{...this.constructor.DEFAULT}),this.setOptions({...n instanceof HTMLElement?eu(n.dataset):null,...t}),this.constructor.all.set(n,this),T(this,Ge,n),this.init(),requestAnimationFrame(()=>{this.afterInit(),this.emit("inited",this)})}get options(){return m(this,Ut)}get element(){return m(this,Ge)}get events(){return m(this,wt)}init(){}afterInit(){}setOptions(n){return n&&Object.assign(m(this,Ut),n),m(this,Ut)}render(n){this.setOptions(n)}destroy(){this.constructor.all.delete(m(this,Ge)),m(this,wt)&&(this.emit("destroyed",this),m(this,wt).offAll())}on(n,t,s){var i;(i=m(this,wt))==null||i.on(n,t,s)}once(n,t,s){var i;(i=m(this,wt))==null||i.once(n,t,s)}off(n,t,s){var i;(i=m(this,wt))==null||i.off(n,t,s)}emit(n,t,s){var o;let i=jr.createEvent(n,t);if(s!==!1){const r=s||`on${n[0].toUpperCase()}${n.substring(1)}`,l=m(this,Ut)[r];l&&l(i)===!1&&(i.preventDefault(),i.stopPropagation())}return i=(o=m(this,wt))==null?void 0:o.emit(n,t),i}i18n(n,t,s){return Pe(m(this,Ut).i18n,n,t,s,this.options.lang,this.constructor.NAME)??`{i18n:${n}}`}static get NAME(){throw new Error(`static NAME should be override in class ${this.name}`)}static get KEY(){return`zui.${this.NAME}`}static get all(){const n=this.NAME;if(uo.has(n))return uo.get(n);const t=new Map;return uo.set(n,t),t}static getAll(){return this.all}static get(n){return this.all.get(n)}static ensure(n,t){return this.get(n)||new this(n,t)}}Ut=new WeakMap,Ge=new WeakMap,wt=new WeakMap,w(xt,"EVENTS",!1),w(xt,"DEFAULT",{});class Z extends xt{constructor(){super(...arguments);w(this,"ref",Oe())}get $(){return this.ref.current}init(){requestAnimationFrame(()=>this.render())}destroy(){super.destroy(),this.element.innerHTML=""}render(t){const s=this.constructor.Component;En(b(s,{ref:this.ref,...this.setOptions(t)}),this.element)}}w(Z,"Component");var ho,G,zr,Ur,$n,Vr,qr={},Gr=[],nu=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function Zt(e,n){for(var t in n)e[t]=n[t];return e}function Kr(e){var n=e.parentNode;n&&n.removeChild(e)}function De(e,n,t){var s,i,o,r={};for(o in n)o=="key"?s=n[o]:o=="ref"?i=n[o]:r[o]=n[o];if(arguments.length>2&&(r.children=arguments.length>3?ho.call(arguments,2):t),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)r[o]===void 0&&(r[o]=e.defaultProps[o]);return Es(e,r,s,i,null)}function Es(e,n,t,s,i){var o={type:e,props:n,key:t,ref:s,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:i??++zr};return i==null&&G.vnode!=null&&G.vnode(o),o}function su(){return{current:null}}function fo(e){return e.children}function kn(e,n){this.props=e,this.context=n}function Tn(e,n){if(n==null)return e.__?Tn(e.__,e.__.__k.indexOf(e)+1):null;for(var t;n0?Es(f.type,f.props,f.key,f.ref?f.ref:null,f.__v):f)!=null){if(f.__=t,f.__b=t.__b+1,(d=_[c])===null||d&&f.key==d.key&&f.type===d.type)_[c]=void 0;else for(u=0;u{if(Array.isArray(i)&&(o=i[1],i=i[0]),!i.length)return;const r=t.get(i);typeof r=="number"?n[r][1]=!!o:(t.set(i,n.length),n.push([i,!!o]))};return e.forEach(i=>{typeof i=="function"&&(i=i()),Array.isArray(i)?ks(...i).forEach(s):i&&typeof i=="object"?Object.entries(i).forEach(s):typeof i=="string"&&i.split(" ").forEach(o=>s(o,!0))}),n.sort((i,o)=>(t.get(i[0])||0)-(t.get(o[0])||0))}const O=(...e)=>ks(...e).reduce((n,[t,s])=>(s&&n.push(t),n),[]).join(" "),vd="";function au({component:e="div",className:n,children:t,style:s,attrs:i}){return De(e,{className:O(n),style:s,...i},t)}function rl({component:e="a",className:n,children:t,attrs:s,url:i,disabled:o,active:r,icon:l,text:a,target:h,trailingIcon:c,hint:u,onClick:d,...f}){const p=[typeof l=="string"?pt("i",{class:`icon ${l}`}):l,pt("span",{className:"text",children:a}),typeof t=="function"?t():t,typeof c=="string"?pt("i",{class:`icon ${c}`}):c];return De(e,{className:O(n,{disabled:o,active:r}),title:u,[e==="a"?"href":"data-url"]:i,[e==="a"?"target":"data-target"]:h,onClick:d,...f,...s},...p)}function uu({component:e="div",className:n,text:t,attrs:s,children:i,style:o,onClick:r}){return De(e,{className:O(n),style:o,onClick:r,...s},t,typeof i=="function"?i():i)}function hu({component:e="div",className:n,style:t,space:s,flex:i,attrs:o,onClick:r,children:l}){return De(e,{className:O(n),style:{width:s,height:s,flex:i,...t},onClick:r,...o},l)}function fu(e){const{tag:n,className:t,style:s,renders:i,generateArgs:o=[],generatorThis:r,generators:l,onGenerate:a,onRenderItem:h,...c}=e,u=[t],d={...s},f=[],p=[];return i.forEach(g=>{const y=[];typeof g=="string"&&l&&l[g]&&(g=l[g]),typeof g=="function"?a?y.push(...a.call(r,g,f,...o)):y.push(...g.call(r,f,...o)??[]):y.push(g),y.forEach(_=>{_!=null&&(typeof _=="object"&&!rt(_)&&("html"in _||"__html"in _||"className"in _||"style"in _||"attrs"in _||"children"in _)?_.html?f.push(b("div",{className:O(_.className),style:_.style,dangerouslySetInnerHTML:{__html:_.html},..._.attrs??{}})):_.__html?p.push(_.__html):(_.style&&Object.assign(d,_.style),_.className&&u.push(_.className),_.children&&f.push(_.children),_.attrs&&Object.assign(c,_.attrs)):f.push(_))})}),p.length&&Object.assign(c,{dangerouslySetInnerHTML:{__html:p}}),[{className:O(u),style:d,...c},f]}function po({tag:e="div",...n}){const[t,s]=fu(n);return C(e,t,...s)}function du({type:e,...n}){return pt(po,{...n})}function ll({component:e="div",className:n,children:t,style:s,attrs:i}){return De(e,{className:O(n),style:s,...i},t)}let Ts=(Vt=class extends kn{constructor(){super(...arguments);w(this,"ref",su())}get name(){return this.props.name??this.constructor.NAME}componentDidMount(){this.afterRender(!0)}componentDidUpdate(){this.afterRender(!1)}componentWillUnmount(){var t,s;(s=(t=this.props).beforeDestroy)==null||s.call(t,{menu:this})}afterRender(t){var s,i;(i=(s=this.props).afterRender)==null||i.call(s,{menu:this,firstRender:t})}handleItemClick(t,s,i,o){i&&i.call(o.target,o);const{onClickItem:r}=this.props;r&&r({menu:this,item:t,index:s,event:o})}beforeRender(){var i;const t={...this.props};typeof t.items=="function"&&(t.items=t.items(this));const s=(i=t.beforeRender)==null?void 0:i.call(t,{menu:this,options:t});return s&&Object.assign(t,s),t}getItemRenderProps(t,s,i){const{commonItemProps:o,onClickItem:r}=t,l={key:i,...s};return o&&Object.assign(l,o[s.type||"item"]),(r||s.onClick)&&(l.onClick=this.handleItemClick.bind(this,l,i,s.onClick)),l.className=O(l.className),l}renderItem(t,s,i){const o=this.getItemRenderProps(t,s,i),{itemRender:r}=t;if(r){if(typeof r=="object"){const y=r[s.type||"item"];if(y)return pt(y,{...o})}else if(typeof r=="function"){const y=r.call(this,o,De);if(Ur(y))return y;typeof y=="object"&&Object.assign(o,y)}}const{type:l="item",component:a,key:h=i,rootAttrs:c,rootClass:u,rootStyle:d,rootChildren:f,...p}=o;if(l==="html")return pt("li",{className:O("action-menu-item",`${this.name}-html`,u,p.className),...c,style:d||p.style,dangerouslySetInnerHTML:{__html:p.html}},h);const g=!a||typeof a=="string"?this.constructor.ItemComponents&&this.constructor.ItemComponents[l]||Vt.ItemComponents[l]:a;return Object.assign(p,{type:l,component:typeof a=="string"?a:void 0}),this.renderTypedItem(g,{className:O(u),children:f,style:d,key:h,...c},{...p,type:l,component:typeof a=="string"?a:void 0})}renderTypedItem(t,s,i){const{children:o,className:r,key:l,...a}=s,{activeClass:h="",activeKey:c,activeIcon:u}=this.props,d=u&&c===l?pt("i",{className:`checked icon icon-${u}`}):null,f=c===l;return pt("li",{className:O("action-menu-item",`${this.name}-${i.type}`,r,{[h]:f}),...a,children:[pt(t,{...i}),d,typeof o=="function"?o():o]},l)}render(){const t=this.beforeRender(),{name:s,style:i,commonItemProps:o,className:r,items:l,children:a,itemRender:h,onClickItem:c,beforeRender:u,afterRender:d,beforeDestroy:f,activeClass:p,activeKey:g,...y}=t,_=this.constructor.ROOT_TAG;return pt(_,{class:O(this.name,r),style:i,...y,ref:this.ref,children:[l&&l.map(this.renderItem.bind(this,t)),a]})}},w(Vt,"ItemComponents",{divider:au,item:rl,heading:uu,space:hu,custom:du,basic:ll}),w(Vt,"ROOT_TAG","menu"),w(Vt,"NAME","action-menu"),Vt);class mo extends Z{}w(mo,"NAME","actionmenu"),w(mo,"Component",Ts);function cl({...e}){return pt(rl,{...e})}let al=(or=class extends Ts{constructor(t){super(t);x(this,zn,new Set);x(this,At,void 0);x(this,Ke,(t,s,i)=>{this.toggleNestedMenu(t,s),i.preventDefault()});T(this,At,t.nestedShow===void 0),m(this,At)&&(this.state={nestedShow:t.defaultNestedShow??{}})}get nestedTrigger(){return this.props.nestedTrigger}beforeRender(){const t=super.beforeRender(),{nestedShow:s,nestedTrigger:i,defaultNestedShow:o,controlledMenu:r,...l}=t;return l}renderNestedMenu(t){let{items:s}=t;if(!s||(typeof s=="function"&&(s=s(t,this)),!s.length))return;const i=this.constructor,{name:o,controlledMenu:r,nestedShow:l,beforeDestroy:a,beforeRender:h,itemRender:c,activeClass:u,activeKey:d,onClickItem:f,afterRender:p,commonItemProps:g,activeIcon:y}=this.props;return pt(i,{items:s,name:o,nestedShow:m(this,At)?this.state.nestedShow:l,nestedTrigger:this.nestedTrigger,controlledMenu:r||this,commonItemProps:g,onClickItem:f,afterRender:p,beforeRender:h,beforeDestroy:a,itemRender:c,activeClass:u,activeKey:d,activeIcon:y})}isNestedItem(t){return(!t.type||t.type==="item")&&!!t.items}renderToggleIcon(t,s){}getItemRenderProps(t,s,i){const o=super.getItemRenderProps(t,s,i);if(!this.isNestedItem(o))return o;const r=o.key??i;m(this,zn).add(r);const l=this.isNestedMenuShow(r);if(l&&(o.rootChildren=[o.rootChildren,this.renderNestedMenu(s)],o.component=cl),this.nestedTrigger==="hover")o.rootAttrs={...o.rootAttrs,onMouseEnter:m(this,Ke).bind(this,r,!0),onMouseLeave:m(this,Ke).bind(this,r,!1)};else if(this.nestedTrigger==="click"){const{onClick:h}=o;o.onClick=c=>{m(this,Ke).call(this,r,void 0,c),h==null||h(c)}}const a=this.renderToggleIcon(l,o);return a&&(o.children=[o.children,a]),o.rootClass=[o.rootClass,"has-nested-menu",l?"show":""],o}isNestedMenuShow(t){const s=m(this,At)?this.state.nestedShow:this.props.nestedShow;return s&&typeof s=="object"?s[t]:!!s}toggleNestedMenu(t,s){const{controlledMenu:i}=this.props;if(i)return i.toggleNestedMenu(t,s);if(!m(this,At))return!1;let{nestedShow:o={}}=this.state;if(typeof o=="boolean"&&(o===!0?o=[...m(this,zn).values()].reduce((r,l)=>(r[l]=!0,r),{}):o={}),s===void 0)s=!o[t];else if(!!o[t]==!!s)return!1;return s?o[t]=s:delete o[t],this.setState({nestedShow:{...o}}),!0}showNestedMenu(t){return this.toggleNestedMenu(t,!0)}hideNestedMenu(t){return this.toggleNestedMenu(t,!1)}showAllNestedMenu(){m(this,At)&&this.setState({nestedShow:!0})}hideAllNestedMenu(){m(this,At)&&this.setState({nestedShow:!1})}},zn=new WeakMap,At=new WeakMap,Ke=new WeakMap,w(or,"ItemComponents",{item:cl}),or);class go extends Z{}w(go,"NAME","actionmenunested"),w(go,"Component",al);const xd="",Sd="",Ed="",Cd="";let St=class extends V{render(){const{component:n,type:t,btnType:s,size:i,className:o,children:r,url:l,target:a,disabled:h,active:c,loading:u,loadingIcon:d,loadingText:f,icon:p,text:g,trailingIcon:y,caret:_,square:v,hint:S,...k}=this.props,N=n||(l?"a":"button"),H=g==null||typeof g=="string"&&!g.length||u&&!f,M=_&&H&&!p&&!y&&!r&&!u;return C(N,{className:O("btn",t,o,{"btn-caret":M,disabled:h||u,active:c,loading:u,square:v===void 0?!M&&!r&&H:v},i?`size-${i}`:""),title:S,[N==="a"?"href":"data-url"]:l,[N==="a"?"target":"data-target"]:a,type:N==="button"?s:void 0,...k},u?b("i",{class:`spin icon ${d||"icon-spinner-snake"}`}):typeof p=="string"?b("i",{class:`icon ${p}`}):p,H?null:b("span",{className:"text",children:u?f:g}),u?null:r,u?null:typeof y=="string"?b("i",{class:`icon ${y}`}):y,u?null:_?b("span",{className:typeof _=="string"?`caret-${_}`:"caret"}):null)}};class yo extends Z{}w(yo,"NAME","button"),w(yo,"Component",St);const $d="",kd="",Td="",Rd="",Ad="",Nd="",Ld="",Md="";let te=(rr=class extends al{get nestedTrigger(){return this.props.nestedTrigger||"click"}get menuName(){return"menu-nested"}beforeRender(){const n=super.beforeRender();let{hasIcons:t}=n;return t===void 0&&(t=n.items.some(s=>s.icon)),n.className=O(n.className,this.menuName,{"has-icons":t,"has-nested-items":n.items.some(s=>this.isNestedItem(s)),"menu-popup":n.popup}),n}renderToggleIcon(n){return b("span",{class:`${this.name}-toggle-icon caret-${n?"down":"right"}`})}},w(rr,"NAME","menu"),rr);class _o extends Z{}w(_o,"NAME","menu"),w(_o,"Component",te);const Od="";let Rn=(e=21)=>crypto.getRandomValues(new Uint8Array(e)).reduce((n,t)=>(t&=63,t<36?n+=t.toString(36):t<62?n+=(t-26).toString(36).toUpperCase():t>62?n+="-":n+="_",n),"");const Ht=document,Rs=window,ul=Ht.documentElement,ye=Ht.createElement.bind(Ht),hl=ye("div"),bo=ye("table"),pu=ye("tbody"),fl=ye("tr"),{isArray:As,prototype:dl}=Array,{concat:mu,filter:wo,indexOf:pl,map:ml,push:gu,slice:gl,some:vo,splice:yu}=dl,_u=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,bu=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,wu=/<.+>/,vu=/^\w+$/;function xo(e,n){const t=xu(n);return!e||!t&&!Ie(n)&&!tt(n)?[]:!t&&bu.test(e)?n.getElementsByClassName(e.slice(1).replace(/\\/g,"")):!t&&vu.test(e)?n.getElementsByTagName(e):n.querySelectorAll(e)}class Ns{constructor(n,t){if(!n)return;if(So(n))return n;let s=n;if(lt(n)){const i=(So(t)?t[0]:t)||Ht;if(s=_u.test(n)&&"getElementById"in i?i.getElementById(n.slice(1).replace(/\\/g,"")):wu.test(n)?xl(n):xo(n,i),!s)return}else if(_e(n))return this.ready(n);(s.nodeType||s===Rs)&&(s=[s]),this.length=s.length;for(let i=0,o=this.length;i{for(;n.firstChild;)n.removeChild(n.firstChild)})};function Ls(...e){const n=Eu(e[0])?e.shift():!1,t=e.shift(),s=e.length;if(!t)return{};if(!s)return Ls(n,A,t);for(let i=0;i{tt(o)&&et(t,(r,l)=>{s?n?o.classList.add(l):o.classList.remove(l):o.classList.toggle(l)})})},$.addClass=function(e){return this.toggleClass(e,!0)},$.removeAttr=function(e){const n=Ms(e);return this.each((t,s)=>{tt(s)&&et(n,(i,o)=>{s.removeAttribute(o)})})};function $u(e,n){if(e){if(lt(e)){if(arguments.length<2){if(!this[0]||!tt(this[0]))return;const t=this[0].getAttribute(e);return An(t)?void 0:t}return ht(n)?this:An(n)?this.removeAttr(e):this.each((t,s)=>{tt(s)&&s.setAttribute(e,n)})}for(const t in e)this.attr(t,e[t]);return this}}$.attr=$u,$.removeClass=function(e){return arguments.length?this.toggleClass(e,!1):this.attr("class","")},$.hasClass=function(e){return!!e&&vo.call(this,n=>tt(n)&&n.classList.contains(e))},$.get=function(e){return ht(e)?gl.call(this):(e=Number(e),this[e<0?e+this.length:e])},$.eq=function(e){return A(this.get(e))},$.first=function(){return this.eq(0)},$.last=function(){return this.eq(-1)};function ku(e){return ht(e)?this.get().map(n=>tt(n)||Su(n)?n.textContent:"").join(""):this.each((n,t)=>{tt(t)&&(t.textContent=e)})}$.text=ku;function It(e,n,t){if(!tt(e))return;const s=Rs.getComputedStyle(e,null);return t?s.getPropertyValue(n)||void 0:s[n]||e.style[n]}function Et(e,n){return parseInt(It(e,n),10)||0}function _l(e,n){return Et(e,`border${n?"Left":"Top"}Width`)+Et(e,`padding${n?"Left":"Top"}`)+Et(e,`padding${n?"Right":"Bottom"}`)+Et(e,`border${n?"Right":"Bottom"}Width`)}const Co={};function Tu(e){if(Co[e])return Co[e];const n=ye(e);Ht.body.insertBefore(n,null);const t=It(n,"display");return Ht.body.removeChild(n),Co[e]=t!=="none"?t:"block"}function bl(e){return It(e,"display")==="none"}function wl(e,n){const t=e&&(e.matches||e.webkitMatchesSelector||e.msMatchesSelector);return!!t&&!!n&&t.call(e,n)}function Os(e){return lt(e)?(n,t)=>wl(t,e):_e(e)?e:So(e)?(n,t)=>e.is(t):e?(n,t)=>t===e:()=>!1}$.filter=function(e){const n=Os(e);return A(wo.call(this,(t,s)=>n.call(t,s,t)))};function ee(e,n){return n?e.filter(n):e}$.detach=function(e){return ee(this,e).each((n,t)=>{t.parentNode&&t.parentNode.removeChild(t)}),this};const Ru=/^\s*<(\w+)[^>]*>/,Au=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,vl={"*":hl,tr:pu,td:fl,th:fl,thead:bo,tbody:bo,tfoot:bo};function xl(e){if(!lt(e))return[];if(Au.test(e))return[ye(RegExp.$1)];const n=Ru.test(e)&&RegExp.$1,t=vl[n]||vl["*"];return t.innerHTML=e,A(t.childNodes).detach().get()}A.parseHTML=xl,$.has=function(e){const n=lt(e)?(t,s)=>xo(e,s).length:(t,s)=>s.contains(e);return this.filter(n)},$.not=function(e){const n=Os(e);return this.filter((t,s)=>(!lt(e)||tt(s))&&!n.call(s,t,s))};function jt(e,n,t,s){const i=[],o=_e(n),r=s&&Os(s);for(let l=0,a=e.length;ln.selected&&!n.disabled&&!n.parentNode.disabled),"value"):e.value||""}function Nu(e){return arguments.length?this.each((n,t)=>{const s=t.multiple&&t.options;if(s||Ol.test(t.type)){const i=As(e)?ml.call(e,String):An(e)?[]:[String(e)];s?et(t.options,(o,r)=>{r.selected=i.indexOf(r.value)>=0},!0):t.checked=i.indexOf(t.value)>=0}else t.value=ht(e)||An(e)?"":e}):this[0]&&Sl(this[0])}$.val=Nu,$.is=function(e){const n=Os(e);return vo.call(this,(t,s)=>n.call(t,s,t))},A.guid=1;function Ct(e){return e.length>1?wo.call(e,(n,t,s)=>pl.call(s,n)===t):e}A.unique=Ct,$.add=function(e,n){return A(Ct(this.get().concat(A(e,n).get())))},$.children=function(e){return ee(A(Ct(jt(this,n=>n.children))),e)},$.parent=function(e){return ee(A(Ct(jt(this,"parentNode"))),e)},$.index=function(e){const n=e?A(e)[0]:this[0],t=e?this:A(n).parent().children();return pl.call(t,n)},$.closest=function(e){const n=this.filter(e);if(n.length)return n;const t=this.parent();return t.length?t.closest(e):n},$.siblings=function(e){return ee(A(Ct(jt(this,n=>A(n).parent().children().not(n)))),e)},$.find=function(e){return A(Ct(jt(this,n=>xo(e,n))))};const Lu=/^\s*\s*$/g,Mu=/^$|^module$|\/(java|ecma)script/i,Ou=["type","src","nonce","noModule"];function Pu(e,n){const t=A(e);t.filter("script").add(t.find("script")).each((s,i)=>{if(Mu.test(i.type)&&ul.contains(i)){const o=ye("script");o.text=i.textContent.replace(Lu,""),et(Ou,(r,l)=>{i[l]&&(o[l]=i[l])}),n.head.insertBefore(o,null),n.head.removeChild(o)}})}function Du(e,n,t,s,i){s?e.insertBefore(n,t?e.firstChild:null):e.nodeName==="HTML"?e.parentNode.replaceChild(n,e):e.parentNode.insertBefore(n,t?e:e.nextSibling),i&&Pu(n,e.ownerDocument)}function ne(e,n,t,s,i,o,r,l){return et(e,(a,h)=>{et(A(h),(c,u)=>{et(A(n),(d,f)=>{const p=t?u:f,g=t?f:u,y=t?c:d;Du(p,y?g.cloneNode(!0):g,s,i,!y)},l)},r)},o),n}$.after=function(){return ne(arguments,this,!1,!1,!1,!0,!0)},$.append=function(){return ne(arguments,this,!1,!1,!0)};function Hu(e){if(!arguments.length)return this[0]&&this[0].innerHTML;if(ht(e))return this;const n=/]/.test(e);return this.each((t,s)=>{tt(s)&&(n?A(s).empty().append(e):s.innerHTML=e)})}$.html=Hu,$.appendTo=function(e){return ne(arguments,this,!0,!1,!0)},$.wrapInner=function(e){return this.each((n,t)=>{const s=A(t),i=s.contents();i.length?i.wrapAll(e):s.append(e)})},$.before=function(){return ne(arguments,this,!1,!0)},$.wrapAll=function(e){let n=A(e),t=n[0];for(;t.children.length;)t=t.firstElementChild;return this.first().before(n),this.appendTo(t)},$.wrap=function(e){return this.each((n,t)=>{const s=A(e)[0];A(t).wrapAll(n?s.cloneNode(!0):s)})},$.insertAfter=function(e){return ne(arguments,this,!0,!1,!1,!1,!1,!0)},$.insertBefore=function(e){return ne(arguments,this,!0,!0)},$.prepend=function(){return ne(arguments,this,!1,!0,!0,!0,!0)},$.prependTo=function(e){return ne(arguments,this,!0,!0,!0,!1,!1,!0)},$.contents=function(){return A(Ct(jt(this,e=>e.tagName==="IFRAME"?[e.contentDocument]:e.tagName==="TEMPLATE"?e.content.childNodes:e.childNodes)))},$.next=function(e,n,t){return ee(A(Ct(jt(this,"nextElementSibling",n,t))),e)},$.nextAll=function(e){return this.next(e,!0)},$.nextUntil=function(e,n){return this.next(n,!0,e)},$.parents=function(e,n){return ee(A(Ct(jt(this,"parentElement",!0,n))),e)},$.parentsUntil=function(e,n){return this.parents(n,e)},$.prev=function(e,n,t){return ee(A(Ct(jt(this,"previousElementSibling",n,t))),e)},$.prevAll=function(e){return this.prev(e,!0)},$.prevUntil=function(e,n){return this.prev(n,!0,e)},$.map=function(e){return A(mu.apply([],ml.call(this,(n,t)=>e.call(n,t,n))))},$.clone=function(){return this.map((e,n)=>n.cloneNode(!0))},$.offsetParent=function(){return this.map((e,n)=>{let t=n.offsetParent;for(;t&&It(t,"position")==="static";)t=t.offsetParent;return t||ul})},$.slice=function(e,n){return A(gl.call(this,e,n))};const Iu=/-([a-z])/g;function $o(e){return e.replace(Iu,(n,t)=>t.toUpperCase())}$.ready=function(e){const n=()=>setTimeout(e,0,A);return Ht.readyState!=="loading"?n():Ht.addEventListener("DOMContentLoaded",n),this},$.unwrap=function(){return this.parent().each((e,n)=>{if(n.tagName==="BODY")return;const t=A(n);t.replaceWith(t.children())}),this},$.offset=function(){const e=this[0];if(!e)return;const n=e.getBoundingClientRect();return{top:n.top+Rs.pageYOffset,left:n.left+Rs.pageXOffset}},$.position=function(){const e=this[0];if(!e)return;const n=It(e,"position")==="fixed",t=n?e.getBoundingClientRect():this.offset();if(!n){const s=e.ownerDocument;let i=e.offsetParent||s.documentElement;for(;(i===s.body||i===s.documentElement)&&It(i,"position")==="static";)i=i.parentNode;if(i!==e&&tt(i)){const o=A(i).offset();t.top-=o.top+Et(i,"borderTopWidth"),t.left-=o.left+Et(i,"borderLeftWidth")}}return{top:t.top-Et(e,"marginTop"),left:t.left-Et(e,"marginLeft")}};const El={class:"className",contenteditable:"contentEditable",for:"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};$.prop=function(e,n){if(e){if(lt(e))return e=El[e]||e,arguments.length<2?this[0]&&this[0][e]:this.each((t,s)=>{s[e]=n});for(const t in e)this.prop(t,e[t]);return this}},$.removeProp=function(e){return this.each((n,t)=>{delete t[El[e]||e]})};const ju=/^--/;function ko(e){return ju.test(e)}const To={},{style:Wu}=hl,Bu=["webkit","moz","ms"];function Fu(e,n=ko(e)){if(n)return e;if(!To[e]){const t=$o(e),s=`${t[0].toUpperCase()}${t.slice(1)}`,i=`${t} ${Bu.join(`${s} `)}${s}`.split(" ");et(i,(o,r)=>{if(r in Wu)return To[e]=r,!1})}return To[e]}const zu={animationIterationCount:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0};function Cl(e,n,t=ko(e)){return!t&&!zu[e]&&yl(n)?`${n}px`:n}function Uu(e,n){if(lt(e)){const t=ko(e);return e=Fu(e,t),arguments.length<2?this[0]&&It(this[0],e,t):e?(n=Cl(e,n,t),this.each((s,i)=>{tt(i)&&(t?i.style.setProperty(e,n):i.style[e]=n)})):this}for(const t in e)this.css(t,e[t]);return this}$.css=Uu;function $l(e,n){try{return e(n)}catch{return n}}const Vu=/^\s+|\s+$/;function kl(e,n){const t=e.dataset[n]||e.dataset[$o(n)];return Vu.test(t)?t:$l(JSON.parse,t)}function qu(e,n,t){t=$l(JSON.stringify,t),e.dataset[$o(n)]=t}function Gu(e,n){if(!e){if(!this[0])return;const t={};for(const s in this[0].dataset)t[s]=kl(this[0],s);return t}if(lt(e))return arguments.length<2?this[0]&&kl(this[0],e):ht(n)?this:this.each((t,s)=>{qu(s,e,n)});for(const t in e)this.data(t,e[t]);return this}$.data=Gu;function Tl(e,n){const t=e.documentElement;return Math.max(e.body[`scroll${n}`],t[`scroll${n}`],e.body[`offset${n}`],t[`offset${n}`],t[`client${n}`])}et([!0,!1],(e,n)=>{et(["Width","Height"],(t,s)=>{const i=`${n?"outer":"inner"}${s}`;$[i]=function(o){if(this[0])return He(this[0])?n?this[0][`inner${s}`]:this[0].document.documentElement[`client${s}`]:Ie(this[0])?Tl(this[0],s):this[0][`${n?"offset":"client"}${s}`]+(o&&n?Et(this[0],`margin${t?"Top":"Left"}`)+Et(this[0],`margin${t?"Bottom":"Right"}`):0)}})}),et(["Width","Height"],(e,n)=>{const t=n.toLowerCase();$[t]=function(s){if(!this[0])return ht(s)?void 0:this;if(!arguments.length)return He(this[0])?this[0].document.documentElement[`client${n}`]:Ie(this[0])?Tl(this[0],n):this[0].getBoundingClientRect()[t]-_l(this[0],!e);const i=parseInt(s,10);return this.each((o,r)=>{if(!tt(r))return;const l=It(r,"boxSizing");r.style[t]=Cl(t,i+(l==="border-box"?_l(r,!e):0))})}});const Rl="___cd";$.toggle=function(e){return this.each((n,t)=>{if(!tt(t))return;(ht(e)?bl(t):e)?(t.style.display=t[Rl]||"",bl(t)&&(t.style.display=Tu(t.tagName))):(t[Rl]=It(t,"display"),t.style.display="none")})},$.hide=function(){return this.toggle(!1)},$.show=function(){return this.toggle(!0)};const Al="___ce",Ro=".",Ao={focus:"focusin",blur:"focusout"},Nl={mouseenter:"mouseover",mouseleave:"mouseout"},Ku=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function No(e){return Nl[e]||Ao[e]||e}function Lo(e){const n=e.split(Ro);return[n[0],n.slice(1).sort()]}$.trigger=function(e,n){if(lt(e)){const[s,i]=Lo(e),o=No(s);if(!o)return this;const r=Ku.test(o)?"MouseEvents":"HTMLEvents";e=Ht.createEvent(r),e.initEvent(o,!0,!0),e.namespace=i.join(Ro),e.___ot=s}e.___td=n;const t=e.___ot in Ao;return this.each((s,i)=>{t&&_e(i[e.___ot])&&(i[`___i${e.type}`]=!0,i[e.___ot](),i[`___i${e.type}`]=!1),i.dispatchEvent(e)})};function Ll(e){return e[Al]=e[Al]||{}}function Yu(e,n,t,s,i){const o=Ll(e);o[n]=o[n]||[],o[n].push([t,s,i]),e.addEventListener(n,i)}function Ml(e,n){return!n||!vo.call(n,t=>e.indexOf(t)<0)}function Ps(e,n,t,s,i){const o=Ll(e);if(n)o[n]&&(o[n]=o[n].filter(([r,l,a])=>{if(i&&a.guid!==i.guid||!Ml(r,t)||s&&s!==l)return!0;e.removeEventListener(n,a)}));else for(n in o)Ps(e,n,t,s,i)}$.off=function(e,n,t){if(ht(e))this.each((s,i)=>{!tt(i)&&!Ie(i)&&!He(i)||Ps(i)});else if(lt(e))_e(n)&&(t=n,n=""),et(Ms(e),(s,i)=>{const[o,r]=Lo(i),l=No(o);this.each((a,h)=>{!tt(h)&&!Ie(h)&&!He(h)||Ps(h,l,r,n,t)})});else for(const s in e)this.off(s,e[s]);return this},$.remove=function(e){return ee(this,e).detach().off(),this},$.replaceWith=function(e){return this.before(e).remove()},$.replaceAll=function(e){return A(e).replaceWith(this),this};function Xu(e,n,t,s,i){if(!lt(e)){for(const o in e)this.on(o,n,t,e[o],i);return this}return lt(n)||(ht(n)||An(n)?n="":ht(t)?(t=n,n=""):(s=t,t=n,n="")),_e(s)||(s=t,t=void 0),s?(et(Ms(e),(o,r)=>{const[l,a]=Lo(r),h=No(l),c=l in Nl,u=l in Ao;h&&this.each((d,f)=>{if(!tt(f)&&!Ie(f)&&!He(f))return;const p=function(g){if(g.target[`___i${g.type}`])return g.stopImmediatePropagation();if(g.namespace&&!Ml(a,g.namespace.split(Ro))||!n&&(u&&(g.target!==f||g.___ot===h)||c&&g.relatedTarget&&f.contains(g.relatedTarget)))return;let y=f;if(n){let v=g.target;for(;!wl(v,n);)if(v===f||(v=v.parentNode,!v))return;y=v}Object.defineProperty(g,"currentTarget",{configurable:!0,get(){return y}}),Object.defineProperty(g,"delegateTarget",{configurable:!0,get(){return f}}),Object.defineProperty(g,"data",{configurable:!0,get(){return t}});const _=s.call(y,g,g.___td);i&&Ps(f,h,a,n,p),_===!1&&(g.preventDefault(),g.stopPropagation())};p.guid=s.guid=s.guid||A.guid++,Yu(f,h,a,n,p)})}),this):this}$.on=Xu;function Ju(e,n,t,s){return this.on(e,n,t,s,!0)}$.one=Ju;const Qu=/\r?\n/g;function Zu(e,n){return`&${encodeURIComponent(e)}=${encodeURIComponent(n.replace(Qu,`\r +`))}`}const th=/file|reset|submit|button|image/i,Ol=/radio|checkbox/i;$.serialize=function(){let e="";return this.each((n,t)=>{et(t.elements||[t],(s,i)=>{if(i.disabled||!i.name||i.tagName==="FIELDSET"||th.test(i.type)||Ol.test(i.type)&&!i.checked)return;const o=Sl(i);if(!ht(o)){const r=As(o)?o:[o];et(r,(l,a)=>{e+=Zu(i.name,a)})}})}),e.slice(1)},window.$=A;const Pl=A,Pd="",Dd="";function eh({key:e,type:n,btnType:t,...s}){return b(St,{type:t,...s})}const Hd="";function nh(e){return e.button===2}const Id="",jd="",Wd="";function Mo(e){return e.split("-")[1]}function Dl(e){return e==="y"?"height":"width"}function Nn(e){return e.split("-")[0]}function Hl(e){return["top","bottom"].includes(Nn(e))?"x":"y"}function Il(e,n,t){let{reference:s,floating:i}=e;const o=s.x+s.width/2-i.width/2,r=s.y+s.height/2-i.height/2,l=Hl(n),a=Dl(l),h=s[a]/2-i[a]/2,c=l==="x";let u;switch(Nn(n)){case"top":u={x:o,y:s.y-i.height};break;case"bottom":u={x:o,y:s.y+s.height};break;case"right":u={x:s.x+s.width,y:r};break;case"left":u={x:s.x-i.width,y:r};break;default:u={x:s.x,y:s.y}}switch(Mo(n)){case"start":u[l]-=h*(t&&c?-1:1);break;case"end":u[l]+=h*(t&&c?-1:1)}return u}const sh=async(e,n,t)=>{const{placement:s="bottom",strategy:i="absolute",middleware:o=[],platform:r}=t,l=o.filter(Boolean),a=await(r.isRTL==null?void 0:r.isRTL(n));let h=await r.getElementRects({reference:e,floating:n,strategy:i}),{x:c,y:u}=Il(h,s,a),d=s,f={},p=0;for(let g=0;ge.concat(n,n+"-start",n+"-end"),[]);const rh={left:"right",right:"left",bottom:"top",top:"bottom"};function Hs(e){return e.replace(/left|right|bottom|top/g,n=>rh[n])}function lh(e,n,t){t===void 0&&(t=!1);const s=Mo(e),i=Hl(e),o=Dl(i);let r=i==="x"?s===(t?"end":"start")?"right":"left":s==="start"?"bottom":"top";return n.reference[o]>n.floating[o]&&(r=Hs(r)),{main:r,cross:Hs(r)}}const ch={start:"end",end:"start"};function Oo(e){return e.replace(/start|end/g,n=>ch[n])}const jl=function(e){return e===void 0&&(e={}),{name:"flip",options:e,async fn(n){var t;const{placement:s,middlewareData:i,rects:o,initialPlacement:r,platform:l,elements:a}=n,{mainAxis:h=!0,crossAxis:c=!0,fallbackPlacements:u,fallbackStrategy:d="bestFit",fallbackAxisSideDirection:f="none",flipAlignment:p=!0,...g}=e,y=Nn(s),_=Nn(r)===r,v=await(l.isRTL==null?void 0:l.isRTL(a.floating)),S=u||(_||!p?[Hs(r)]:function(W){const D=Hs(W);return[Oo(W),D,Oo(D)]}(r));u||f==="none"||S.push(...function(W,D,K,z){const X=Mo(W);let j=function(J,Pt,Ae){const Ne=["left","right"],Le=["right","left"],Yt=["top","bottom"],_n=["bottom","top"];switch(J){case"top":case"bottom":return Ae?Pt?Le:Ne:Pt?Ne:Le;case"left":case"right":return Pt?Yt:_n;default:return[]}}(Nn(W),K==="start",z);return X&&(j=j.map(J=>J+"-"+X),D&&(j=j.concat(j.map(Oo)))),j}(r,p,f,v));const k=[r,...S],N=await oh(n,g),H=[];let M=((t=i.flip)==null?void 0:t.overflows)||[];if(h&&H.push(N[y]),c){const{main:W,cross:D}=lh(s,o,v);H.push(N[W],N[D])}if(M=[...M,{placement:s,overflows:H}],!H.every(W=>W<=0)){var P;const W=(((P=i.flip)==null?void 0:P.index)||0)+1,D=k[W];if(D)return{data:{index:W,overflows:M},reset:{placement:D}};let K="bottom";switch(d){case"bestFit":{var R;const z=(R=M.map(X=>[X,X.overflows.filter(j=>j>0).reduce((j,J)=>j+J,0)]).sort((X,j)=>X[1]-j[1])[0])==null?void 0:R[0].placement;z&&(K=z);break}case"initialPlacement":K=r}if(s!==K)return{reset:{placement:K}}}return{}}}};function mt(e){var n;return((n=e.ownerDocument)==null?void 0:n.defaultView)||window}function $t(e){return mt(e).getComputedStyle(e)}function se(e){return Bl(e)?(e.nodeName||"").toLowerCase():""}let Is;function Wl(){if(Is)return Is;const e=navigator.userAgentData;return e&&Array.isArray(e.brands)?(Is=e.brands.map(n=>n.brand+"/"+n.version).join(" "),Is):navigator.userAgent}function Wt(e){return e instanceof mt(e).HTMLElement}function _t(e){return e instanceof mt(e).Element}function Bl(e){return e instanceof mt(e).Node}function Fl(e){return typeof ShadowRoot>"u"?!1:e instanceof mt(e).ShadowRoot||e instanceof ShadowRoot}function js(e){const{overflow:n,overflowX:t,overflowY:s,display:i}=$t(e);return/auto|scroll|overlay|hidden|clip/.test(n+s+t)&&!["inline","contents"].includes(i)}function ah(e){return["table","td","th"].includes(se(e))}function Po(e){const n=/firefox/i.test(Wl()),t=$t(e),s=t.backdropFilter||t.WebkitBackdropFilter;return t.transform!=="none"||t.perspective!=="none"||!!s&&s!=="none"||n&&t.willChange==="filter"||n&&!!t.filter&&t.filter!=="none"||["transform","perspective"].some(i=>t.willChange.includes(i))||["paint","layout","strict","content"].some(i=>{const o=t.contain;return o!=null&&o.includes(i)})}function zl(){return!/^((?!chrome|android).)*safari/i.test(Wl())}function Do(e){return["html","body","#document"].includes(se(e))}const Ul=Math.min,Ln=Math.max,Ws=Math.round;function Vl(e){const n=$t(e);let t=parseFloat(n.width),s=parseFloat(n.height);const i=e.offsetWidth,o=e.offsetHeight,r=Ws(t)!==i||Ws(s)!==o;return r&&(t=i,s=o),{width:t,height:s,fallback:r}}function ql(e){return _t(e)?e:e.contextElement}const Gl={x:1,y:1};function je(e){const n=ql(e);if(!Wt(n))return Gl;const t=n.getBoundingClientRect(),{width:s,height:i,fallback:o}=Vl(n);let r=(o?Ws(t.width):t.width)/s,l=(o?Ws(t.height):t.height)/i;return r&&Number.isFinite(r)||(r=1),l&&Number.isFinite(l)||(l=1),{x:r,y:l}}function be(e,n,t,s){var i,o;n===void 0&&(n=!1),t===void 0&&(t=!1);const r=e.getBoundingClientRect(),l=ql(e);let a=Gl;n&&(s?_t(s)&&(a=je(s)):a=je(e));const h=l?mt(l):window,c=!zl()&&t;let u=(r.left+(c&&((i=h.visualViewport)==null?void 0:i.offsetLeft)||0))/a.x,d=(r.top+(c&&((o=h.visualViewport)==null?void 0:o.offsetTop)||0))/a.y,f=r.width/a.x,p=r.height/a.y;if(l){const g=mt(l),y=s&&_t(s)?mt(s):s;let _=g.frameElement;for(;_&&s&&y!==g;){const v=je(_),S=_.getBoundingClientRect(),k=getComputedStyle(_);S.x+=(_.clientLeft+parseFloat(k.paddingLeft))*v.x,S.y+=(_.clientTop+parseFloat(k.paddingTop))*v.y,u*=v.x,d*=v.y,f*=v.x,p*=v.y,u+=S.x,d+=S.y,_=mt(_).frameElement}}return{width:f,height:p,top:d,right:u+f,bottom:d+p,left:u,x:u,y:d}}function ie(e){return((Bl(e)?e.ownerDocument:e.document)||window.document).documentElement}function Bs(e){return _t(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Kl(e){return be(ie(e)).left+Bs(e).scrollLeft}function uh(e,n,t){const s=Wt(n),i=ie(n),o=be(e,!0,t==="fixed",n);let r={scrollLeft:0,scrollTop:0};const l={x:0,y:0};if(s||!s&&t!=="fixed")if((se(n)!=="body"||js(i))&&(r=Bs(n)),Wt(n)){const a=be(n,!0);l.x=a.x+n.clientLeft,l.y=a.y+n.clientTop}else i&&(l.x=Kl(i));return{x:o.left+r.scrollLeft-l.x,y:o.top+r.scrollTop-l.y,width:o.width,height:o.height}}function Mn(e){if(se(e)==="html")return e;const n=e.assignedSlot||e.parentNode||(Fl(e)?e.host:null)||ie(e);return Fl(n)?n.host:n}function Yl(e){return Wt(e)&&$t(e).position!=="fixed"?e.offsetParent:null}function Xl(e){const n=mt(e);let t=Yl(e);for(;t&&ah(t)&&$t(t).position==="static";)t=Yl(t);return t&&(se(t)==="html"||se(t)==="body"&&$t(t).position==="static"&&!Po(t))?n:t||function(s){let i=Mn(s);for(;Wt(i)&&!Do(i);){if(Po(i))return i;i=Mn(i)}return null}(e)||n}function Jl(e){const n=Mn(e);return Do(n)?e.ownerDocument.body:Wt(n)&&js(n)?n:Jl(n)}function On(e,n){var t;n===void 0&&(n=[]);const s=Jl(e),i=s===((t=e.ownerDocument)==null?void 0:t.body),o=mt(s);return i?n.concat(o,o.visualViewport||[],js(s)?s:[]):n.concat(s,On(s))}function Ql(e,n,t){return n==="viewport"?Ds(function(s,i){const o=mt(s),r=ie(s),l=o.visualViewport;let a=r.clientWidth,h=r.clientHeight,c=0,u=0;if(l){a=l.width,h=l.height;const d=zl();(d||!d&&i==="fixed")&&(c=l.offsetLeft,u=l.offsetTop)}return{width:a,height:h,x:c,y:u}}(e,t)):_t(n)?function(s,i){const o=be(s,!0,i==="fixed"),r=o.top+s.clientTop,l=o.left+s.clientLeft,a=Wt(s)?je(s):{x:1,y:1},h=s.clientWidth*a.x,c=s.clientHeight*a.y,u=l*a.x,d=r*a.y;return{top:d,left:u,right:u+h,bottom:d+c,x:u,y:d,width:h,height:c}}(n,t):Ds(function(s){var i;const o=ie(s),r=Bs(s),l=(i=s.ownerDocument)==null?void 0:i.body,a=Ln(o.scrollWidth,o.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),h=Ln(o.scrollHeight,o.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0);let c=-r.scrollLeft+Kl(s);const u=-r.scrollTop;return $t(l||o).direction==="rtl"&&(c+=Ln(o.clientWidth,l?l.clientWidth:0)-a),{width:a,height:h,x:c,y:u}}(ie(e)))}const hh={getClippingRect:function(e){let{element:n,boundary:t,rootBoundary:s,strategy:i}=e;const o=t==="clippingAncestors"?function(h,c){const u=c.get(h);if(u)return u;let d=On(h).filter(y=>_t(y)&&se(y)!=="body"),f=null;const p=$t(h).position==="fixed";let g=p?Mn(h):h;for(;_t(g)&&!Do(g);){const y=$t(g),_=Po(g);(p?_||f:_||y.position!=="static"||!f||!["absolute","fixed"].includes(f.position))?f=y:d=d.filter(v=>v!==g),g=Mn(g)}return c.set(h,d),d}(n,this._c):[].concat(t),r=[...o,s],l=r[0],a=r.reduce((h,c)=>{const u=Ql(n,c,i);return h.top=Ln(u.top,h.top),h.right=Ul(u.right,h.right),h.bottom=Ul(u.bottom,h.bottom),h.left=Ln(u.left,h.left),h},Ql(n,l,i));return{width:a.right-a.left,height:a.bottom-a.top,x:a.left,y:a.top}},convertOffsetParentRelativeRectToViewportRelativeRect:function(e){let{rect:n,offsetParent:t,strategy:s}=e;const i=Wt(t),o=ie(t);if(t===o)return n;let r={scrollLeft:0,scrollTop:0},l={x:1,y:1};const a={x:0,y:0};if((i||!i&&s!=="fixed")&&((se(t)!=="body"||js(o))&&(r=Bs(t)),Wt(t))){const h=be(t);l=je(t),a.x=h.x+t.clientLeft,a.y=h.y+t.clientTop}return{width:n.width*l.x,height:n.height*l.y,x:n.x*l.x-r.scrollLeft*l.x+a.x,y:n.y*l.y-r.scrollTop*l.y+a.y}},isElement:_t,getDimensions:function(e){return Vl(e)},getOffsetParent:Xl,getDocumentElement:ie,getScale:je,async getElementRects(e){let{reference:n,floating:t,strategy:s}=e;const i=this.getOffsetParent||Xl,o=this.getDimensions;return{reference:uh(n,await i(t),s),floating:{x:0,y:0,...await o(t)}}},getClientRects:e=>Array.from(e.getClientRects()),isRTL:e=>$t(e).direction==="rtl"};function fh(e,n,t,s){s===void 0&&(s={});const{ancestorScroll:i=!0,ancestorResize:o=!0,elementResize:r=!0,animationFrame:l=!1}=s,a=i&&!l,h=a||o?[..._t(e)?On(e):e.contextElement?On(e.contextElement):[],...On(n)]:[];h.forEach(f=>{a&&f.addEventListener("scroll",t,{passive:!0}),o&&f.addEventListener("resize",t)});let c,u=null;if(r){let f=!0;u=new ResizeObserver(()=>{f||t(),f=!1}),_t(e)&&!l&&u.observe(e),_t(e)||!e.contextElement||l||u.observe(e.contextElement),u.observe(n)}let d=l?be(e):null;return l&&function f(){const p=be(e);!d||p.x===d.x&&p.y===d.y&&p.width===d.width&&p.height===d.height||t(),d=p,c=requestAnimationFrame(f)}(),t(),()=>{var f;h.forEach(p=>{a&&p.removeEventListener("scroll",t),o&&p.removeEventListener("resize",t)}),(f=u)==null||f.disconnect(),u=null,l&&cancelAnimationFrame(c)}}const Zl=(e,n,t)=>{const s=new Map,i={platform:hh,...t},o={...i.platform,_c:s};return sh(e,n,{...i,platform:o})};let dh=class extends te{get nestedTrigger(){return this.props.nestedTrigger||"hover"}get name(){return"menu"}get menuName(){return"menu-context"}componentWillUnmount(){super.componentWillUnmount()}_getPopperOptions(){return{middleware:[jl()],placement:"right-start"}}_getPopperElement(){var n;return(n=this.ref.current)==null?void 0:n.parentElement}_createPopper(){const n=this._getPopperOptions();this.ref.current&&Zl(this._getPopperElement(),this.ref.current,n).then(({x:t,y:s})=>{Object.assign(this.ref.current.style,{left:`${t}px`,top:`${s}px`,position:"absolute"})})}afterRender(n){super.afterRender(n),this.props.controlledMenu&&this._createPopper()}beforeRender(){const n=super.beforeRender();return n.className=O(n.className,"menu-popup"),n}renderToggleIcon(){return b("span",{class:"contextmenu-toggle-icon caret-right"})}};class ct extends xt{constructor(){super(...arguments);x(this,ri);x(this,li);x(this,ue,void 0);x(this,Ye,void 0);x(this,Un,void 0);w(this,"arrowEl");x(this,Vn,void 0)}get isShown(){var t;return(t=m(this,ue))==null?void 0:t.classList.contains(this.constructor.CLASS_SHOW)}get menu(){return m(this,ue)||this._ensureMenu()}get trigger(){return m(this,Un)||this.element}get isDynamic(){return this.options.items||this.options.menu}init(){const{element:t}=this;t!==document.body&&!t.hasAttribute("data-toggle")&&t.setAttribute("data-toggle","contextmenu")}show(t){return T(this,Un,t),this.emit("show",{menu:this,trigger:this.trigger}).defaultPrevented||this.isDynamic&&!this._renderMenu()?!1:(this.menu.classList.add(this.constructor.CLASS_SHOW),this._createPopper(),this.emit("shown",this),!0)}hide(){var s,i;return(s=m(this,Vn))==null||s.call(this),this.emit("hide",this).defaultPrevented?!1:((i=m(this,ue))==null||i.classList.remove(this.constructor.CLASS_SHOW),this.emit("hidden",this),!0)}toggle(t){return this.isShown?this.hide():this.show(t)}destroy(){var t;super.destroy(),(t=m(this,ue))==null||t.remove()}_ensureMenu(){var o;const{element:t}=this,s=this.constructor.MENU_CLASS;let i;if(this.isDynamic)i=document.createElement("div"),i.classList.add(s),document.body.appendChild(i);else if(t){const r=t.getAttribute("href")??t.dataset.target;if((r==null?void 0:r[0])==="#"&&(i=document.querySelector(r)),!i){const l=t.nextElementSibling;l!=null&&l.classList.contains(s)?i=l:i=(o=t.parentNode)==null?void 0:o.querySelector(`.${s}`)}i&&i.classList.add("menu-popup")}if(!i)throw new Error("ContextMenu: Cannot find menu element");return i.style.width="max-content",i.style.position=this.options.strategy,i.style.top="0",i.style.left="0",T(this,ue,i),i}_getPopperOptions(){var o;const{placement:t,strategy:s}=this.options,i={middleware:[],placement:t,strategy:s};return this.options.flip&&((o=i.middleware)==null||o.push(jl())),i}_createPopper(){const t=this._getPopperOptions(),s=this._getPopperElement();T(this,Vn,fh(s,this.menu,()=>{Zl(s,this.menu,t).then(({x:i,y:o,middlewareData:r,placement:l})=>{Object.assign(this.menu.style,{left:`${i}px`,top:`${o}px`});const a=l.split("-")[0],h=L(this,ri,ha).call(this,a);if(r.arrow&&this.arrowEl){const{x:c,y:u}=r.arrow;Object.assign(this.arrowEl.style,{left:c!=null?`${c}px`:"",top:u!=null?`${u}px`:"",[h]:`${-this.arrowEl.offsetWidth/2}px`,background:"inherit",border:"inherit",...L(this,li,fa).call(this,a)})}})}))}_getMenuOptions(){const{menu:t,items:s}=this.options;let i=s||(t==null?void 0:t.items);if(i)return typeof i=="function"&&(i=i(this)),{nestedTrigger:"hover",...t,items:i}}_renderMenu(){const t=this._getMenuOptions();return!t||this.emit("updateMenu",{menu:t,trigger:this.trigger,contextmenu:this}).defaultPrevented?!1:(En(C(dh,t),this.menu),!0)}_getPopperElement(){return m(this,Ye)||T(this,Ye,{getBoundingClientRect:()=>{const{trigger:t}=this;if(t instanceof MouseEvent){const{clientX:s,clientY:i}=t;return{width:0,height:0,top:i,right:s,bottom:i,left:s}}return t instanceof HTMLElement?t.getBoundingClientRect():t},contextElement:this.element}),m(this,Ye)}static clear(t){var a,h;t instanceof Event&&(t={event:t});const{event:s,exclude:i,ignoreSelector:o=".not-hide-menu"}=t||{};if(s&&o&&((h=(a=s.target).closest)!=null&&h.call(a,o))||s&&nh(s))return;const r=this.getAll().entries(),l=new Set(i||[]);for(const[c,u]of r)l.has(c)||u.hide()}static show(t){const{event:s,...i}=t,o=this.ensure(document.body);return Object.keys(i).length&&o.setOptions(i),o.show(s),s instanceof Event&&s.stopPropagation(),o}static hide(){const t=this.get(document.body);return t==null||t.hide(),t}}ue=new WeakMap,Ye=new WeakMap,Un=new WeakMap,Vn=new WeakMap,ri=new WeakSet,ha=function(t){return{top:"bottom",right:"left",bottom:"top",left:"right"}[t]},li=new WeakSet,fa=function(t){return t==="bottom"?{borderBottomStyle:"none",borderRightStyle:"none"}:t==="top"?{borderTopStyle:"none",borderLeftStyle:"none"}:t==="left"?{borderBottomStyle:"none",borderLeftStyle:"none"}:{borderTopStyle:"none",borderRightStyle:"none"}},w(ct,"NAME","contextmenu"),w(ct,"EVENTS",!0),w(ct,"DEFAULT",{placement:"bottom-start",strategy:"fixed",flip:!0,preventOverflow:!0}),w(ct,"MENU_CLASS","contextmenu"),w(ct,"CLASS_SHOW","show"),w(ct,"MENU_SELECTOR",'[data-toggle="contextmenu"]:not(.disabled):not(:disabled)'),document.addEventListener("contextmenu",e=>{var s;const n=e.target;if((s=n.closest)!=null&&s.call(n,`.${ct.MENU_CLASS}`))return;const t=n.closest(ct.MENU_SELECTOR);t&&(ct.ensure(t).show(e),e.preventDefault())}),document.addEventListener("click",ct.clear.bind(ct));const Fd="";function tc(e){return e.split("-")[1]}function ph(e){return e==="y"?"height":"width"}function ec(e){return e.split("-")[0]}function nc(e){return["top","bottom"].includes(ec(e))?"x":"y"}function mh(e){return typeof e!="number"?function(n){return{top:0,right:0,bottom:0,left:0,...n}}(e):{top:e,right:e,bottom:e,left:e}}const gh=Math.min,yh=Math.max;function _h(e,n,t){return yh(e,gh(n,t))}const bh=e=>({name:"arrow",options:e,async fn(n){const{element:t,padding:s=0}=e||{},{x:i,y:o,placement:r,rects:l,platform:a}=n;if(t==null)return{};const h=mh(s),c={x:i,y:o},u=nc(r),d=ph(u),f=await a.getDimensions(t),p=u==="y"?"top":"left",g=u==="y"?"bottom":"right",y=l.reference[d]+l.reference[u]-c[u]-l.floating[d],_=c[u]-l.reference[u],v=await(a.getOffsetParent==null?void 0:a.getOffsetParent(t));let S=v?u==="y"?v.clientHeight||0:v.clientWidth||0:0;S===0&&(S=l.floating[d]);const k=y/2-_/2,N=h[p],H=S-f[d]-h[g],M=S/2-f[d]/2+k,P=_h(N,M,H),R=tc(r)!=null&&M!=P&&l.reference[d]/2-(Me.concat(n,n+"-start",n+"-end"),[]);const wh=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(n){const{x:t,y:s}=n,i=await async function(o,r){const{placement:l,platform:a,elements:h}=o,c=await(a.isRTL==null?void 0:a.isRTL(h.floating)),u=ec(l),d=tc(l),f=nc(l)==="x",p=["left","top"].includes(u)?-1:1,g=c&&f?-1:1,y=typeof r=="function"?r(o):r;let{mainAxis:_,crossAxis:v,alignmentAxis:S}=typeof y=="number"?{mainAxis:y,crossAxis:0,alignmentAxis:null}:{mainAxis:0,crossAxis:0,alignmentAxis:null,...y};return d&&typeof S=="number"&&(v=d==="end"?-1*S:S),f?{x:v*g,y:_*p}:{x:_*p,y:v*g}}(n,e);return{x:t+i.x,y:s+i.y,data:i}}}},lr=class extends ct{constructor(){super(...arguments);x(this,ci);x(this,Xe,!1);x(this,Je,0);w(this,"hideLater",()=>{m(this,Qe).call(this),T(this,Je,window.setTimeout(this.hide.bind(this),100))});x(this,Qe,()=>{clearTimeout(m(this,Je)),T(this,Je,0)})}get isHover(){return this.options.trigger==="hover"}get elementShowClass(){return`with-${this.constructor.NAME}-show`}show(t,s){(s==null?void 0:s.clearOthers)!==!1&&lr.clear({event:s==null?void 0:s.event,exclude:[this.element]});const i=super.show(t);return i&&(!m(this,Xe)&&this.isHover&&L(this,ci,da).call(this),this.element.classList.add(this.elementShowClass)),i}hide(){const t=super.hide();return t&&this.element.classList.remove(this.elementShowClass),t}toggle(t,s){return this.isShown?this.hide():this.show(t,{event:t,...s})}destroy(){m(this,Xe)&&(this.element.removeEventListener("mouseleave",this.hideLater),this.menu.removeEventListener("mouseenter",m(this,Qe)),this.menu.removeEventListener("mouseleave",this.hideLater)),super.destroy()}_getArrowSize(){const{arrow:t}=this.options;return t?typeof t=="number"?t:8:0}_getPopperOptions(){var i,o;const t=super._getPopperOptions(),s=this._getArrowSize();return s&&this.arrowEl&&((i=t.middleware)==null||i.push(wh(s)),(o=t.middleware)==null||o.push(bh({element:this.arrowEl}))),t}_ensureMenu(){const t=super._ensureMenu();if(this.options.arrow){const s=this._getArrowSize();this.arrowEl=document.createElement("div"),this.arrowEl.style.position="absolute",this.arrowEl.style.width=`${s}px`,this.arrowEl.style.height=`${s}px`,this.arrowEl.style.transform="rotate(45deg)",t.append(this.arrowEl)}return t}_getMenuOptions(){const t=super._getMenuOptions();if(t&&this.options.arrow){const{afterRender:s}=t;t.afterRender=(...i)=>{var o;this.arrowEl&&((o=this.menu.querySelector(".menu"))==null||o.appendChild(this.arrowEl)),s==null||s(...i)}}return t}};let it=lr;Xe=new WeakMap,Je=new WeakMap,Qe=new WeakMap,ci=new WeakSet,da=function(){const{menu:t}=this;t.addEventListener("mouseenter",m(this,Qe)),t.addEventListener("mouseleave",this.hideLater),this.element.addEventListener("mouseleave",this.hideLater),T(this,Xe,!0)},w(it,"NAME","dropdown"),w(it,"MENU_CLASS","dropdown-menu"),w(it,"MENU_SELECTOR",'[data-toggle="dropdown"]:not(.disabled):not(:disabled)'),w(it,"DEFAULT",{...ct.DEFAULT,strategy:"fixed",trigger:"click"}),document.addEventListener("click",function(e){var s;const n=e.target,t=(s=n.closest)==null?void 0:s.call(n,it.MENU_SELECTOR);if(t){const i=it.ensure(t);i.options.trigger==="click"&&i.toggle()}else it.clear({event:e})}),document.addEventListener("mouseover",function(e){var i;const n=e.target,t=(i=n.closest)==null?void 0:i.call(n,it.MENU_SELECTOR);if(!t)return;const s=it.ensure(t);s.isHover&&s.show()});const vh=e=>{const n=document.getElementsByClassName("with-dropdown-show")[0];if(!n)return;const t=typeof n.closest=="function"?n.closest(it.MENU_SELECTOR):null;!t||!e.target.contains(t)||it.clear({event:e})};window.addEventListener("scroll",vh,!0);class xh extends V{constructor(t){var s;super(t);x(this,qn,void 0);x(this,Ze,Oe());this.state={placement:((s=t.dropdown)==null?void 0:s.placement)||"",show:!1}}get ref(){return m(this,Ze)}get triggerElement(){return m(this,Ze).current}componentDidMount(){const{modifiers:t=[],...s}=this.props.dropdown||{};t.push({name:"dropdown-trigger",enabled:!0,phase:"beforeMain",fn:({state:i})=>{var r;const o=((r=i.placement)==null?void 0:r.split("-").shift())||"";this.setState({placement:o})}}),T(this,qn,it.ensure(this.triggerElement,{...s,modifiers:t,onShow:()=>{this.setState({show:!0})},onHide:()=>{this.setState({show:!0})}}))}componentWillUnmount(){var t;(t=m(this,qn))==null||t.destroy()}beforeRender(){const{className:t,children:s,dropdown:i,...o}=this.props;return{className:O("dropdown",t),children:typeof s=="function"?s(this.state):s,...o,"data-toggle":"dropdown","data-dropdown-placement":this.state.placement,ref:m(this,Ze)}}render(){const{children:t,...s}=this.beforeRender();return b("div",{...s,children:t})}}qn=new WeakMap,Ze=new WeakMap;class Sh extends xh{get triggerElement(){return this.ref.current.base}render(){var o;const{placement:n,show:t}=this.state,s=this.beforeRender();let{caret:i=!0}=s;if(i!==!1&&(t||i===!0)){const r=t?n:(o=this.props.dropdown)==null?void 0:o.placement;i=(r==="top"?"up":r==="bottom"?"down":r)||(typeof i=="string"?i:"")||"down"}return s.caret=i,b(St,{...s})}}function sc({key:e,type:n,btnType:t,...s}){return b(Sh,{type:t,...s})}const Ud="";let ic=class extends V{componentDidMount(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!0})}componentDidUpdate(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!1})}componentWillUnmount(){var n;(n=this.props.beforeDestroy)==null||n.call(this)}handleItemClick(n,t,s,i){s&&s.call(i.target,i);const{onClickItem:o}=this.props;o&&o.call(this,{item:n,index:t,event:i})}beforeRender(){var s;const n={...this.props},t=(s=n.beforeRender)==null?void 0:s.call(this,n);return t&&Object.assign(n,t),typeof n.items=="function"&&(n.items=n.items.call(this)),n}onRenderItem(n,t){const{key:s=t,...i}=n;return b(St,{...i},s)}renderItem(n,t,s){const{itemRender:i,defaultBtnProps:o,onClickItem:r}=n,l={key:s,...t};if(o&&Object.assign(l,o),r&&(l.onClick=this.handleItemClick.bind(this,l,s,t.onClick)),i){const a=i.call(this,l,C);if(rt(a))return a;typeof a=="object"&&Object.assign(l,a)}return this.onRenderItem(l,s)}render(){const n=this.beforeRender(),{className:t,items:s,size:i,type:o,defaultBtnProps:r,children:l,itemRender:a,onClickItem:h,beforeRender:c,afterRender:u,beforeDestroy:d,...f}=n;return b("div",{className:O("btn-group",i?`size-${i}`:"",t),...f,children:[s&&s.map(this.renderItem.bind(this,n)),l]})}};function Eh({key:e,type:n,btnType:t,...s}){return b(ic,{type:t,...s})}let oe=(tn=class extends Ts{beforeRender(){const{gap:n,btnProps:t,wrap:s,...i}=super.beforeRender();return i.className=O(i.className,s?"flex-wrap":"",typeof n=="number"?`gap-${n}`:""),typeof n=="string"&&(i.style?i.style.gap=n:i.style={gap:n}),i}isBtnItem(n){return n==="item"||n==="dropdown"}renderTypedItem(n,t,s){const i=this.isBtnItem(s.type)?{btnType:"ghost",...this.props.btnProps}:{},o={...t,...i,...s,className:O(`${this.name}-${s.type}`,t.className,i.className,s.className),style:Object.assign({},t.style,i.style,s.style)};return b(n,{...o})}},w(tn,"ItemComponents",{item:eh,dropdown:sc,"btn-group":Eh}),w(tn,"ROOT_TAG","nav"),w(tn,"NAME","toolbar"),w(tn,"defaultProps",{btnProps:{btnType:"ghost"}}),tn);function Ch({className:e,style:n,actions:t,heading:s,content:i,contentClass:o,children:r,close:l,onClose:a,icon:h,...c}){let u;l===!0?u=b(St,{className:"alert-close btn ghost",square:!0,onClick:a,children:b("span",{class:"close"})}):rt(l)?u=l:typeof l=="object"&&(u=b(St,{...l,onClick:a}));const d=rt(t)?t:t?b(oe,{...t}):null;return b("div",{className:O("alert",e),style:n,...c,children:[rt(h)?h:typeof h=="string"?b("i",{className:`icon ${h}`}):null,rt(i)?i:b("div",{className:O("alert-content",o),children:[rt(s)?s:s&&b("div",{className:"alert-heading",children:s}),b("div",{className:"alert-text",children:i}),s?d:null]}),s?null:d,u,r]})}function $h(e){if(e==="center")return"fade-from-center";if(e){if(e.includes("top"))return"fade-from-top";if(e.includes("bottom"))return"fade-from-bottom"}return"fade"}let kh=class extends V{componentDidMount(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!0})}componentDidUpdate(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!1})}componentWillUnmount(){var n;(n=this.props.beforeDestroy)==null||n.call(this)}render(){const{afterRender:n,beforeDestroy:t,margin:s,type:i,placement:o,animation:r,show:l,className:a,time:h,...c}=this.props;return b(Ch,{className:O("messager",a,i,r===!0?$h(o):r,l?"in":""),...c})}};class Fs extends Z{constructor(){super(...arguments);x(this,en);w(this,"_show",!1);w(this,"_showTimer",0);w(this,"_afterRender",({firstRender:t})=>{t&&this.show();const{margin:s}=this.options;s&&(this.element.style.margin=`${s}px`)})}get isShown(){return this._show}afterInit(){this.on("click",t=>{t.target.closest('.alert-close,[data-dismiss="messager"]')&&(t.preventDefault(),t.stopPropagation(),this.hide())})}setOptions(t){return t=super.setOptions(t),{...t,show:this._show,afterRender:this._afterRender}}show(){this._show||(this.emit("show"),this.render(),this._show=!0,L(this,en,to).call(this,()=>{this.emit("shown");const{time:t}=this.options;t&&L(this,en,to).call(this,()=>this.hide(),t)}))}hide(){this._show&&(this._show=!1,this.emit("hide"),this.render(),L(this,en,to).call(this,()=>{this.emit("hidden")}))}}en=new WeakSet,to=function(t,s=200){this._showTimer&&clearTimeout(this._showTimer),this._showTimer=window.setTimeout(()=>{t(),this._showTimer=0},s)},w(Fs,"NAME","MessagerItem"),w(Fs,"EVENTS",!0),w(Fs,"Component",kh);const cr=class extends xt{constructor(){super(...arguments);x(this,ai);x(this,ui);x(this,Se,void 0);x(this,nn,Rn(6));x(this,qt,void 0)}get id(){return m(this,nn)}get isShown(){var t;return!!((t=m(this,qt))!=null&&t.isShown)}show(t){this.setOptions(t),L(this,ai,pa).call(this).show()}hide(){var t;(t=m(this,qt))==null||t.hide()}static show(t){typeof t=="string"&&(t={content:t});const{container:s,...i}=t,o=new cr(s||"body",i);return o.show(),o}};let We=cr;Se=new WeakMap,nn=new WeakMap,qt=new WeakMap,ai=new WeakSet,pa=function(){if(m(this,qt))m(this,qt).setOptions(this.options);else{const t=L(this,ui,ma).call(this),s=new Fs(t,this.options);s.on("hidden",()=>{s.destroy(),t.remove(),T(this,Se,void 0)}),T(this,qt,s)}return m(this,qt)},ui=new WeakSet,ma=function(){if(m(this,Se))return m(this,Se);const{placement:t="top"}=this.options;let s=this.element.querySelector(`.messagers-${t}`);s||(s=document.createElement("div"),s.className=`messagers messagers-${t}`,this.element.appendChild(s));let i=s.querySelector(`#messager-${m(this,nn)}`);return i||(i=document.createElement("div"),i.className="messager-holder",i.id=`messager-${m(this,nn)}`,s.appendChild(i),T(this,Se,i)),i},w(We,"NAME","messager"),w(We,"DEFAULT",{placement:"top",animation:!0,close:!0,margin:6,time:5e3}),A(document).on("zui.messager.show",(e,n)=>{n&&We.show(n)});const Vd="",qd="",Gd="",Kd="";let Th=(hi=class extends V{render(){const{percent:n,circleSize:t,circleBorderSize:s,circleBgColor:i,circleColor:o}=this.props,r=(t-s)/2,l=t/2;return b("svg",{width:t,height:t,class:"progress-circle",children:[b("circle",{cx:l,cy:l,r,stroke:i,"stroke-width":s}),b("circle",{cx:l,cy:l,r,stroke:o,"stroke-dasharray":Math.PI*r*2,"stroke-dashoffset":Math.PI*r*2*(100-n)/100,"stroke-width":s}),b("text",{x:l,y:l+s/4,"dominant-baseline":"middle",style:{fontSize:`${r}px`},children:Math.round(n)})]})}},w(hi,"NAME","zui.progress-circle"),w(hi,"defaultProps",{circleSize:24,circleBorderSize:2,circleBgColor:"var(--progress-circle-bg)",circleColor:"var(--progress-circle-bar-color)"}),hi);class Ho extends Z{}w(Ho,"NAME","table-sorter"),w(Ho,"Component",Th);const Yd="",Xd="";let Rh=class extends V{constructor(){super(...arguments);w(this,"state",{checked:!1});w(this,"handleOnClick",()=>{this.setState({checked:!this.state.checked})})}componentDidMount(){this.setState({checked:this.props.defaultChecked??!1})}render(){const{component:t,className:s,children:i,text:o,icon:r,surffixIcon:l,disabled:a,defaultChecked:h,onChange:c,...u}=this.props,d=this.state.checked?1:0,f=t||"div",p=typeof r=="string"?b("i",{class:`icon ${r}`}):r,g=typeof l=="string"?b("i",{class:`icon ${l}`}):l,y=[b("input",{onChange:c,type:"checkbox",value:d,checked:!!this.state.checked}),b("label",{children:[p,o,g]})];return C(f,{className:O("switch",s,{disabled:a}),onClick:this.handleOnClick,...u},...y,i)}};class Io extends Z{}w(Io,"NAME","switch"),w(Io,"Component",Rh);const Jd="",Qd="",Zd="",tp="",ep="",np="",sp="",ip="";function Ah(e){const n=typeof e=="string"?document.querySelector(e):e;if(!n)return!1;if(n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement)return n.select(),!0;if(window.getSelection){const t=window.getSelection();if(t){const s=document.createRange();return s.selectNodeContents(n),t.removeAllRanges(),t.addRange(s),!0}}return!1}function Nh(e,n){const t=typeof e=="string"?document.querySelector(e):e;if(!t)return!1;const s=t.getBoundingClientRect(),i=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth;if(n!=null&&n.fullyCheck)return s.left>=0&&s.top>=0&&s.left+s.width<=o&&s.top+s.height<=i;const r=s.top<=i&&s.top+s.height>=0,l=s.left<=o&&s.left+s.width>=0;return r&&l}const Lh=Object.freeze(Object.defineProperty({__proto__:null,classes:O,getClassList:ks,isElementVisible:Nh,selectText:Ah},Symbol.toStringTag,{value:"Module"}));/*! js-cookie v3.0.1 | MIT */function zs(e){for(var n=1;n"u")){r=zs({},n,r),typeof r.expires=="number"&&(r.expires=new Date(Date.now()+r.expires*864e5)),r.expires&&(r.expires=r.expires.toUTCString()),i=encodeURIComponent(i).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var l="";for(var a in r)r[a]&&(l+="; "+a,r[a]!==!0&&(l+="="+r[a].split(";")[0]));return document.cookie=i+"="+e.write(o,i)+l}}function s(i){if(!(typeof document>"u"||arguments.length&&!i)){for(var o=document.cookie?document.cookie.split("; "):[],r={},l=0;l=5&&((r||!d&&o===5)&&(a.push(o,0,r,i),o=6),d&&(a.push(o,d,0,i),o=6)),r=""},c=0;c"?(o=1,r=""):r=s+r[0]:l?s===l?l="":r+=s:s==='"'||s==="'"?l=s:s===">"?(h(),o=1):o&&(s==="="?(o=5,i=r,r=""):s==="/"&&(o<5||t[c][u+1]===">")?(h(),o===3&&(a=a[0]),o=a,(a=a[0]).push(2,0,o),o=0):s===" "||s===" "||s===` +`||s==="\r"?(h(),o=2):r+=s),o===3&&r==="!--"&&(o=4,a=a[0])}return h(),a}(e)),n),arguments,[])).length>1?n:n[0]}var Ph=lc.bind(C);Object.assign(window,{htm:lc,html:Ph,preact:Ka});const ar=class{constructor(n,t="local"){x(this,on);x(this,Gn,void 0);x(this,he,void 0);x(this,Nt,void 0);x(this,sn,void 0);T(this,Gn,t),T(this,he,`ZUI_STORE:${n??Rn()}`),T(this,Nt,t==="local"?localStorage:sessionStorage)}get type(){return m(this,Gn)}get session(){return this.type==="session"?this:(m(this,sn)||T(this,sn,new ar(m(this,he),"session")),m(this,sn))}get(n,t){const s=m(this,Nt).getItem(L(this,on,eo).call(this,n));return typeof s=="string"?JSON.parse(s):s??t}set(n,t){if(t==null)return this.remove(n);m(this,Nt).setItem(L(this,on,eo).call(this,n),JSON.stringify(t))}remove(n){m(this,Nt).removeItem(L(this,on,eo).call(this,n))}each(n){for(let t=0;t{n[t]=s}),n}};let Us=ar;Gn=new WeakMap,he=new WeakMap,Nt=new WeakMap,sn=new WeakMap,on=new WeakSet,eo=function(n){return`${m(this,he)}:${n}`};const cc=new Us("DEFAULT");function Dh(e,n="local"){return new Us(e,n)}Object.assign(cc,{create:Dh});const B=Pl,Wo=window.document;let Vs,re;const Hh=/)<[^<]*)*<\/script>/gi,Ih=/^(?:text|application)\/javascript/i,jh=/^(?:text|application)\/xml/i,ac="application/json",uc="text/html",Wh=/^\s*$/,Bo=Wo.createElement("a");Bo.href=window.location.href;function Bh(e,n,t){const s=new CustomEvent(n,{detail:t});return B(e).trigger(s,t),!s.defaultPrevented}function we(e,n,t,s){if(e.global)return Bh(n||Wo,t,s)}B.active=0;function Fh(e){e.global&&B.active++===0&&we(e,null,"ajaxStart")}function zh(e){e.global&&!--B.active&&we(e,null,"ajaxStop")}function Uh(e,n){const t=n.context;if(n.beforeSend.call(t,e,n)===!1||we(n,t,"ajaxBeforeSend",[e,n])===!1)return!1;we(n,t,"ajaxSend",[e,n])}function Vh(e,n,t){const s=t.context,i="success";t.success.call(s,e,i,n),we(t,s,"ajaxSuccess",[n,t,e]),hc(i,n,t)}function qs(e,n,t,s){const i=s.context;s.error.call(i,t,n,e),we(s,i,"ajaxError",[t,s,e||n]),hc(n,t,s)}function hc(e,n,t){const s=t.context;t.complete.call(s,n,e),we(t,s,"ajaxComplete",[n,t]),zh(t)}function qh(e,n,t){if(t.dataFilter==le)return e;const s=t.context;return t.dataFilter.call(s,e,n)}function le(){}B.ajaxSettings={type:"GET",beforeSend:le,success:le,error:le,complete:le,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:ac,xml:"application/xml, text/xml",html:uc,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:le};function Gh(e){return e&&(e=e.split(";",2)[0]),e&&(e==uc?"html":e==ac?"json":Ih.test(e)?"script":jh.test(e)&&"xml")||"text"}function fc(e,n){return n==""?e:(e+"&"+n).replace(/[&?]{1,2}/,"?")}function Kh(e){e.processData&&e.data&&typeof e.data!="string"&&(e.data=B.param(e.data,e.traditional)),e.data&&(!e.type||e.type.toUpperCase()=="GET"||e.dataType=="jsonp")&&(e.url=fc(e.url,e.data),e.data=void 0)}B.ajax=function(e){var p;const n=B.extend({},e||{});let t,s;for(Vs in B.ajaxSettings)n[Vs]===void 0&&(n[Vs]=B.ajaxSettings[Vs]);Fh(n),n.crossDomain||(t=Wo.createElement("a"),t.href=n.url,t.href=t.href,n.crossDomain=Bo.protocol+"//"+Bo.host!=t.protocol+"//"+t.host),n.url||(n.url=window.location.toString()),(s=n.url.indexOf("#"))>-1&&(n.url=n.url.slice(0,s)),Kh(n);let i=n.dataType;/\?.+=\?/.test(n.url)&&(i="jsonp"),(n.cache===!1||(!e||e.cache!==!0)&&(i=="script"||i=="jsonp"))&&(n.url=fc(n.url,"_="+Date.now()));let r=n.accepts[i];const l={},a=function(g,y){l[g.toLowerCase()]=[g,y]},h=/^([\w-]+:)\/\//.test(n.url)?RegExp.$1:window.location.protocol,c=n.xhr(),u=c.setRequestHeader;let d;if(n.crossDomain||a("X-Requested-With","XMLHttpRequest"),a("Accept",r||"*/*"),r=n.mimeType,r&&(r.indexOf(",")>-1&&(r=r.split(",",2)[0]),(p=c.overrideMimeType)==null||p.call(c,r)),(n.contentType||n.contentType!==!1&&n.data&&n.type.toUpperCase()!="GET")&&a("Content-Type",n.contentType||"application/x-www-form-urlencoded"),n.headers)for(re in n.headers)a(re,n.headers[re]);if(c.setRequestHeader=a,c.onreadystatechange=function(){if(c.readyState==4){c.onreadystatechange=le,clearTimeout(d);let g,y=!1;if(c.status>=200&&c.status<300||c.status==304||c.status==0&&h=="file:"){if(i=i||Gh(n.mimeType||c.getResponseHeader("content-type")),c.responseType=="arraybuffer"||c.responseType=="blob")g=c.response;else{g=c.responseText;try{g=qh(g,i,n),i=="xml"?g=c.responseXML:i=="json"&&(g=Wh.test(g)?null:JSON.parse(g))}catch(_){y=_}if(y)return qs(y,"parsererror",c,n)}Vh(g,c,n)}else qs(c.statusText||null,c.status?"error":"abort",c,n)}},Uh(c,n)===!1)return c.abort(),qs(null,"abort",c,n),c;const f="async"in n?n.async:!0;if(c.open(n.type,n.url,f,n.username,n.password),n.xhrFields)for(re in n.xhrFields)c[re]=n.xhrFields[re];for(re in l)u.apply(c,l[re]);return n.timeout>0&&(d=setTimeout(function(){c.onreadystatechange=le,c.abort(),qs(null,"timeout",c,n)},n.timeout)),c.send(n.data?n.data:null),c};function Gs(e,n,t,s){return B.isFunction(n)&&(s=t,t=n,n=void 0),B.isFunction(t)||(s=t,t=void 0),{url:e,data:n,success:t,dataType:s}}B.get=function(e,n,t,s){return B.ajax(Gs(e,n,t,s))},B.post=function(e,n,t,s){const i=Gs(e,n,t,s);return B.ajax(Object.assign(i,{type:"POST"}))},B.getJSON=function(e,n,t,s){const i=Gs(e,n,t,s);return i.dataType="json",B.ajax(i)},B.fn.load=function(e,n,t){if(!this.length)return this;const s=e.split(/\s/);let i;const o=Gs(e,n,t),r=o.success;return s.length>1&&(o.url=s[0],i=s[1]),o.success=(l,...a)=>{this.html(i?B("
    ").html(l.replace(Hh,"")).find(i):l),r==null||r.call(this,l,...a)},B.ajax(o),this};const dc=encodeURIComponent;function pc(e,n,t,s){const i=B.isArray(n),o=B.isPlainObject(n);B.each(n,function(r,l){const a=Array.isArray(l)?"array":typeof l;s&&(r=t?s:s+"["+(o||a=="object"||a=="array"?r:"")+"]"),!s&&i?e.add(l.name,l.value):a=="array"||!t&&a=="object"?pc(e,l,t,r):e.add(r,l)})}B.param=function(e,n){const t=[];return t.add=function(s,i){B.isFunction(i)&&(i=i()),i==null&&(i=""),this.push(dc(s)+"="+dc(i))},pc(t,e,n),t.join("&").replace(/%20/g,"+")};const Yh=Object.assign(B.ajax,{get:B.get,post:B.post,getJSON:B.getJSON,param:B.param,ajaxSettings:B.ajaxSettings}),Xh=new Cn,op="";function Jh(e){if(e.indexOf("#")===0&&(e=e.slice(1)),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),e.length!==6)throw new Error(`Invalid HEX color "${e}".`);return[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16)]}function Qh(e){const[n,t,s]=typeof e=="string"?Jh(e):e;return n*.299+t*.587+s*.114>186}function mc(e,n){return Qh(e)?(n==null?void 0:n.dark)??"#333333":(n==null?void 0:n.light)??"#ffffff"}function gc(e,n=255){return Math.min(Math.max(e,0),n)}function Zh(e,n,t){e=e%360/360,n=gc(n),t=gc(t);const s=t<=.5?t*(n+1):t+n-t*n,i=t*2-s,o=r=>(r=r<0?r+1:r>1?r-1:r,r*6<1?i+(s-i)*r*6:r*2<1?s:r*3<2?i+(s-i)*(2/3-r)*6:i);return[o(e+1/3)*255,o(e)*255,o(e-1/3)*255]}function tf(e){let n=0;if(typeof e!="string"&&(e=String(e)),e&&e.length)for(let t=0;t{e.classList.toggle(s,i)})}function Pn(e,n,t){if(typeof n=="object")return Object.entries(n).forEach(([s,i])=>{Pn(e,s,i)});t!==void 0&&(e.style[n]=typeof t=="number"?`${t}px`:t)}function Ks(e,n,t){if(typeof n=="object")return Object.entries(n).forEach(([s,i])=>{Ks(e,s,i)});t!==void 0&&(t===null?e.removeAttribute(n):e.setAttribute(n,t))}const dt=class extends xt{constructor(){super(...arguments);x(this,rn);x(this,Ee,0);x(this,Kn,void 0);x(this,fe,void 0);x(this,fi,t=>{const s=t.target;(s.closest(dt.DISMISS_SELECTOR)||this.options.backdrop===!0&&!s.closest(".modal-dialog")&&s.closest(".modal"))&&this.hide()})}get modalElement(){return this.element}get isShown(){return this.modalElement.classList.contains(dt.CLASS_SHOW)}get dialog(){return this.modalElement.querySelector(".modal-dialog")}afterInit(){if(this.on("click",m(this,fi)),this.options.responsive&&typeof ResizeObserver<"u"){const{dialog:t}=this;if(t){const s=new ResizeObserver(()=>{if(!this.isShown)return;const i=t.clientWidth,o=t.clientHeight;(!m(this,fe)||m(this,fe)[0]!==i||m(this,fe)[1]!==o)&&(T(this,fe,[i,o]),this.layout())});s.observe(t),T(this,Kn,s)}}this.options.show&&this.show()}destroy(){var t;super.destroy(),(t=m(this,Kn))==null||t.disconnect()}show(t){if(this.isShown)return!1;this.setOptions(t);const{modalElement:s}=this,{animation:i,backdrop:o,className:r,style:l}=this.options;return _c(s,[{"modal-trans":i,"modal-no-backdrop":!o},dt.CLASS_SHOW,r]),Pn(s,{zIndex:`${dt.zIndex++}`,...l}),this.layout(),this.emit("show",this),L(this,rn,no).call(this,()=>{s.classList.add(dt.CLASS_SHOWN),L(this,rn,no).call(this,()=>{this.emit("shown",this)})},50),!0}hide(){return this.isShown?(this.modalElement.classList.remove(dt.CLASS_SHOWN),this.emit("hide",this),L(this,rn,no).call(this,()=>{this.modalElement.classList.remove(dt.CLASS_SHOW),this.emit("hidden",this)}),!0):!1}layout(t,s){if(!this.isShown)return;const{dialog:i}=this;if(!i)return;s=s??this.options.size,Ks(i,"data-size",null);const o={width:null,height:null};typeof s=="object"?(o.width=s.width,o.height=s.height):typeof s=="string"&&["md","sm","lg","full"].includes(s)?Ks(i,"data-size",s):s&&(o.width=s),Pn(i,o),t=t??this.options.position??"fit";const r=i.clientWidth,l=i.clientHeight;T(this,fe,[r,l]),typeof t=="function"&&(t=t({width:r,height:l}));const a={top:null,left:null,bottom:null,right:null,alignSelf:"center"};typeof t=="number"?(a.alignSelf="flex-start",a.top=t):typeof t=="object"&&t?(a.alignSelf="flex-start",Object.assign(a,t)):t==="fit"?(a.alignSelf="flex-start",a.top=`${Math.max(0,Math.floor((window.innerHeight-l)/3))}px`):t==="bottom"?a.alignSelf="flex-end":t==="top"?a.alignSelf="flex-start":t!=="center"&&typeof t=="string"&&(a.alignSelf="flex-start",a.top=t),Pn(i,a),Pn(this.modalElement,"justifyContent",a.left?"flex-start":"center")}static query(t){if(t===void 0?t=document.querySelector(`.modal.${dt.CLASS_SHOW}`):typeof t=="string"&&(t=document.querySelector(t)),!!t)return dt.get(t)}static hide(t){var s;(s=dt.query(t))==null||s.hide()}static show(t){var s;(s=dt.query(t))==null||s.show()}};let ot=dt;Ee=new WeakMap,Kn=new WeakMap,fe=new WeakMap,fi=new WeakMap,rn=new WeakSet,no=function(t,s){m(this,Ee)&&(clearTimeout(m(this,Ee)),T(this,Ee,0)),t&&(this.options.animation?T(this,Ee,window.setTimeout(t,s??this.options.transTime)):t())},w(ot,"NAME","Modal"),w(ot,"EVENTS",!0),w(ot,"DEFAULT",{position:"fit",show:!0,keyboard:!0,animation:!0,backdrop:!0,responsive:!0,transTime:300}),w(ot,"CLASS_SHOW","show"),w(ot,"CLASS_SHOWN","in"),w(ot,"DISMISS_SELECTOR",'[data-dismiss="modal"]'),w(ot,"zIndex",2e3),A(window).on("resize",()=>{ot.all.forEach(e=>{const n=e;n.isShown&&n.options.responsive&&n.layout()})}),A(document).on("zui.modal.hide",(e,n)=>{ot.hide(n==null?void 0:n.target)});class bc extends V{componentDidMount(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!0})}componentDidUpdate(){var n;(n=this.props.afterRender)==null||n.call(this,{firstRender:!1})}componentWillUnmount(){var n;(n=this.props.beforeDestroy)==null||n.call(this)}renderHeader(){const{header:n,title:t}=this.props;return rt(n)?n:n===!1||!t?null:b("div",{className:"modal-header",children:b("div",{className:"modal-title",children:t})})}renderActions(){const{actions:n,closeBtn:t}=this.props;return!t&&!n?null:rt(n)?n:b("div",{className:"modal-actions",children:[n?b(oe,{...n}):null,t?b("button",{type:"button",class:"btn square ghost","data-dismiss":"modal",children:b("span",{class:"close"})}):null]})}renderBody(){const{body:n}=this.props;return n?rt(n)?n:b("div",{className:"modal-body",children:n}):null}renderFooter(){const{footer:n,footerActions:t}=this.props;return rt(n)?n:n===!1||!t?null:b("div",{className:"modal-footer",children:t?b(oe,{...t}):null})}render(){const{className:n,style:t,children:s}=this.props;return b("div",{className:O("modal-dialog",n),style:t,children:b("div",{className:"modal-content",children:[this.renderHeader(),this.renderActions(),this.renderBody(),s,this.renderFooter()]})})}}w(bc,"defaultProps",{closeBtn:!0});class nf extends V{constructor(){super(...arguments);x(this,Yn,Oe());x(this,ln,void 0);w(this,"state",{});x(this,Xn,()=>{var i,o;const t=(o=(i=m(this,Yn).current)==null?void 0:i.contentWindow)==null?void 0:o.document;if(!t)return;let s=m(this,ln);s==null||s.disconnect(),s=new ResizeObserver(()=>{const r=t.body,l=t.documentElement,a=Math.ceil(Math.max(r.scrollHeight,r.offsetHeight,l.offsetHeight));this.setState({height:a})}),s.observe(t.body),s.observe(t.documentElement),T(this,ln,s)})}componentDidMount(){m(this,Xn).call(this)}componentWillUnmount(){var t;(t=m(this,ln))==null||t.disconnect()}render(){const{url:t}=this.props;return b("iframe",{className:"modal-iframe",style:this.state,src:t,ref:m(this,Yn),onLoad:m(this,Xn)})}}Yn=new WeakMap,ln=new WeakMap,Xn=new WeakMap;function sf(e,n){const{custom:t,title:s,content:i}=n;return{body:i,title:s,...typeof t=="function"?t():t}}async function of(e,n){const{dataType:t="html",url:s,request:i,custom:o,title:r,replace:l=!0}=n,h=await(await fetch(s,i)).text();if(t!=="html")try{const c=JSON.parse(h);return{title:r,...o,...c}}catch{}return n.replace!==!1&&t==="html"?[h]:{title:r,...o,body:t==="html"?b("div",{className:"modal-body",dangerouslySetInnerHTML:{__html:h}}):h}}async function rf(e,n){const{url:t,custom:s,title:i}=n;return{title:i,...s,body:b(nf,{url:t})}}const lf={custom:sf,ajax:of,iframe:rf},ts=class extends ot{constructor(){super(...arguments);x(this,cn);x(this,di);x(this,Zn);x(this,Jn,void 0);x(this,Qn,void 0);x(this,Lt,void 0)}get id(){return m(this,Qn)}get loading(){return this.modalElement.classList.contains(ts.LOADING_CLASS)}get modalElement(){let t=m(this,Jn);if(!t){const{id:s}=this;t=this.element.querySelector(`#${s}`),t||(t=document.createElement("div"),Ks(t,{id:s,style:this.options.style}),_c(t,["modal modal-async",this.options.className]),this.element.appendChild(t)),T(this,Jn,t)}return t}afterInit(){super.afterInit(),T(this,Qn,this.options.id||`modal-${Rn()}`)}show(t){return super.show(t)?(this.buildDialog(),!0):!1}render(t){super.render(t),this.buildDialog()}async buildDialog(){if(this.loading)return!1;m(this,Lt)&&clearTimeout(m(this,Lt));const{modalElement:t,options:s}=this,{type:i,loadTimeout:o}=s,r=lf[i];if(!r)return console.warn(`Modal: Cannot build modal with type "${i}"`),!1;t.classList.add(ts.LOADING_CLASS),await L(this,di,ga).call(this),o&&T(this,Lt,window.setTimeout(()=>{T(this,Lt,0),L(this,Zn,mr).call(this,this.options.timeoutTip)},o));const l=await r(t,s);return l===!1?await L(this,Zn,mr).call(this,this.options.failedTip):l&&typeof l=="object"&&await L(this,cn,so).call(this,l),m(this,Lt)&&(clearTimeout(m(this,Lt)),T(this,Lt,0)),t.classList.remove(ts.LOADING_CLASS),!0}};let Dn=ts;Jn=new WeakMap,Qn=new WeakMap,Lt=new WeakMap,cn=new WeakSet,so=function(t){return new Promise(s=>{if(Array.isArray(t))return this.modalElement.innerHTML=t[0],s();const{afterRender:i,...o}=t;t={afterRender:r=>{this.layout(),i==null||i(r),s()},...o},En(b(bc,{...t}),this.modalElement)})},di=new WeakSet,ga=function(){const{loadingText:t}=this.options;return L(this,cn,so).call(this,{body:b("div",{className:"modal-loading-indicator",children:[b("span",{className:"spinner"}),t?b("span",{className:"modal-loading-text",children:t}):null]})})},Zn=new WeakSet,mr=function(t){if(t)return L(this,cn,so).call(this,{body:b("div",{className:"modal-load-failed",children:t})})},w(Dn,"LOADING_CLASS","loading"),w(Dn,"DEFAULT",{...ot.DEFAULT,loadTimeout:1e4});class Be extends xt{constructor(){super(...arguments);x(this,pi);x(this,mi);x(this,gi);x(this,de,void 0)}get modal(){return m(this,de)}get container(){const{container:t}=this.options;return typeof t=="string"?document.querySelector(t):t instanceof HTMLElement?t:document.body}show(){return L(this,mi,_a).call(this).show()}hide(){var t;(t=m(this,de))==null||t.hide()}}de=new WeakMap,pi=new WeakSet,ya=function(){const{container:t,...s}=this.options,i=s,o=this.element.getAttribute("href")||"";return i.type||(i.target||o[0]==="#"?i.type="static":i.type=i.type||(i.url||o?"ajax":"custom")),!i.url&&(i.type==="iframe"||i.type==="ajax")&&o[0]!=="#"&&(i.url=o),i},mi=new WeakSet,_a=function(){const t=L(this,pi,ya).call(this);let s=m(this,de);return s?s.setOptions(t):t.type==="static"?(s=new ot(L(this,gi,ba).call(this),t),T(this,de,s)):(s=new Dn(this.container,t),T(this,de,s)),s},gi=new WeakSet,ba=function(){let t=this.options.target;if(!t){const{element:s}=this;if(s.tagName==="A"){const i=s.getAttribute("href");i!=null&&i.startsWith("#")&&(t=i)}}return this.container.querySelector(t||".modal")},w(Be,"NAME","ModalTrigger"),w(Be,"EVENTS",!0),w(Be,"TOGGLE_SELECTOR",'[data-toggle="modal"]'),window.addEventListener("click",e=>{var s;const n=e.target,t=(s=n.closest)==null?void 0:s.call(n,Be.TOGGLE_SELECTOR);if(t){const i=Be.ensure(t);i&&i.show()}});const cp="";let cf=(ur=class extends Ts{beforeRender(){const n=super.beforeRender();return n.className=O(n.className,n.type?`nav-${n.type}`:"",{"nav-stacked":n.stacked}),n}},w(ur,"NAME","nav"),ur);class Uo extends Z{}w(Uo,"NAME","nav"),w(Uo,"Component",cf);const ap="";function Hn(e,n){const t=e.pageTotal||Math.ceil(e.recTotal/e.recPerPage);return typeof n=="string"&&(n==="first"?n=1:n==="last"?n=t:n==="prev"?n=e.page-1:n==="next"?n=e.page+1:n==="current"?n=e.page:n=Number.parseInt(n,10)),n=n!==void 0?Math.max(1,Math.min(n<0?t+n:n,t)):e.page,{...e,pageTotal:t,page:n}}function af({key:e,type:n,btnType:t,page:s,format:i,pagerInfo:o,linkCreator:r,...l}){const a=Hn(o,s);return l.text===void 0&&!l.icon&&i&&(l.text=typeof i=="function"?i(a):st(i,a)),l.url===void 0&&r&&(l.url=typeof r=="function"?r(a):st(r,a)),l.disabled===void 0&&(l.disabled=s!==void 0&&a.page===o.page),b(St,{type:t,...l})}const kt=24*60*60*1e3,at=e=>e?(e instanceof Date||(typeof e=="string"&&(e=e.trim(),/^\d+$/.test(e)&&(e=Number.parseInt(e,10))),typeof e=="number"&&e<1e10&&(e*=1e3),e=new Date(e)),e):new Date,Fe=(e,n=new Date)=>(e=at(e),n=at(n),e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()&&e.getDate()===n.getDate()),Vo=(e,n=new Date)=>at(e).getFullYear()===at(n).getFullYear(),wc=(e,n=new Date)=>(e=at(e),n=at(n),e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()),uf=(e,n=new Date)=>{e=at(e),n=at(n);const t=1e3*60*60*24,s=Math.floor(e.getTime()/t),i=Math.floor(n.getTime()/t);return Math.floor((s+4)/7)===Math.floor((i+4)/7)},hf=(e,n)=>Fe(at(n),e),ff=(e,n)=>Fe(at(n).getTime()-kt,e),df=(e,n)=>Fe(at(n).getTime()+kt,e),pf=(e,n)=>Fe(at(n).getTime()-2*kt,e),Ys=(e,n="yyyy-MM-dd hh:mm")=>{e=at(e);const t={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"H+":e.getHours()%12,"m+":e.getMinutes(),"s+":e.getSeconds(),"S+":e.getMilliseconds()};return/(y+)/i.test(n)&&(n=n.replace(RegExp.$1,`${e.getFullYear()}`.substring(4-RegExp.$1.length))),Object.keys(t).forEach(s=>{if(new RegExp(`(${s})`).test(n)){const i=`${t[s]}`;n=n.replace(RegExp.$1,RegExp.$1.length===1?i:`00${i}`.substring(i.length))}}),n},mf=(e,n,t)=>{const s={full:"yyyy-M-d",month:"M-d",day:"d",str:"{0} ~ {1}",...t},i=Ys(e,Vo(e)?s.month:s.full);if(Fe(e,n))return i;const o=Ys(n,Vo(e,n)?wc(e,n)?s.day:s.month:s.full);return s.str.replace("{0}",i).replace("{1}",o)},gf=e=>{const n=new Date().getTime();switch(e){case"oneWeek":return n-kt*7;case"oneMonth":return n-kt*31;case"threeMonth":return n-kt*31*3;case"halfYear":return n-kt*183;case"oneYear":return n-kt*365;case"twoYear":return n-2*(kt*365);default:return 0}},qo=(e,n,t=!0,s=Date.now())=>{switch(n){case"year":return e*=365,qo(e,"day",t,s);case"quarter":e*=3;break;case"month":return e*=30,qo(e,"day",t,s);case"week":e*=7;break;case"day":e*=24;break;case"hour":e*=60;break;case"minute":e*=6e4;break;default:e=0}return t?s+e:s-e};function yf({key:e,type:n,page:t,text:s="",pagerInfo:i,children:o,...r}){const l=Hn(i,t);return s=typeof s=="function"?s(l):st(s,l),b(ll,{...r,children:[o,s]})}function _f({key:e,type:n,btnType:t,count:s=12,pagerInfo:i,onClick:o,linkCreator:r,...l}){if(!i.pageTotal)return;const a={...l,square:!0},h=()=>(a.text="",a.icon="icon-ellipsis-h",a.disabled=!0,b(St,{type:t,...a})),c=(d,f)=>{const p=[];for(let g=d;g<=f;g++){a.text=g,delete a.icon,a.disabled=!1;const y=Hn(i,g);r&&(a.url=typeof r=="function"?r(y):st(r,y)),p.push(b(St,{type:t,...a,onClick:o}))}return p};let u=[];return u=[...c(1,1)],i.pageTotal<=1||(i.pageTotal<=s?u=[...u,...c(2,i.pageTotal)]:i.pagei.pageTotal-s+3?u=[...u,h(),...c(i.pageTotal-s+3,i.pageTotal)]:u=[...u,h(),...c(i.page-Math.ceil((s-4)/2),i.page+Math.floor((s-4)/2)),h(),...c(i.pageTotal,i.pageTotal)]),u}function bf({type:e,pagerInfo:n,linkCreator:t,items:s=[5,10,15,20,25,30,35,40,45,50,100,200,500,1e3,2e3],dropdown:i={},...o}){var l;i.items=i.items??s.map(a=>{const h={...n,recPerPage:a};return{text:`${a}`,url:typeof t=="function"?t(h):st(t,h)}});const{text:r=""}=o;return o.text=typeof r=="function"?r(n):st(r,n),i.menu={...i.menu,className:O((l=i.menu)==null?void 0:l.className,"pager-size-menu")},b(sc,{type:"dropdown",dropdown:i,...o})}function wf({key:e,page:n,type:t,btnType:s,pagerInfo:i,size:o,onClick:r,onChange:l,linkCreator:a,...h}){const c={...h};let u;const d=g=>{var y;u=Number((y=g.target)==null?void 0:y.value)||1,u=u>i.pageTotal?i.pageTotal:u},f=g=>{if(!(g!=null&&g.target))return;u=u<=i.pageTotal?u:i.pageTotal;const y=Hn(i,u);l&&!l({info:y,event:g})||(g.target.href=c.url=typeof a=="function"?a(y):st(a,y))},p=Hn(i,n||0);return c.url=typeof a=="function"?a(p):st(a,p),b("div",{className:O("input-group","pager-goto-group",o?`size-${o}`:""),children:[b("input",{type:"number",class:"form-control",max:i.pageTotal,min:"1",onInput:d}),b(St,{type:s,...c,onClick:f})]})}let vc=(es=class extends oe{get pagerInfo(){const{page:n=1,recTotal:t=0,recPerPage:s=10}=this.props;return{page:n,recTotal:t,recPerPage:s,pageTotal:s?Math.ceil(t/s):0}}isBtnItem(n){return n==="link"||n==="nav"||n==="size-menu"||n==="goto"||super.isBtnItem(n)}getItemRenderProps(n,t,s){const i=super.getItemRenderProps(n,t,s),o=t.type||"item";return o==="info"?Object.assign(i,{pagerInfo:this.pagerInfo}):(o==="link"||o==="size-menu"||o==="nav"||o==="goto")&&Object.assign(i,{pagerInfo:this.pagerInfo,linkCreator:n.linkCreator}),i}},w(es,"NAME","pager"),w(es,"defaultProps",{gap:1,btnProps:{btnType:"ghost",size:"sm"}}),w(es,"ItemComponents",{...oe.ItemComponents,link:af,info:yf,nav:_f,"size-menu":bf,goto:wf}),es);class Go extends Z{}w(Go,"NAME","pager"),w(Go,"Component",vc);const up="",hp="";class vf extends V{constructor(){super(...arguments);x(this,yi,t=>{var r;const{onDeselect:s,selections:i}=this.props,o=(r=t.target.closest(".picker-deselect-btn"))==null?void 0:r.dataset.idx;o&&s&&(i!=null&&i.length)&&(t.stopPropagation(),s([i[+o]],t))})}render(){const{className:t,style:s,disabled:i,placeholder:o,focused:r,selections:l=[],onClick:a,children:h}=this.props;let c;return l.length?c=b("div",{className:"picker-multi-selections",children:l.map((u,d)=>b("div",{className:"picker-multi-selection",children:[u.text??u.value,b("div",{className:"picker-deselect-btn btn",onClick:m(this,yi),"data-idx":d,children:b("span",{className:"close"})})]}))}):c=b("span",{className:"picker-select-placeholder",children:o}),b("div",{className:O("picker-select picker-select-multi form-control",t,{disabled:i,focused:r}),style:s,onClick:a,children:[c,h,b("span",{class:"caret"})]})}}yi=new WeakMap;class xf extends V{constructor(){super(...arguments);x(this,_i,t=>{const{onDeselect:s,selections:i}=this.props;s&&(i!=null&&i.length)&&(t.stopPropagation(),s(i,t))})}render(){const{className:t,style:s,disabled:i,placeholder:o,focused:r,selections:l=[],onDeselect:a,onClick:h,children:c}=this.props,[u]=l,d=u?b("span",{className:"picker-single-selection",children:u.text??u.value}):b("span",{className:"picker-select-placeholder",children:o}),f=u&&a?b("button",{type:"button",className:"btn picker-deselect-btn",onClick:m(this,_i),children:b("span",{className:"close"})}):null;return b("div",{className:O("picker-select picker-select-single form-control",t,{disabled:i,focused:r}),style:s,onClick:h,children:[d,c,f,b("span",{class:"caret"})]})}}_i=new WeakMap;const fp="";class Sf extends V{constructor(){super(...arguments);x(this,bi);w(this,"state",{keys:"",shown:!1});x(this,ns,t=>{var s;(s=t.target)!=null&&s.closest(`#picker-menu-${this.props.id}`)||this.hide()});x(this,wi,({item:t})=>{const s=this.props.items.find(i=>i.value===t.key);s&&this.props.onSelectItem(s)});x(this,ss,t=>{this.setState({keys:t.target.value})});x(this,vi,()=>{this.setState({keys:""})})}componentDidMount(){document.addEventListener("click",m(this,ns)),this.show()}componentWillUnmount(){document.removeEventListener("click",m(this,ns))}show(){this.state.shown||this.setState({shown:!0})}hide(){this.state.shown&&this.setState({shown:!1},()=>{window.setTimeout(()=>{var t,s;(s=(t=this.props).onRequestHide)==null||s.call(t)},200)})}render(){const{id:t,search:s,className:i,style:o={},maxHeight:r,maxWidth:l,width:a,menu:h,searchHint:c}=this.props,{shown:u,keys:d}=this.state,f=d.trim().length;return b("div",{className:O("picker-menu",i,{shown:u,"has-search":f}),id:`picker-menu-${t}`,style:{maxHeight:r,maxWidth:l,width:a,...o},children:[s?b("div",{className:"picker-menu-search",children:[b("input",{className:"form-control picker-menu-search-input",type:"text",placeholder:c,value:d,onChange:m(this,ss),onInput:m(this,ss)}),f?b("button",{type:"button",className:"btn picker-menu-search-clear",onClick:m(this,vi),children:b("span",{className:"close"})}):b("span",{className:"magnifier"})]}):null,b(te,{className:"picker-menu-list",items:L(this,bi,wa).call(this),onClickItem:m(this,wi),...h})]})}}bi=new WeakSet,wa=function(){const{selections:t,items:s}=this.props,i=new Set(t),o=this.state.keys.toLowerCase().split(" ").filter(r=>r.length);return s.reduce((r,l)=>{const{value:a,keys:h,text:c,...u}=l;if(!o.length||o.every(d=>a.toLowerCase().includes(d)||(h==null?void 0:h.toLowerCase().includes(d))||typeof c=="string"&&c.toLowerCase().includes(d))){let d=c??a;typeof d=="string"&&o.length&&(d=b("span",{dangerouslySetInnerHTML:{__html:o.reduce((f,p)=>f.replace(p,`${p}`),d)}})),r.push({key:a,active:i.has(a),text:d,...u})}return r},[])},ns=new WeakMap,wi=new WeakMap,ss=new WeakMap,vi=new WeakMap;function xc(e){const n=new Set;return e.reduce((t,s)=>(n.has(s)||(n.add(s),t.push(s)),t),[])}let Ef=(hr=class extends V{constructor(t){super(t);x(this,an);x(this,ls);x(this,xi);x(this,Si);x(this,Ti);x(this,is,0);x(this,os,Rn());x(this,rs,Oe());x(this,Ei,(t,s)=>{const{valueList:i}=this,o=new Set(t.map(l=>l.value)),r=i.filter(l=>!o.has(l));this.setState({value:r.length?r.join(this.props.valueSplitter??","):void 0})});x(this,Ci,t=>{console.log("#handleSelectClick",t),this.setState({open:!0})});x(this,$i,()=>{this.close()});x(this,ki,t=>{this.props.multi?this.toggleValue(t.value):this.setState({value:t.value},()=>{var s;(s=m(this,rs).current)==null||s.hide()})});this.state={value:L(this,xi,va).call(this,t.defaultValue)??"",open:!1,loading:!1,search:"",items:Array.isArray(t.items)?t.items:[]}}get value(){return this.state.value}get valueList(){return L(this,ls,gr).call(this,this.state.value)}componentDidMount(){var t;(t=this.props.afterRender)==null||t.call(this,{firstRender:!0})}componentDidUpdate(){var t;(t=this.props.afterRender)==null||t.call(this,{firstRender:!1})}componentWillUnmount(){var t;(t=this.props.beforeDestroy)==null||t.call(this)}async loadItemList(){let{items:t}=this.props;if(typeof t=="function"){const i=++ua(this,is)._;if(await L(this,an,io).call(this,{loading:!0,items:[]}),t=await t(),m(this,is)!==i)return[]}const s={};return Array.isArray(t)&&this.state.items!==t&&(s.items=t),this.state.loading&&(s.loading=!1),Object.keys(s).length&&await L(this,an,io).call(this,s),t}getItemList(){return this.state.items}getItemMap(){return this.getItemList().reduce((t,s)=>(t[s.value]=s,t),{})}getItemByValue(t){return this.getItemList().find(s=>s.value===t)}getSelections(){const t=this.getItemMap();return this.valueList.map(s=>t[s]||{value:s})}async toggle(t){if(t===void 0)t=!this.state.open;else if(t===this.state.open)return;await L(this,an,io).call(this,{open:t}),t&&this.loadItemList()}open(){return this.toggle(!0)}close(){return this.toggle(!1)}toggleValue(t,s){const{valueList:i}=this,o=i.indexOf(t);s!==!!o&&(o>-1?i.splice(o,1):i.push(t),this.setState({value:i.join(this.props.valueSplitter??",")}))}render(){const{className:t,style:s,children:i,multi:o}=this.props,r=o?vf:xf;return b("div",{className:O("picker",t),style:s,id:`picker-${m(this,os)}`,children:[b(r,{...L(this,Si,xa).call(this)}),i,this.state.open?b(Sf,{...L(this,Ti,Sa).call(this),ref:m(this,rs)}):null]})}},is=new WeakMap,os=new WeakMap,rs=new WeakMap,an=new WeakSet,io=function(t){return new Promise(s=>{this.setState(t,s)})},ls=new WeakSet,gr=function(t){return typeof t=="string"?xc(t.split(this.props.valueSplitter??",")):Array.isArray(t)?xc(t):[]},xi=new WeakSet,va=function(t){const s=L(this,ls,gr).call(this,t);return s.length?s.join(this.props.valueSplitter??","):void 0},Si=new WeakSet,xa=function(){const{placeholder:t,disabled:s}=this.props,{open:i}=this.state;return{focused:i,placeholder:t,disabled:s,selections:this.getSelections(),onClick:m(this,Ci),onDeselect:m(this,Ei)}},Ei=new WeakMap,Ci=new WeakMap,$i=new WeakMap,ki=new WeakMap,Ti=new WeakSet,Sa=function(){const{search:t,menuClass:s,menuWidth:i,menuStyle:o,menuMaxHeight:r,menuMaxWidth:l}=this.props,{items:a}=this.state;return{id:m(this,os),items:a,selections:this.valueList,search:t===!0||typeof t=="number"&&t<=a.length,style:o,className:s,width:i,maxHeight:r,maxWidth:l,onRequestHide:m(this,$i),onSelectItem:m(this,ki)}},w(hr,"defaultProps",{container:"body",valueSplitter:",",search:!0,menuWidth:"auto",menuMaxHeight:400}),hr);class Ko extends Z{}w(Ko,"NAME","picker"),w(Ko,"Component",Ef);const dp="",pp="";class Yo extends Z{}w(Yo,"NAME","toolbar"),w(Yo,"Component",oe);const mp="";function In(e){return e.split("-")[1]}function Xo(e){return e==="y"?"height":"width"}function ze(e){return e.split("-")[0]}function Xs(e){return["top","bottom"].includes(ze(e))?"x":"y"}function Sc(e,n,t){let{reference:s,floating:i}=e;const o=s.x+s.width/2-i.width/2,r=s.y+s.height/2-i.height/2,l=Xs(n),a=Xo(l),h=s[a]/2-i[a]/2,c=l==="x";let u;switch(ze(n)){case"top":u={x:o,y:s.y-i.height};break;case"bottom":u={x:o,y:s.y+s.height};break;case"right":u={x:s.x+s.width,y:r};break;case"left":u={x:s.x-i.width,y:r};break;default:u={x:s.x,y:s.y}}switch(In(n)){case"start":u[l]-=h*(t&&c?-1:1);break;case"end":u[l]+=h*(t&&c?-1:1)}return u}const Cf=async(e,n,t)=>{const{placement:s="bottom",strategy:i="absolute",middleware:o=[],platform:r}=t,l=o.filter(Boolean),a=await(r.isRTL==null?void 0:r.isRTL(n));let h=await r.getElementRects({reference:e,floating:n,strategy:i}),{x:c,y:u}=Sc(h,s,a),d=s,f={},p=0;for(let g=0;g({name:"arrow",options:e,async fn(n){const{element:t,padding:s=0}=e||{},{x:i,y:o,placement:r,rects:l,platform:a}=n;if(t==null)return{};const h=Ec(s),c={x:i,y:o},u=Xs(r),d=Xo(u),f=await a.getDimensions(t),p=u==="y"?"top":"left",g=u==="y"?"bottom":"right",y=l.reference[d]+l.reference[u]-c[u]-l.floating[d],_=c[u]-l.reference[u],v=await(a.getOffsetParent==null?void 0:a.getOffsetParent(t));let S=v?u==="y"?v.clientHeight||0:v.clientWidth||0:0;S===0&&(S=l.floating[d]);const k=y/2-_/2,N=h[p],H=S-f[d]-h[g],M=S/2-f[d]/2+k,P=Rf(N,M,H),R=In(r)!=null&&M!=P&&l.reference[d]/2-(Me.concat(n,n+"-start",n+"-end"),[]);const Nf={left:"right",right:"left",bottom:"top",top:"bottom"};function Qs(e){return e.replace(/left|right|bottom|top/g,n=>Nf[n])}function Lf(e,n,t){t===void 0&&(t=!1);const s=In(e),i=Xs(e),o=Xo(i);let r=i==="x"?s===(t?"end":"start")?"right":"left":s==="start"?"bottom":"top";return n.reference[o]>n.floating[o]&&(r=Qs(r)),{main:r,cross:Qs(r)}}const Mf={start:"end",end:"start"};function Jo(e){return e.replace(/start|end/g,n=>Mf[n])}const Of=function(e){return e===void 0&&(e={}),{name:"flip",options:e,async fn(n){var t;const{placement:s,middlewareData:i,rects:o,initialPlacement:r,platform:l,elements:a}=n,{mainAxis:h=!0,crossAxis:c=!0,fallbackPlacements:u,fallbackStrategy:d="bestFit",fallbackAxisSideDirection:f="none",flipAlignment:p=!0,...g}=e,y=ze(s),_=ze(r)===r,v=await(l.isRTL==null?void 0:l.isRTL(a.floating)),S=u||(_||!p?[Qs(r)]:function(W){const D=Qs(W);return[Jo(W),D,Jo(D)]}(r));u||f==="none"||S.push(...function(W,D,K,z){const X=In(W);let j=function(J,Pt,Ae){const Ne=["left","right"],Le=["right","left"],Yt=["top","bottom"],_n=["bottom","top"];switch(J){case"top":case"bottom":return Ae?Pt?Le:Ne:Pt?Ne:Le;case"left":case"right":return Pt?Yt:_n;default:return[]}}(ze(W),K==="start",z);return X&&(j=j.map(J=>J+"-"+X),D&&(j=j.concat(j.map(Jo)))),j}(r,p,f,v));const k=[r,...S],N=await $f(n,g),H=[];let M=((t=i.flip)==null?void 0:t.overflows)||[];if(h&&H.push(N[y]),c){const{main:W,cross:D}=Lf(s,o,v);H.push(N[W],N[D])}if(M=[...M,{placement:s,overflows:H}],!H.every(W=>W<=0)){var P;const W=(((P=i.flip)==null?void 0:P.index)||0)+1,D=k[W];if(D)return{data:{index:W,overflows:M},reset:{placement:D}};let K="bottom";switch(d){case"bestFit":{var R;const z=(R=M.map(X=>[X,X.overflows.filter(j=>j>0).reduce((j,J)=>j+J,0)]).sort((X,j)=>X[1]-j[1])[0])==null?void 0:R[0].placement;z&&(K=z);break}case"initialPlacement":K=r}if(s!==K)return{reset:{placement:K}}}return{}}}},Pf=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(n){const{x:t,y:s}=n,i=await async function(o,r){const{placement:l,platform:a,elements:h}=o,c=await(a.isRTL==null?void 0:a.isRTL(h.floating)),u=ze(l),d=In(l),f=Xs(l)==="x",p=["left","top"].includes(u)?-1:1,g=c&&f?-1:1,y=typeof r=="function"?r(o):r;let{mainAxis:_,crossAxis:v,alignmentAxis:S}=typeof y=="number"?{mainAxis:y,crossAxis:0,alignmentAxis:null}:{mainAxis:0,crossAxis:0,alignmentAxis:null,...y};return d&&typeof S=="number"&&(v=d==="end"?-1*S:S),f?{x:v*g,y:_*p}:{x:_*p,y:v*g}}(n,e);return{x:t+i.x,y:s+i.y,data:i}}}};function gt(e){var n;return((n=e.ownerDocument)==null?void 0:n.defaultView)||window}function Tt(e){return gt(e).getComputedStyle(e)}function ce(e){return $c(e)?(e.nodeName||"").toLowerCase():""}let Zs;function Cc(){if(Zs)return Zs;const e=navigator.userAgentData;return e&&Array.isArray(e.brands)?(Zs=e.brands.map(n=>n.brand+"/"+n.version).join(" "),Zs):navigator.userAgent}function Bt(e){return e instanceof gt(e).HTMLElement}function bt(e){return e instanceof gt(e).Element}function $c(e){return e instanceof gt(e).Node}function kc(e){return typeof ShadowRoot>"u"?!1:e instanceof gt(e).ShadowRoot||e instanceof ShadowRoot}function ti(e){const{overflow:n,overflowX:t,overflowY:s,display:i}=Tt(e);return/auto|scroll|overlay|hidden|clip/.test(n+s+t)&&!["inline","contents"].includes(i)}function Df(e){return["table","td","th"].includes(ce(e))}function Qo(e){const n=/firefox/i.test(Cc()),t=Tt(e),s=t.backdropFilter||t.WebkitBackdropFilter;return t.transform!=="none"||t.perspective!=="none"||!!s&&s!=="none"||n&&t.willChange==="filter"||n&&!!t.filter&&t.filter!=="none"||["transform","perspective"].some(i=>t.willChange.includes(i))||["paint","layout","strict","content"].some(i=>{const o=t.contain;return o!=null&&o.includes(i)})}function Tc(){return!/^((?!chrome|android).)*safari/i.test(Cc())}function Zo(e){return["html","body","#document"].includes(ce(e))}const Rc=Math.min,jn=Math.max,ei=Math.round;function Ac(e){const n=Tt(e);let t=parseFloat(n.width),s=parseFloat(n.height);const i=e.offsetWidth,o=e.offsetHeight,r=ei(t)!==i||ei(s)!==o;return r&&(t=i,s=o),{width:t,height:s,fallback:r}}function Nc(e){return bt(e)?e:e.contextElement}const Lc={x:1,y:1};function Ue(e){const n=Nc(e);if(!Bt(n))return Lc;const t=n.getBoundingClientRect(),{width:s,height:i,fallback:o}=Ac(n);let r=(o?ei(t.width):t.width)/s,l=(o?ei(t.height):t.height)/i;return r&&Number.isFinite(r)||(r=1),l&&Number.isFinite(l)||(l=1),{x:r,y:l}}function ve(e,n,t,s){var i,o;n===void 0&&(n=!1),t===void 0&&(t=!1);const r=e.getBoundingClientRect(),l=Nc(e);let a=Lc;n&&(s?bt(s)&&(a=Ue(s)):a=Ue(e));const h=l?gt(l):window,c=!Tc()&&t;let u=(r.left+(c&&((i=h.visualViewport)==null?void 0:i.offsetLeft)||0))/a.x,d=(r.top+(c&&((o=h.visualViewport)==null?void 0:o.offsetTop)||0))/a.y,f=r.width/a.x,p=r.height/a.y;if(l){const g=gt(l),y=s&&bt(s)?gt(s):s;let _=g.frameElement;for(;_&&s&&y!==g;){const v=Ue(_),S=_.getBoundingClientRect(),k=getComputedStyle(_);S.x+=(_.clientLeft+parseFloat(k.paddingLeft))*v.x,S.y+=(_.clientTop+parseFloat(k.paddingTop))*v.y,u*=v.x,d*=v.y,f*=v.x,p*=v.y,u+=S.x,d+=S.y,_=gt(_).frameElement}}return{width:f,height:p,top:d,right:u+f,bottom:d+p,left:u,x:u,y:d}}function ae(e){return(($c(e)?e.ownerDocument:e.document)||window.document).documentElement}function ni(e){return bt(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Mc(e){return ve(ae(e)).left+ni(e).scrollLeft}function Hf(e,n,t){const s=Bt(n),i=ae(n),o=ve(e,!0,t==="fixed",n);let r={scrollLeft:0,scrollTop:0};const l={x:0,y:0};if(s||!s&&t!=="fixed")if((ce(n)!=="body"||ti(i))&&(r=ni(n)),Bt(n)){const a=ve(n,!0);l.x=a.x+n.clientLeft,l.y=a.y+n.clientTop}else i&&(l.x=Mc(i));return{x:o.left+r.scrollLeft-l.x,y:o.top+r.scrollTop-l.y,width:o.width,height:o.height}}function Wn(e){if(ce(e)==="html")return e;const n=e.assignedSlot||e.parentNode||(kc(e)?e.host:null)||ae(e);return kc(n)?n.host:n}function Oc(e){return Bt(e)&&Tt(e).position!=="fixed"?e.offsetParent:null}function Pc(e){const n=gt(e);let t=Oc(e);for(;t&&Df(t)&&Tt(t).position==="static";)t=Oc(t);return t&&(ce(t)==="html"||ce(t)==="body"&&Tt(t).position==="static"&&!Qo(t))?n:t||function(s){let i=Wn(s);for(;Bt(i)&&!Zo(i);){if(Qo(i))return i;i=Wn(i)}return null}(e)||n}function Dc(e){const n=Wn(e);return Zo(n)?e.ownerDocument.body:Bt(n)&&ti(n)?n:Dc(n)}function Bn(e,n){var t;n===void 0&&(n=[]);const s=Dc(e),i=s===((t=e.ownerDocument)==null?void 0:t.body),o=gt(s);return i?n.concat(o,o.visualViewport||[],ti(s)?s:[]):n.concat(s,Bn(s))}function Hc(e,n,t){return n==="viewport"?Js(function(s,i){const o=gt(s),r=ae(s),l=o.visualViewport;let a=r.clientWidth,h=r.clientHeight,c=0,u=0;if(l){a=l.width,h=l.height;const d=Tc();(d||!d&&i==="fixed")&&(c=l.offsetLeft,u=l.offsetTop)}return{width:a,height:h,x:c,y:u}}(e,t)):bt(n)?function(s,i){const o=ve(s,!0,i==="fixed"),r=o.top+s.clientTop,l=o.left+s.clientLeft,a=Bt(s)?Ue(s):{x:1,y:1},h=s.clientWidth*a.x,c=s.clientHeight*a.y,u=l*a.x,d=r*a.y;return{top:d,left:u,right:u+h,bottom:d+c,x:u,y:d,width:h,height:c}}(n,t):Js(function(s){var i;const o=ae(s),r=ni(s),l=(i=s.ownerDocument)==null?void 0:i.body,a=jn(o.scrollWidth,o.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),h=jn(o.scrollHeight,o.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0);let c=-r.scrollLeft+Mc(s);const u=-r.scrollTop;return Tt(l||o).direction==="rtl"&&(c+=jn(o.clientWidth,l?l.clientWidth:0)-a),{width:a,height:h,x:c,y:u}}(ae(e)))}const If={getClippingRect:function(e){let{element:n,boundary:t,rootBoundary:s,strategy:i}=e;const o=t==="clippingAncestors"?function(h,c){const u=c.get(h);if(u)return u;let d=Bn(h).filter(y=>bt(y)&&ce(y)!=="body"),f=null;const p=Tt(h).position==="fixed";let g=p?Wn(h):h;for(;bt(g)&&!Zo(g);){const y=Tt(g),_=Qo(g);(p?_||f:_||y.position!=="static"||!f||!["absolute","fixed"].includes(f.position))?f=y:d=d.filter(v=>v!==g),g=Wn(g)}return c.set(h,d),d}(n,this._c):[].concat(t),r=[...o,s],l=r[0],a=r.reduce((h,c)=>{const u=Hc(n,c,i);return h.top=jn(u.top,h.top),h.right=Rc(u.right,h.right),h.bottom=Rc(u.bottom,h.bottom),h.left=jn(u.left,h.left),h},Hc(n,l,i));return{width:a.right-a.left,height:a.bottom-a.top,x:a.left,y:a.top}},convertOffsetParentRelativeRectToViewportRelativeRect:function(e){let{rect:n,offsetParent:t,strategy:s}=e;const i=Bt(t),o=ae(t);if(t===o)return n;let r={scrollLeft:0,scrollTop:0},l={x:1,y:1};const a={x:0,y:0};if((i||!i&&s!=="fixed")&&((ce(t)!=="body"||ti(o))&&(r=ni(t)),Bt(t))){const h=ve(t);l=Ue(t),a.x=h.x+t.clientLeft,a.y=h.y+t.clientTop}return{width:n.width*l.x,height:n.height*l.y,x:n.x*l.x-r.scrollLeft*l.x+a.x,y:n.y*l.y-r.scrollTop*l.y+a.y}},isElement:bt,getDimensions:function(e){return Ac(e)},getOffsetParent:Pc,getDocumentElement:ae,getScale:Ue,async getElementRects(e){let{reference:n,floating:t,strategy:s}=e;const i=this.getOffsetParent||Pc,o=this.getDimensions;return{reference:Hf(n,await i(t),s),floating:{x:0,y:0,...await o(t)}}},getClientRects:e=>Array.from(e.getClientRects()),isRTL:e=>Tt(e).direction==="rtl"};function jf(e,n,t,s){s===void 0&&(s={});const{ancestorScroll:i=!0,ancestorResize:o=!0,elementResize:r=!0,animationFrame:l=!1}=s,a=i&&!l,h=a||o?[...bt(e)?Bn(e):e.contextElement?Bn(e.contextElement):[],...Bn(n)]:[];h.forEach(f=>{a&&f.addEventListener("scroll",t,{passive:!0}),o&&f.addEventListener("resize",t)});let c,u=null;if(r){let f=!0;u=new ResizeObserver(()=>{f||t(),f=!1}),bt(e)&&!l&&u.observe(e),bt(e)||!e.contextElement||l||u.observe(e.contextElement),u.observe(n)}let d=l?ve(e):null;return l&&function f(){const p=ve(e);!d||p.x===d.x&&p.y===d.y&&p.width===d.width&&p.height===d.height||t(),d=p,c=requestAnimationFrame(f)}(),t(),()=>{var f;h.forEach(p=>{a&&p.removeEventListener("scroll",t),o&&p.removeEventListener("resize",t)}),(f=u)==null||f.disconnect(),u=null,l&&cancelAnimationFrame(c)}}const Wf=(e,n,t)=>{const s=new Map,i={platform:If,...t},o={...i.platform,_c:s};return Cf(e,n,{...i,platform:o})},$e=class extends xt{constructor(){super(...arguments);x(this,as);x(this,Ai);x(this,Ni);x(this,Li);x(this,Mi);x(this,Oi);x(this,Pi);x(this,Di);x(this,Hi);x(this,un,!1);x(this,hn,void 0);x(this,fn,0);x(this,Ce,void 0);x(this,ut,void 0);x(this,Ri,void 0);x(this,cs,void 0);w(this,"hideLater",()=>{m(this,dn).call(this),T(this,fn,window.setTimeout(this.hide.bind(this),100))});x(this,dn,()=>{clearTimeout(m(this,fn)),T(this,fn,0)})}get isShown(){var t;return(t=m(this,Ce))==null?void 0:t.classList.contains($e.CLASS_SHOW)}get tooltip(){return m(this,Ce)||L(this,Ni,Ca).call(this)}get trigger(){return m(this,Ri)||this.element}get isHover(){return this.options.trigger==="hover"}get elementShowClass(){return`with-${$e.NAME}-show`}get isDynamic(){return this.options.title}init(){const{element:t}=this;t!==document.body&&!t.hasAttribute("data-toggle")&&t.setAttribute("data-toggle","tooltip")}show(t){return this.setOptions(t),!m(this,un)&&this.isHover&&L(this,Hi,Na).call(this),this.options.animation&&this.tooltip.classList.add("fade"),this.element.classList.add(this.elementShowClass),this.tooltip.classList.add($e.CLASS_SHOW),L(this,Pi,Ra).call(this),!0}hide(){var t,s;return(t=m(this,cs))==null||t.call(this),this.element.classList.remove(this.elementShowClass),(s=m(this,Ce))==null||s.classList.remove($e.CLASS_SHOW),!0}toggle(t){return this.isShown?this.hide():this.show(t)}destroy(){m(this,un)&&(this.element.removeEventListener("mouseleave",this.hideLater),this.tooltip.removeEventListener("mouseenter",m(this,dn)),this.tooltip.removeEventListener("mouseleave",this.hideLater)),super.destroy()}static clear(t){t instanceof Event&&(t={event:t});const{exclude:s}=t||{},i=this.getAll().entries(),o=new Set(s||[]);for(const[r,l]of i)o.has(r)||l.hide()}};let ft=$e;un=new WeakMap,hn=new WeakMap,fn=new WeakMap,Ce=new WeakMap,ut=new WeakMap,Ri=new WeakMap,cs=new WeakMap,as=new WeakSet,yr=function(){const{arrow:t}=this.options;return typeof t=="number"?t:8},Ai=new WeakSet,Ea=function(){const t=L(this,as,yr).call(this);return T(this,ut,document.createElement("div")),m(this,ut).style.position=this.options.strategy,m(this,ut).style.width=`${t}px`,m(this,ut).style.height=`${t}px`,m(this,ut).style.transform="rotate(45deg)",m(this,ut)},Ni=new WeakSet,Ca=function(){var i;const t=$e.TOOLTIP_CLASS;let s;if(this.isDynamic){s=document.createElement("div");const o=this.options.className?this.options.className.split(" "):[];let r=[t,this.options.type||""];r=r.concat(o),s.classList.add(...r),s[this.options.html?"innerHTML":"innerText"]=this.options.title||""}else if(this.element){const o=this.element.getAttribute("href")??this.element.dataset.target;if(o!=null&&o.startsWith("#")&&(s=document.querySelector(o)),!s){const r=this.element.nextElementSibling;r!=null&&r.classList.contains(t)?s=r:s=(i=this.element.parentNode)==null?void 0:i.querySelector(`.${t}`)}}if(this.options.arrow&&(s==null||s.append(L(this,Ai,Ea).call(this))),!s)throw new Error("Tooltip: Cannot find tooltip element");return s.style.width="max-content",s.style.position="absolute",s.style.top="0",s.style.left="0",document.body.appendChild(s),T(this,Ce,s),s},Li=new WeakSet,$a=function(){var r;const t=L(this,as,yr).call(this),{strategy:s,placement:i}=this.options,o={middleware:[Pf(t),Of()],strategy:s,placement:i};return this.options.arrow&&m(this,ut)&&((r=o.middleware)==null||r.push(Af({element:m(this,ut)}))),o},Mi=new WeakSet,ka=function(t){return{top:"bottom",right:"left",bottom:"top",left:"right"}[t]},Oi=new WeakSet,Ta=function(t){return t==="bottom"?{borderBottomStyle:"none",borderRightStyle:"none"}:t==="top"?{borderTopStyle:"none",borderLeftStyle:"none"}:t==="left"?{borderBottomStyle:"none",borderLeftStyle:"none"}:{borderTopStyle:"none",borderRightStyle:"none"}},Pi=new WeakSet,Ra=function(){const t=L(this,Li,$a).call(this),s=L(this,Di,Aa).call(this);T(this,cs,jf(s,this.tooltip,()=>{Wf(s,this.tooltip,t).then(({x:i,y:o,middlewareData:r,placement:l})=>{Object.assign(this.tooltip.style,{left:`${i}px`,top:`${o}px`});const a=l.split("-")[0],h=L(this,Mi,ka).call(this,a);if(r.arrow&&m(this,ut)){const{x:c,y:u}=r.arrow;Object.assign(m(this,ut).style,{left:c!=null?`${c}px`:"",top:u!=null?`${u}px`:"",[h]:`${-m(this,ut).offsetWidth/2}px`,background:"inherit",border:"inherit",...L(this,Oi,Ta).call(this,a)})}})}))},Di=new WeakSet,Aa=function(){return m(this,hn)||T(this,hn,{getBoundingClientRect:()=>{const{element:t}=this;if(t instanceof MouseEvent){const{clientX:s,clientY:i}=t;return{width:0,height:0,top:i,right:s,bottom:i,left:s}}return t instanceof HTMLElement?t.getBoundingClientRect():t},contextElement:this.element}),m(this,hn)},dn=new WeakMap,Hi=new WeakSet,Na=function(){const{tooltip:t}=this;t.addEventListener("mouseenter",m(this,dn)),t.addEventListener("mouseleave",this.hideLater),this.element.addEventListener("mouseleave",this.hideLater),T(this,un,!0)},w(ft,"NAME","tooltip"),w(ft,"TOOLTIP_CLASS","tooltip"),w(ft,"CLASS_SHOW","show"),w(ft,"MENU_SELECTOR",'[data-toggle="tooltip"]:not(.disabled):not(:disabled)'),w(ft,"DEFAULT",{animation:!0,placement:"top",strategy:"absolute",trigger:"hover",type:"darker",arrow:!0}),document.addEventListener("click",function(e){var s;const n=e.target,t=(s=n.closest)==null?void 0:s.call(n,ft.MENU_SELECTOR);if(t){const i=ft.ensure(t);i.options.trigger==="click"&&i.toggle()}else ft.clear({event:e})}),document.addEventListener("mouseover",function(e){var i;const n=e.target,t=(i=n.closest)==null?void 0:i.call(n,ft.MENU_SELECTOR);if(!t)return;const s=ft.ensure(t);s.isHover&&s.show()});let Bf=class extends V{constructor(){super(...arguments);w(this,"handleItemClick",t=>{const{onClickItem:s,changeActiveKey:i}=this.props;s&&s(t);const{item:o}=t;o.items||i&&i(o.key)})}render(){const{items:t,activeClass:s,activeIcon:i,activeKey:o,defaultNestedShow:r=!0,isDropdownMenu:l=!1,...a}=this.props;return C(te,{className:l?"dropdown-menu":"",items:t,activeClass:s,activeKey:o,activeIcon:i,onClickItem:this.handleItemClick,defaultNestedShow:r,...a})}};class tr extends Z{}w(tr,"NAME","MenuTree"),w(tr,"Component",Bf);const yp="";class Ve extends xt{constructor(){super(...arguments);x(this,yt,void 0)}init(){const{element:t}=this;t!==document.body&&!t.hasAttribute("data-toggle")&&t.setAttribute("data-toggle","tab")}showTarget(){const t=this.element.getAttribute("href")||this.element.dataset.target||this.element.dataset.tab;t!=null&&t.startsWith("#")&&T(this,yt,document.querySelector(t)),this.addActive(this.element.closest(`.${this.constructor.NAV_CLASS}`),this.element.parentElement),m(this,yt)&&(this.addActive(m(this,yt).parentElement,m(this,yt)),m(this,yt).dispatchEvent(new CustomEvent("show.zui3.tab")))}show(){const t=this.element.getAttribute("href")||this.element.dataset.target||this.element.dataset.tab;t!=null&&t.startsWith("#")&&T(this,yt,document.querySelector(t)),m(this,yt)&&(this.addActive(m(this,yt).parentElement,m(this,yt)),this.addActive(this.element.closest(`.${this.constructor.NAV_CLASS}`),this.element.parentElement))}addActive(t,s){const i=t.children;Array.from(i).forEach(r=>{r.classList.remove("active"),r.classList.contains("fade")&&r.classList.remove("in")}),s.classList.add("active"),s.classList.contains("fade")&&this.transition(s).then(function(){s.dispatchEvent(new CustomEvent("shown.zui3.tab"))})}transition(t){return new Promise(function(s){setTimeout(()=>{t.classList.add("in"),s()},100)})}}yt=new WeakMap,w(Ve,"NAME","NavTabs"),w(Ve,"NAV_CLASS","nav-tabs"),w(Ve,"EVENTS",!0),w(Ve,"TOGGLE_SELECTOR",'[data-toggle="tab"]'),document.addEventListener("click",e=>{e.target instanceof HTMLElement&&(e.target.dataset.toggle==="tab"||e.target.getAttribute("data-tab"))&&(e.preventDefault(),new Ve(e.target).showTarget())});const _p="";class Ff extends V{constructor(t){super(t);w(this,"handleChange",t=>{this.setState({activeKey:t})});this.state={activeKey:t.activeKey??t.items[0].key}}render(){const{items:t,className:s,contentClass:i}=this.props,{activeKey:o}=this.state;return b("div",{className:O("zui-tabs",s),children:[b("ul",{className:"-flex -items-center",children:t.map(({key:r,label:l,labelCount:a})=>b("li",{className:O("-flex -items-center -gap-3",{active:o===r}),children:b("a",{className:"-flex -h-8 -items-center -justify-center -gap-1 -px-4 -text-inherit",onClick:()=>this.handleChange(r),children:[b("span",{className:O({"text-primary":o===r}),children:l}),o===r?b("span",{className:"label circle gray",children:a}):null]})},r))}),t.map(r=>{const{key:l,content:a,isElm:h}=r;return h?b("div",{dangerouslySetInnerHTML:{__html:a},className:O("-px-3","-py-2",{"-hidden":o!==l})},l):b("div",{className:O(i,{"-hidden":o!==l}),children:a},l)})]})}}class zf extends V{constructor(t){super(t);w(this,"handleChange",t=>{const s=t.target.value;this.setState({value:s});const{onChange:i}=this.props;i&&i(s)});w(this,"handleClear",()=>{this.setState({value:""});const{onChange:t}=this.props;t&&t("")});this.state={value:t.defaultValue??""}}render(){const{type:t="text",icon:s}=this.props,{value:i}=this.state,o=s?b("label",{className:"input-control-prefix",children:b("i",{className:`icon icon-${s}`})}):null;return b("div",{className:"zui-input input-control has-prefix-icon",children:[o,b("input",{className:"form-control",type:t,value:i,onChange:this.handleChange}),b("span",{className:O("-absolute -w-8 -h-8 -right-0 -top-0 -flex -justify-center -items-center -cursor-pointer",{"-hidden":!i}),onClick:this.handleClear,children:b("i",{className:"icon icon-close"})})]})}}let Uf=(fr=class extends V{constructor(t){super(t);w(this,"handleChange",t=>{const{collapse:s}=this.state;this.setState({searchValue:t,collapse:!!t||s})});w(this,"acount",t=>{let s=0;return t.forEach(i=>{var o;s+=((o=i.items)==null?void 0:o.length)||0}),s});w(this,"filter",t=>{const s=[],{searchValue:i}=this.state;return t.forEach(o=>{const r=o.items.filter(l=>l.text.includes(i));r.length>0&&s.push({...o,items:r})}),s});this.state={collapse:!0,searchValue:""}}render(){const{involved:t,others:s,finished:i,involvedText:o,othersText:r,finishedBtnText:l,finishedText:a}=this.props,{collapse:h,searchValue:c}=this.state;return C("div",{className:"quick-menu",style:{width:h?250:500}},C("div",{className:"-p-2"},C(zf,{onChange:this.handleChange,icon:"search"})),C("main",{className:"-flex"},C("div",{className:"-flex -max-h-[350px] -flex-col -pl-2 -py-2",style:{flexBasis:h?"100%":"50%"}},C(Ff,{className:"-flex -flex-col -max-h-full -overflow-hidden -grow",contentClass:"-grow -overflow-y-scroll",activeKey:1,items:[{key:1,label:o,labelCount:this.acount(t),content:C(te,{defaultNestedShow:!0,items:c?this.filter(t):t})},{key:2,label:r,labelCount:this.acount(s),content:C(te,{defaultNestedShow:!0,items:c?this.filter(s):s})}]}),C("div",{onClick:()=>this.setState({collapse:!h}),className:`-py-2 -pr-2 -flex -justify-end -items-center -cursor-pointer ${c?"-hidden":""}`},C("span",null,l),C("i",{className:`icon ${h?"icon-angle-right":"icon-angle-left"}`}))),h||c?null:C("div",{className:"-basis-1/2 -max-h-[350px] -overflow-y-auto -border-l-[1px] -border-solid -border-slate-200"},C(te,{defaultNestedShow:!0,items:i}))),c?C("div",{className:"-max-h-[350px] -overflow-y-auto"},C("span",{className:"label gray size-lg -ml-2"},a),C(te,{defaultNestedShow:!0,items:this.filter(i)})):null)}},w(fr,"NAME","zui.searchForm"),fr);class er extends Z{}w(er,"NAME","QuickMenu"),w(er,"Component",Uf);const bp="",Vf=({formConfig:e,className:n,fields:t,operators:s,savedQuery:i,andOr:o,formSession:r,searchBtnText:l,resetBtnText:a,saveSearch:h,savedQueryTitle:c,onApplyQuery:u,onDeleteQuery:d,groupName:f,handleSelect:p,toggleMore:g,toggleHistory:y,resetForm:_,submitForm:v,actionURL:S,module:k,groupItems:N})=>{const M=[n,...["search-form"]],P=[1,2,3],R=r?r.groupAndOr:"",W=D=>{const K=r?r[`andOr${D}`]:"";return C("div",{class:[1,4].includes(D)?"search-group":"search-group hidden","data-id":D},C("div",{class:"group-name"},[1,4].includes(D)?D===1?f[0]:f[1]:C("select",{class:"form-control",id:`andOr${D}`,name:`andOr${D}`},o.map(z=>C("option",{value:z.value,selected:K===z.value,title:z.value},z.title)))),C("div",{class:"group-select"},C("select",{class:"form-control field-select",id:`field${D}`,name:`field${D}`,onChange:p.bind(void 0)}," ",t==null?void 0:t.map(z=>C("option",{value:z.name,selected:!1,title:z.name,control:z.control},z.label)))),C("div",{class:"group-select"},C("select",{class:"form-control search-method",id:`operator${D}`,name:`operator${D}`},s.map(z=>C("option",{key:z.value,value:z.value,title:z.value},z.title)))),C("div",{class:"group-value"},C("input",{type:"text",class:"form-control value-input",value:t[D-1].defaultValue,placeholder:t[D-1].placeholder}),C("select",{class:"form-control value-select hidden"}),C("input",{type:"datetime-local",class:"form-control value-date hidden"})))};return C("form",{id:"searchForm",className:O(M),...e},C("div",{class:"search-form-content"},C("div",{class:"search-form-items"},C("div",{class:"search-col"},P.map(D=>W(D))),C("div",{class:"search-col"},C("select",{class:"form-control",id:"groupAndOr",name:"groupAndOr"},o.map(D=>C("option",{value:D.value,selected:R===D.value,title:D.value},D.title)))),C("div",{class:"search-col"},P.map(D=>W(D+3)))),C("div",{class:"search-form-footer"},C("div",{class:"inline-block flex items-center justify-center"},C("button",{class:"btn primary btn-submit-form",type:"button",onClick:v},l||"搜索"),C("button",{class:"btn btn-reset-form",type:"button",onClick:_},a||"重置")),C("div",{class:"save-bar"},(h==null?void 0:h.hasPriv)&&C("a",{class:"btn save-query",...h.config},C("i",{class:"icon icon-save"}),h.text||"保存搜索条件"),C("a",{class:"btn toggle-more",onClick:g},C("i",{class:"icon icon-chevron-double-down"}))))),C("div",null,C("button",{class:"btn search-toggle-btn",type:"button",onClick:y},C("i",{class:"icon icon-angle-left"}))),C("div",{class:"history-record hidden"},C("p",null,c),C("div",{class:"labels"},(i==null?void 0:i.length)&&i.map(D=>{if(D)return C("div",{class:"label-btn","data-id":D.id},C("span",{class:"label lighter-pale bd-lighter",onClick:K=>u(K,Number(D.id))},D.title," ",D.hasPriv?C("i",{onClick:K=>d(K,Number(D.id)),class:"icon icon-close"}):""))}))),S?C("input",{type:"hidden",name:"actionURL",value:S}):"",k?C("input",{type:"hidden",name:"module",value:k}):"",N?C("input",{type:"hidden",name:"groupItems",value:N}):"")};let qf=(Gt=class extends V{componentDidMount(){this.initForm()}initForm(){const{formSession:n}=this.props;this.base.querySelectorAll(".search-form-content .search-group").forEach((s,i)=>{let o={};const r=s.querySelector(".field-select");r&&(r.value=(n?n[r.id]:null)||this.props.fields[i].name,this.props.fields.forEach(a=>{a.name==r.value&&(o=JSON.parse(JSON.stringify(a)))})),o.defaultValue=n?n["value"+(i+1)]:"";const l=s.querySelector(".search-method");l&&(l.value=(n?n[l.id]:null)||this.props.fields[i].operator||""),this.toggleElement(s,o)})}toggleAttr(n,t){if(!n.classList.contains("hidden")){n.setAttribute("name",t),n.setAttribute("id",t);return}n.removeAttribute("name"),n.removeAttribute("id")}toggleElement(n,t){const s=n.querySelector(".value-select"),i=n.querySelector(".value-input"),o=n.querySelector(".value-date"),r=n.querySelector(".search-method");if(t.operator,t.control==="select"&&(s.innerHTML="",t.values)){for(const c in t.values){const u=document.createElement("option");u.value=c,u.setAttribute("value",c),u.innerHTML=t.values[c],s.appendChild(u)}s.value=t.defaultValue||""}s.classList.toggle("hidden",t.control!=="select"),i.classList.toggle("hidden",t.control!=="input"),o==null||o.classList.toggle("hidden",t.control!=="date"),i.classList.contains("hidden")||(i.value=t.defaultValue||"",i.placeholder=t.placeholder||""),o&&!o.classList.contains("hidden")&&(o.value=t.defaultValue||"");const l=n.dataset.id,a=n.querySelector(".group-value");if(!a)return;a.childNodes.forEach(c=>{this.toggleAttr(c,`value${l}`)})}handleSelect(n){if(!n||!n.target)return;const t=n.target,i=this.props.fields.filter(r=>r.name===t.value)[0],o=t.closest(".search-group");this.toggleElement(o,i)}toggleElementDisplay(n,t,s,i){const o=t.classList.contains("hidden"),r=n.querySelector(".icon");r==null||r.classList.toggle(s,o),r==null||r.classList.toggle(i,!o)}toggleMore(n){if(!(n!=null&&n.target))return;const t=n.target,i=t.closest(".search-form-content").querySelectorAll(".search-col .search-group + .search-group");i.forEach(o=>{o.classList.toggle("hidden",!o.classList.contains("hidden"))}),this.toggleElementDisplay(t,i[0],"icon-chevron-double-down","icon-chevron-double-up")}toggleHistory(n){var i;if(!(n!=null&&n.target))return;const t=n.target,s=(i=t.closest(Gt.FORM_ID))==null?void 0:i.querySelector(".history-record");s&&(this.toggleElementDisplay(t,s,"icon-angle-right","icon-angle-left"),s.classList.toggle("hidden",!s.classList.contains("hidden")))}resetForm(n){if(!(n!=null&&n.target))return;const s=n.target.closest(Gt.FORM_ID);if(!s)return;s.querySelectorAll('.group-value [id^="value"]:not(.hidden), #searchForm .group-value [id*=" value"]:not(.hidden)').forEach(o=>{o.value=""})}submitForm(n){if(!(n!=null&&n.target))return;const s=n.target.closest(Gt.FORM_ID);s&&s.submit()}onDeleteQuery(n,t){!n||!n.target||t&&n.stopPropagation()}onApplyQuery(n,t){if(!n||!n.target||!t)return;const{applyQueryURL:s}=this.props;s&&(location.href=s.replace("myQueryID",t.toString()))}render(){const{submitForm:n,onApplyQuery:t,onDeleteQuery:s}=this.props;return C(Vf,{...this.props,handleSelect:this.handleSelect.bind(this),toggleMore:this.toggleMore.bind(this),toggleHistory:this.toggleHistory.bind(this),resetForm:this.resetForm.bind(this),submitForm:n?n.bind(this):this.submitForm.bind(this),onDeleteQuery:s?s.bind(this):this.onDeleteQuery.bind(this),onApplyQuery:t?t.bind(this):this.onApplyQuery.bind(this)})}},w(Gt,"NAME","zui.searchForm"),w(Gt,"FORM_ID","#searchForm"),Gt);class nr extends Z{}w(nr,"NAME","searchForm"),w(nr,"Component",qf);class Ic extends xt{constructor(){super(...arguments);x(this,Ii);x(this,ji);x(this,Wi)}init(){A(this.element).on("submit",this.onSubmit.bind(this)).on("input mousedown change",this.onInput.bind(this))}enable(t=!0){A(this.element).toggleClass("loading",!t)}disable(){this.enable(!1)}onInput(t){const s=A(t.target).closest(".has-error");s.length&&(s.removeClass("has-error"),s.closest(".form-group").find(`#${s.attr("id")}Tip`).remove())}onSubmit(t){var o;t.preventDefault();const{element:s}=this,i=A.extend({},this.options);this.emit("before",{event:t,element:s,options:i},!1),((o=i.beforeSubmit)==null?void 0:o.call(i,t,s,i))!==!1&&(this.disable(),L(this,Ii,La).call(this,new FormData(s)).finally(()=>{this.enable()}))}submit(){this.element.submit()}reset(){this.element.reset()}}Ii=new WeakSet,La=async function(t){var h,c;const{element:s,options:i}=this,{beforeSend:o}=i;if(o){const u=o(t);u instanceof FormData&&(t=u)}this.emit("send",{formData:t},!1);let r,l,a;try{const u=await fetch(i.url||s.action,{method:s.method||"POST",body:t,credentials:"same-origin",headers:{"X-Requested-With":"XMLHttpRequest"}});l=await u.text(),u.ok?(a=JSON.parse(l),(!a||typeof a!="object")&&(r=new Error("Invalid json format"))):r=new Error(u.statusText)}catch(u){r=u}r?(this.emit("error",{error:r,responseText:l},!1),(h=i.onError)==null||h.call(i,r,l)):L(this,Wi,Oa).call(this,a),this.emit("complete",{result:a,error:r},!1),(c=i.onComplete)==null||c.call(i,a,r)},ji=new WeakSet,Ma=function(t){var i;let s;Object.entries(t).forEach(([o,r])=>{Array.isArray(r)&&(r=r.join(""));const l=A(this.element).find(`#${o}`);if(!l.length)return;l.addClass("has-error");const a=l.closest(".form-group");if(a.length){let h=A(`#${o}Tip`);h.length||(h=A(`
    `).appendTo(a)),h.empty().text(r)}s||(s=l)}),s&&((i=s[0])==null||i.focus())},Wi=new WeakSet,Oa=function(t){var o,r;const{options:s}=this,{message:i}=t;if(t.result==="success"){if(this.emit("success",{result:t},!1),((o=s.onSuccess)==null?void 0:o.call(s,t))===!1)return;typeof i=="string"&&i.length&&A(document).trigger("zui.messager.show",{content:i,type:"success"});const{closeModal:l}=s;l&&A(document).trigger("zui.modal.hide",{target:l});const a=t.callback||s.callback;if(typeof a=="string"){const c=a.indexOf("("),u=(c>0?a.substr(0,c):a).split(".");let d=window,f=u[0];u.length>1&&(f=u[1],u[0]==="top"?d=window.top:u[0]==="parent"&&(d=window.parent));const p=d==null?void 0:d[f];if(typeof p=="function"){let g=[];return c>0&&a[a.length-1]==")"&&(g=JSON.parse("["+a.substring(c+1,a.length-1)+"]")),g.push(t),p.apply(this,g)}}else a&&typeof a=="object"&&(a.target?window[a.target]:window)[a.name].apply(this,Array.isArray(a.params)?a.params:[a.params]);const h=t.locate||s.locate;h&&A(document).trigger("zui.locate",h)}else{if(this.emit("fail",{result:t},!1),((r=s.onFail)==null?void 0:r.call(s,t))===!1)return;typeof i=="string"&&i.length?A(document).trigger("zui.messager.show",{content:i}):typeof i=="object"&&i&&L(this,ji,Ma).call(this,i)}},w(Ic,"NAME","ajaxform");const wp="";class jc extends V{constructor(t){super(t);x(this,ke,0);x(this,Te,null);w(this,"_handleWheel",t=>{const{wheelContainer:s}=this.props,i=t.target;if(!(!i||!s)&&(typeof s=="string"&&i.closest(s)||typeof s=="object")){const o=(this.props.type==="horz"?t.deltaX:t.deltaY)*(this.props.wheelSpeed??1);this.scrollOffset(o)&&t.preventDefault()}});w(this,"_handleMouseMove",t=>{const{dragStart:s}=this.state;s&&(m(this,ke)&&cancelAnimationFrame(m(this,ke)),T(this,ke,requestAnimationFrame(()=>{const i=this.props.type==="horz"?t.clientX-s.x:t.clientY-s.y;this.scroll(s.offset+i*this.props.scrollSize/this.props.clientSize),T(this,ke,0)})),t.preventDefault())});w(this,"_handleMouseUp",()=>{this.state.dragStart&&this.setState({dragStart:!1})});w(this,"_handleMouseDown",t=>{this.state.dragStart||this.setState({dragStart:{x:t.clientX,y:t.clientY,offset:this.scrollPos}}),t.stopPropagation()});w(this,"_handleClick",t=>{const s=t.currentTarget;if(!s)return;const i=s.getBoundingClientRect(),{type:o,clientSize:r,scrollSize:l}=this.props,a=(o==="horz"?t.clientX-i.left:t.clientY-i.top)-this.barSize/2;this.scroll(a*l/r),t.preventDefault()});this.state={scrollPos:this.props.defaultScrollPos??0,dragStart:!1}}get scrollPos(){return this.props.scrollPos??this.state.scrollPos}get controlled(){return this.props.scrollPos!==void 0}get maxScrollPos(){const{scrollSize:t,clientSize:s}=this.props;return Math.max(0,t-s)}get barSize(){const{clientSize:t,scrollSize:s,size:i=12,minBarSize:o=3*i}=this.props;return Math.max(Math.round(t*t/s),o)}componentDidMount(){document.addEventListener("mousemove",this._handleMouseMove),document.addEventListener("mouseup",this._handleMouseUp);const{wheelContainer:t}=this.props;t&&(T(this,Te,typeof t=="string"?document:t.current),m(this,Te).addEventListener("wheel",this._handleWheel,{passive:!1}))}componentWillUnmount(){document.removeEventListener("mousemove",this._handleMouseMove),document.removeEventListener("mouseup",this._handleMouseUp),m(this,Te)&&m(this,Te).removeEventListener("wheel",this._handleWheel)}scroll(t){return t=Math.max(0,Math.min(Math.round(t),this.maxScrollPos)),t===this.scrollPos?!1:(this.controlled?this._afterScroll(t):this.setState({scrollPos:t},this._afterScroll.bind(this,t)),!0)}scrollOffset(t){return this.scroll(this.scrollPos+t)}_afterScroll(t){const{onScroll:s}=this.props;s&&s(t,this.props.type??"vert")}render(){const{clientSize:t,type:s,size:i=12,className:o,style:r,left:l,top:a,bottom:h,right:c}=this.props,{maxScrollPos:u,scrollPos:d}=this,{dragStart:f}=this.state,p={left:l,top:a,bottom:h,right:c,...r},g={};return s==="horz"?(p.height=i,p.width=t,g.width=this.barSize,g.left=Math.round(Math.min(u,d)*(t-g.width)/u)):(p.width=i,p.height=t,g.height=this.barSize,g.top=Math.round(Math.min(u,d)*(t-g.height)/u)),b("div",{className:O("scrollbar",o,{"is-vert":s==="vert","is-horz":s==="horz","is-dragging":f}),style:p,onMouseDown:this._handleClick,children:b("div",{className:"scrollbar-bar",style:g,onMouseDown:this._handleMouseDown})})}}ke=new WeakMap,Te=new WeakMap;function Wc(e,n,t){return e&&(n&&(e=Math.max(n,e)),t&&(e=Math.min(t,e))),e}function Bc({col:e,className:n,height:t,row:s,onRenderCell:i,style:o,outerStyle:r,children:l,outerClass:a,...h}){var P;const c={left:e.left,width:e.realWidth,height:t,...r},{align:u,border:d}=e.setting,f={justifyContent:u?u==="left"?"start":u==="right"?"end":u:void 0,...e.setting.cellStyle,...o},p=["dtable-cell",a,e.setting.className,{"has-border-left":d===!0||d==="left","has-border-right":d===!0||d==="right"}],g=["dtable-cell-content",n],y=[l??((P=s.data)==null?void 0:P[e.name])??""],_=i?i(y,{row:s,col:e},C):y,v=[],S=[],k={},N={};let H="div";_==null||_.forEach(R=>{if(typeof R=="object"&&R&&!rt(R)&&("html"in R||"className"in R||"style"in R||"attrs"in R||"children"in R||"tagName"in R)){const W=R.outer?v:S;R.html?W.push(b("div",{className:O("dtable-cell-html",R.className),style:R.style,dangerouslySetInnerHTML:{__html:R.html},...R.attrs??{}})):(R.style&&Object.assign(R.outer?c:f,R.style),R.className&&(R.outer?p:g).push(R.className),R.children&&W.push(R.children),R.attrs&&Object.assign(R.outer?k:N,R.attrs)),R.tagName&&!R.outer&&(H=R.tagName)}else S.push(R)});const M=H;return b("div",{className:O(p),style:c,"data-col":e.name,...h,...k,children:[S.length>0&&b(M,{className:O(g),style:f,...N,children:S}),v]})}function sr({row:e,className:n,top:t=0,left:s=0,width:i,height:o,cols:r,CellComponent:l=Bc,onRenderCell:a}){return b("div",{className:O("dtable-cells",n),style:{top:t,left:s,width:i,height:o},children:r.map(h=>h.visible?b(l,{col:h,row:e,onRenderCell:a},h.name):null)})}function Fc({row:e,className:n,top:t,height:s,fixedLeftCols:i,fixedRightCols:o,scrollCols:r,fixedLeftWidth:l,scrollWidth:a,scrollColsWidth:h,fixedRightWidth:c,scrollLeft:u,CellComponent:d=Bc,onRenderCell:f,style:p,...g}){let y=null;i!=null&&i.length&&(y=b(sr,{className:"dtable-fixed-left",cols:i,width:l,row:e,CellComponent:d,onRenderCell:f}));let _=null;r!=null&&r.length&&(_=b(sr,{className:"dtable-flexable",cols:r,left:l-u,width:Math.max(a,h),row:e,CellComponent:d,onRenderCell:f}));let v=null;o!=null&&o.length&&(v=b(sr,{className:"dtable-fixed-right",cols:o,left:l+a,width:c,row:e,CellComponent:d,onRenderCell:f}));const S={top:t,height:s,lineHeight:`${s-2}px`,...p};return b("div",{className:O("dtable-row",n),style:S,"data-id":e.id,...g,children:[y,_,v]})}function Gf({height:e,onRenderRow:n,...t}){const s={height:e,...t,row:{id:"HEADER",index:-1,top:0},className:"dtable-in-header",top:0};if(n){const i=n({props:s},C);i&&Object.assign(s,i)}return b("div",{className:"dtable-header",style:{height:e},children:b(Fc,{...s})})}function Kf({className:e,style:n,top:t,rows:s,height:i,rowHeight:o,scrollTop:r,onRenderRow:l,...a}){return n={...n,top:t,height:i},b("div",{className:O("dtable-rows",e),style:n,children:s.map(h=>{const c={className:`dtable-row-${h.index%2?"odd":"even"}`,row:h,top:h.top-r,height:o,...a},u=l==null?void 0:l({props:c,row:h},C);return u&&Object.assign(c,u),b(Fc,{...c})})})}const si=new Map,ii=[];function zc(e,n){const{name:t}=e;if(!(n!=null&&n.override)&&si.has(t))throw new Error(`DTable: Plugin with name ${t} already exists`);si.set(t,e),n!=null&&n.buildIn&&!ii.includes(t)&&ii.push(t)}function Rt(e,n){zc(e,n);const t=s=>{if(!s)return e;const{defaultOptions:i,...o}=e;return{...o,defaultOptions:{...i,...s}}};return t.plugin=e,t}function Uc(e){return si.delete(e)}function Yf(e){if(typeof e=="string"){const n=si.get(e);return n||console.warn(`DTable: Cannot found plugin "${e}"`),n}if(typeof e=="function"&&"plugin"in e)return e.plugin;if(typeof e=="object")return e;console.warn("DTable: Invalid plugin",e)}function Vc(e,n,t){return n.forEach(s=>{var o;if(!s)return;const i=Yf(s);i&&(t.has(i.name)||((o=i.plugins)!=null&&o.length&&Vc(e,i.plugins,t),e.push(i),t.add(i.name)))}),e}function Xf(e=[],n=!0){return n&&ii.length&&e.unshift(...ii),e!=null&&e.length?Vc([],e,new Set):[]}function qc(){return{cols:[],data:[],rowKey:"id",width:"100%",height:"auto",rowHeight:35,defaultColWidth:80,minColWidth:20,maxColWidth:9999,header:!0,footer:!1,headerHeight:0,footerHeight:0,rowHover:!0,colHover:!1,cellHover:!1,bordered:!1,striped:!0,responsive:!1,scrollbarHover:!0,horzScrollbarPos:"outside"}}const vp="";let Jf=(Bi=class extends V{constructor(t){super(t);x(this,Fi);x(this,zi);x(this,Ui);x(this,Vi);x(this,fs);x(this,Xi);x(this,Ji);x(this,Qi);w(this,"ref",Oe());x(this,Re,0);x(this,pn,void 0);x(this,pe,!1);x(this,Mt,void 0);x(this,me,void 0);x(this,nt,[]);x(this,vt,void 0);x(this,Ot,new Map);x(this,mn,{});x(this,us,void 0);x(this,hs,[]);w(this,"updateLayout",()=>{m(this,Re)&&cancelAnimationFrame(m(this,Re)),T(this,Re,requestAnimationFrame(()=>{T(this,vt,void 0),this.forceUpdate(),T(this,Re,0)}))});x(this,Kt,(t,s)=>{s=s||t.type;const i=m(this,Ot).get(s);if(i!=null&&i.length){for(const o of i)if(o.call(this,t)===!1){t.stopPropagation(),t.preventDefault();break}}});x(this,gn,t=>{m(this,Kt).call(this,t,`window_${t.type}`)});x(this,yn,t=>{m(this,Kt).call(this,t,`document_${t.type}`)});x(this,qi,(t,s)=>{if(this.options.onRenderRow){const i=this.options.onRenderRow.call(this,t,s);i&&Object.assign(t.props,i)}return m(this,nt).forEach(i=>{if(i.onRenderRow){const o=i.onRenderRow.call(this,t,s);o&&Object.assign(t.props,o)}}),t.props});x(this,Gi,(t,s)=>(this.options.onRenderHeaderRow&&(t.props=this.options.onRenderHeaderRow.call(this,t,s)),m(this,nt).forEach(i=>{i.onRenderHeaderRow&&(t.props=i.onRenderHeaderRow.call(this,t,s))}),t.props));x(this,ds,(t,s,i)=>{const{row:o,col:r}=s;t[0]=this.getCellValue(o,r);const l=o.id==="HEADER"?"onRenderHeaderCell":"onRenderCell";return r.setting[l]&&(t=r.setting[l].call(this,t,s,i)),this.options[l]&&(t=this.options[l].call(this,t,s,i)),m(this,nt).forEach(a=>{a[l]&&(t=a[l].call(this,t,s,i))}),t});x(this,ps,(t,s)=>{s==="horz"?this.scroll({scrollLeft:t}):this.scroll({scrollTop:t})});x(this,Ki,t=>{var l,a,h,c,u;const s=this.getPointerInfo(t);if(!s)return;const{rowID:i,colName:o,cellElement:r}=s;if(i==="HEADER")r&&((l=this.options.onHeaderCellClick)==null||l.call(this,t,{colName:o,element:r}),m(this,nt).forEach(d=>{var f;(f=d.onHeaderCellClick)==null||f.call(this,t,{colName:o,element:r})}));else{const{rowElement:d}=s,f=this.layout.visibleRows.find(p=>p.id===i);if(r){if(((a=this.options.onCellClick)==null?void 0:a.call(this,t,{colName:o,rowID:i,rowInfo:f,element:r,rowElement:d}))===!0)return;for(const p of m(this,nt))if(((h=p.onCellClick)==null?void 0:h.call(this,t,{colName:o,rowID:i,rowInfo:f,element:r,rowElement:d}))===!0)return}if(((c=this.options.onRowClick)==null?void 0:c.call(this,t,{rowID:i,rowInfo:f,element:d}))===!0)return;for(const p of m(this,nt))if(((u=p.onRowClick)==null?void 0:u.call(this,t,{rowID:i,rowInfo:f,element:d}))===!0)return}});x(this,Yi,t=>{const s=t.key.toLowerCase();if(["pageup","pagedown","home","end"].includes(s))return!this.scroll({to:s.replace("page","")})});T(this,pn,t.id??`dtable-${Rn(10)}`),this.state={scrollTop:0,scrollLeft:0,renderCount:0},T(this,me,Object.freeze(Xf(t.plugins))),m(this,me).forEach(s=>{var l;const{methods:i,data:o,state:r}=s;i&&Object.entries(i).forEach(([a,h])=>{typeof h=="function"&&Object.assign(this,{[a]:h.bind(this)})}),o&&Object.assign(m(this,mn),o.call(this)),r&&Object.assign(this.state,r.call(this)),(l=s.onCreate)==null||l.call(this,s)})}get options(){var t;return((t=m(this,vt))==null?void 0:t.options)||m(this,Mt)||qc()}get plugins(){return m(this,nt)}get layout(){return m(this,vt)}get id(){return m(this,pn)}get data(){return m(this,mn)}get parent(){var t;return this.props.parent??((t=this.ref.current)==null?void 0:t.parentElement)}componentWillReceiveProps(){T(this,Mt,void 0)}componentDidMount(){if(m(this,pe)?this.forceUpdate():L(this,fs,_r).call(this),m(this,nt).forEach(t=>{let{events:s}=t;s&&(typeof s=="function"&&(s=s.call(this)),Object.entries(s).forEach(([i,o])=>{o&&this.on(i,o)}))}),this.on("click",m(this,Ki)),this.on("keydown",m(this,Yi)),this.options.responsive){if(typeof ResizeObserver<"u"){const{parent:t}=this;if(t){const s=new ResizeObserver(this.updateLayout);s.observe(t),T(this,us,s)}}this.on("window_resize",this.updateLayout)}m(this,nt).forEach(t=>{var s;(s=t.onMounted)==null||s.call(this)})}componentDidUpdate(){m(this,pe)?L(this,fs,_r).call(this):m(this,nt).forEach(t=>{var s;(s=t.onUpdated)==null||s.call(this)})}componentWillUnmount(){var s;(s=m(this,us))==null||s.disconnect();const{current:t}=this.ref;if(t)for(const i of m(this,Ot).keys())i.startsWith("window_")?window.removeEventListener(i.replace("window_",""),m(this,gn)):i.startsWith("document_")?document.removeEventListener(i.replace("document_",""),m(this,yn)):t.removeEventListener(i,m(this,Kt));m(this,nt).forEach(i=>{var o;(o=i.onUnmounted)==null||o.call(this)}),m(this,me).forEach(i=>{var o;(o=i.onDestory)==null||o.call(this)}),T(this,mn,{}),m(this,Ot).clear()}on(t,s,i){var r;i&&(t=`${i}_${t}`);const o=m(this,Ot).get(t);o?o.push(s):(m(this,Ot).set(t,[s]),t.startsWith("window_")?window.addEventListener(t.replace("window_",""),m(this,gn)):t.startsWith("document_")?document.addEventListener(t.replace("document_",""),m(this,yn)):(r=this.ref.current)==null||r.addEventListener(t,m(this,Kt)))}off(t,s,i){var l;i&&(t=`${i}_${t}`);const o=m(this,Ot).get(t);if(!o)return;const r=o.indexOf(s);r>=0&&o.splice(r,1),o.length||(m(this,Ot).delete(t),t.startsWith("window_")?window.removeEventListener(t.replace("window_",""),m(this,gn)):t.startsWith("document_")?document.removeEventListener(t.replace("document_",""),m(this,yn)):(l=this.ref.current)==null||l.removeEventListener(t,m(this,Kt)))}emitCustomEvent(t,s){m(this,Kt).call(this,s instanceof Event?s:new CustomEvent(t,{detail:s}),t)}scroll(t,s){const{scrollLeft:i,scrollTop:o,rowsHeightTotal:r,rowsHeight:l,rowHeight:a,colsInfo:{scrollWidth:h,scrollColsWidth:c}}=this.layout,{to:u}=t;let{scrollLeft:d,scrollTop:f}=t;if(u==="up"||u==="down")f=o+(u==="down"?1:-1)*Math.floor(l/a)*a;else if(u==="left"||u==="right")d=i+(u==="right"?1:-1)*h;else if(u==="home")f=0;else if(u==="end")f=r-l;else if(u==="left-begin")d=0;else if(u==="right-end")d=c-h;else{const{offsetLeft:g,offsetTop:y}=t;typeof g=="number"&&(d=i+g),typeof y=="number"&&(d=o+y)}const p={};return typeof d=="number"&&(d=Math.max(0,Math.min(d,c-h)),d!==i&&(p.scrollLeft=d)),typeof f=="number"&&(f=Math.max(0,Math.min(f,r-l)),f!==o&&(p.scrollTop=f)),Object.keys(p).length?(this.setState(p,()=>{var g;(g=this.options.onScroll)==null||g.call(this,p),s==null||s.call(this,!0)}),!0):(s==null||s.call(this,!1),!1)}getColInfo(t){if(t===void 0)return;if(typeof t=="object")return t;const{colsMap:s,colsList:i}=this.layout;return typeof t=="number"?i[t]:s[t]}getRowInfo(t){if(t===void 0)return;if(typeof t=="object")return t;if(t===-1||t==="HEADER")return{id:"HEADER",index:-1,top:0};const{rows:s,rowsMap:i}=this.layout;return typeof t=="number"?s[t]:i[t]}getCellValue(t,s){var a;const i=typeof t=="object"?t:this.getRowInfo(t);if(!i)return;const o=typeof s=="object"?s:this.getColInfo(s);if(!o)return;let r=i.id==="HEADER"?o.setting.title:(a=i.data)==null?void 0:a[o.name];const{cellValueGetter:l}=this.options;return l&&(r=l.call(this,i,o,r)),r}getRowInfoByIndex(t){return this.layout.rows[t]}update(t={},s){if(!m(this,Mt))return;typeof t=="function"&&(s=t,t={});const{dirtyType:i,state:o}=t;if(i==="layout")T(this,vt,void 0);else if(i==="options"){if(T(this,Mt,void 0),!m(this,vt))return;T(this,vt,void 0)}this.setState(o??(r=>({renderCount:r.renderCount+1})),s)}getPointerInfo(t){const s=t.target;if(!s||s.closest(".no-cell-event"))return;const i=s.closest(".dtable-cell");if(!i)return;const o=i.closest(".dtable-row");if(!o)return;const r=i==null?void 0:i.getAttribute("data-col"),l=o==null?void 0:o.getAttribute("data-id");if(!(typeof r!="string"||typeof l!="string"))return{cellElement:i,rowElement:o,colName:r,rowID:l,target:s}}i18n(t,s,i){return Pe(m(this,hs),t,s,i,this.options.lang)??`{i18n:${t}}`}render(){const t=L(this,Qi,Ba).call(this),{className:s,rowHover:i,colHover:o,cellHover:r,bordered:l,striped:a,scrollbarHover:h}=this.options,c={width:t==null?void 0:t.width,height:t==null?void 0:t.height},u=["dtable",s,{"dtable-hover-row":i,"dtable-hover-col":o,"dtable-hover-cell":r,"dtable-bordered":l,"dtable-striped":a,"dtable-scrolled-down":((t==null?void 0:t.scrollTop)??0)>0,"scrollbar-hover":h}],d=[];return t&&m(this,nt).forEach(f=>{var g;const p=(g=f.onRender)==null?void 0:g.call(this,t);p&&(p.style&&Object.assign(c,p.style),p.className&&u.push(p.className),p.children&&d.push(p.children))}),b("div",{id:m(this,pn),className:O(u),style:c,ref:this.ref,tabIndex:-1,children:[t&&L(this,Fi,Pa).call(this,t),t&&L(this,zi,Da).call(this,t),t&&L(this,Ui,Ha).call(this,t),t&&L(this,Vi,Ia).call(this,t)]})}},Re=new WeakMap,pn=new WeakMap,pe=new WeakMap,Mt=new WeakMap,me=new WeakMap,nt=new WeakMap,vt=new WeakMap,Ot=new WeakMap,mn=new WeakMap,us=new WeakMap,hs=new WeakMap,Kt=new WeakMap,gn=new WeakMap,yn=new WeakMap,Fi=new WeakSet,Pa=function(t){const{header:s,colsInfo:i,headerHeight:o,scrollLeft:r}=t;if(!s)return null;if(s===!0)return b(Gf,{scrollLeft:r,height:o,onRenderCell:m(this,ds),onRenderRow:m(this,Gi),...i});const l=Array.isArray(s)?s:[s];return b(po,{className:"dtable-header",style:{height:o},renders:l,generateArgs:[t],generatorThis:this})},zi=new WeakSet,Da=function(t){const{headerHeight:s,rowsHeight:i,visibleRows:o,rowHeight:r,colsInfo:l,scrollLeft:a,scrollTop:h}=t;return b(Kf,{top:s,height:i,rows:o,rowHeight:r,scrollLeft:a,scrollTop:h,onRenderCell:m(this,ds),onRenderRow:m(this,qi),...l})},Ui=new WeakSet,Ha=function(t){const{footer:s}=t;if(!s)return null;const i=typeof s=="function"?s.call(this,t):Array.isArray(s)?s:[s];return b(po,{className:"dtable-footer",style:{height:t.footerHeight,top:t.rowsHeight+t.headerHeight},renders:i,generateArgs:[t],generatorThis:this,generators:t.footerGenerators})},Vi=new WeakSet,Ia=function(t){const s=[],{scrollLeft:i,colsInfo:o,scrollTop:r,rowsHeight:l,rowsHeightTotal:a,footerHeight:h}=t,{scrollColsWidth:c,scrollWidth:u}=o,{scrollbarSize:d=12,horzScrollbarPos:f}=this.options;return c>u&&s.push(b(jc,{type:"horz",scrollPos:i,scrollSize:c,clientSize:u,onScroll:m(this,ps),left:o.fixedLeftWidth,bottom:(f==="inside"?0:-d)+h,size:d,wheelContainer:this.ref},"horz")),a>l&&s.push(b(jc,{type:"vert",scrollPos:r,scrollSize:a,clientSize:l,onScroll:m(this,ps),right:0,size:d,top:t.headerHeight,wheelContainer:this.ref},"vert")),s.length?s:null},fs=new WeakSet,_r=function(){var t;T(this,pe,!1),(t=this.options.afterRender)==null||t.call(this),m(this,nt).forEach(s=>{var i;return(i=s.afterRender)==null?void 0:i.call(this)})},qi=new WeakMap,Gi=new WeakMap,ds=new WeakMap,ps=new WeakMap,Ki=new WeakMap,Yi=new WeakMap,Xi=new WeakSet,ja=function(){if(m(this,Mt))return!1;const s={...qc(),...m(this,me).reduce((i,o)=>{const{defaultOptions:r}=o;return r&&Object.assign(i,r),i},{}),...this.props};return T(this,Mt,s),T(this,nt,m(this,me).reduce((i,o)=>{const{when:r,options:l}=o;return(!r||r(s))&&(i.push(o),l&&Object.assign(s,typeof l=="function"?l.call(this,s):l)),i},[])),T(this,hs,[this.options.i18n,...this.plugins.map(i=>i.i18n)].filter(Boolean)),!0},Ji=new WeakSet,Wa=function(){var ia,oa;const{plugins:t}=this;let s=m(this,Mt);const i={flex:b("div",{style:"flex:auto"}),divider:b("div",{style:"width:1px;margin:var(--space);background:var(--color-border);height:50%"})};t.forEach(I=>{var Xt;const Q=(Xt=I.beforeLayout)==null?void 0:Xt.call(this,s);Q&&(s={...s,...Q}),Object.assign(i,I.footer)});const{defaultColWidth:o,minColWidth:r,maxColWidth:l}=s,a=[],h=[],c=[],u={},d=[],f=[];let p=0,g=0,y=0;s.cols.forEach(I=>{if(I.hidden)return;const{name:Q,type:Xt="",fixed:Jt=!1,flex:Me=!1,width:ms=o,minWidth:gs=r,maxWidth:dr=l,...yd}=I,q={name:Q,type:Xt,setting:{name:Q,type:Xt,fixed:Jt,flex:Me,width:ms,minWidth:gs,maxWidth:dr,...yd},flex:Jt?0:Me===!0?1:typeof Me=="number"?Me:0,left:0,width:Wc(ms,gs,dr),realWidth:0,visible:!0,index:d.length};t.forEach(ra=>{var la,ca;const Zi=(la=ra.colTypes)==null?void 0:la[Xt];if(Zi){const aa=typeof Zi=="function"?Zi(q):Zi;aa&&Object.assign(q.setting,aa)}(ca=ra.onAddCol)==null||ca.call(this,q)}),q.width=Wc(q.setting.width??q.width,q.setting.minWidth??gs,q.setting.maxWidth??dr),q.realWidth=q.realWidth||q.width,Jt==="left"?(q.left=p,p+=q.width,a.push(q)):Jt==="right"?(q.left=g,g+=q.width,h.push(q)):(q.left=y,y+=q.width,c.push(q)),q.flex&&f.push(q),d.push(q),u[q.name]=q});let _=s.width,v=0;const S=p+y+g;if(typeof _=="function"&&(_=_.call(this,S)),_==="auto")v=S;else if(_==="100%"){const{parent:I}=this;if(I)v=I.clientWidth;else{v=0,T(this,pe,!0);return}}else v=_??0;const{data:k,rowKey:N="id",rowHeight:H}=s,M=[],P=(I,Q,Xt)=>{var Me,ms;const Jt={data:Xt??{[N]:I},id:I,index:M.length,top:0};if(Xt||(Jt.lazy=!0),M.push(Jt),((Me=s.onAddRow)==null?void 0:Me.call(this,Jt,Q))!==!1){for(const gs of t)if(((ms=gs.onAddRow)==null?void 0:ms.call(this,Jt,Q))===!1)return}};if(typeof k=="number")for(let I=0;I{typeof I=="object"?P(`${I[N]??""}`,Q,I):P(`${I??""}`,Q)});let R=M;const W={};if(s.onAddRows){const I=s.onAddRows.call(this,R);I&&(R=I)}for(const I of t){const Q=(ia=I.onAddRows)==null?void 0:ia.call(this,R);Q&&(R=Q)}R.forEach((I,Q)=>{W[I.id]=I,I.index=Q,I.top=I.index*H});const{header:D,footer:K}=s,z=D?s.headerHeight||H:0,X=K?s.footerHeight||H:0;let j=s.height,J=0;const Pt=R.length*H,Ae=z+X+Pt;if(typeof j=="function"&&(j=j.call(this,Ae)),j==="auto")J=Ae;else if(typeof j=="object")J=Math.min(j.max,Math.max(j.min,Ae));else if(j==="100%"){const{parent:I}=this;if(I)J=I.clientHeight;else{J=0,T(this,pe,!0);return}}else J=j;const Ne=J-z-X,Le=v-p-g,Yt={options:s,allRows:M,width:v,height:J,rows:R,rowsMap:W,rowHeight:H,rowsHeight:Ne,rowsHeightTotal:Pt,header:D,footer:K,footerGenerators:i,headerHeight:z,footerHeight:X,colsMap:u,colsList:d,flexCols:f,colsInfo:{fixedLeftCols:a,fixedRightCols:h,scrollCols:c,fixedLeftWidth:p,scrollWidth:Le,scrollColsWidth:y,fixedRightWidth:g}},_n=(oa=s.onLayout)==null?void 0:oa.call(this,Yt);_n&&Object.assign(Yt,_n),t.forEach(I=>{if(I.onLayout){const Q=I.onLayout.call(this,Yt);Q&&Object.assign(Yt,Q)}}),T(this,vt,Yt)},Qi=new WeakSet,Ba=function(){(L(this,Xi,ja).call(this)||!m(this,vt))&&L(this,Ji,Wa).call(this);const{layout:t}=this;if(!t)return;let{scrollLeft:s}=this.state;const{flexCols:i,colsInfo:{scrollCols:o,scrollWidth:r,scrollColsWidth:l}}=t;if(i.length){const S=r-l;if(S>0){const k=i.reduce((H,M)=>H+M.flex,0);let N=0;i.forEach(H=>{const M=Math.min(S-N,Math.ceil(S*(H.flex/k)));H.realWidth=M+H.width,N+=H.realWidth})}else i.forEach(k=>{k.realWidth=k.width})}s=Math.min(Math.max(0,l-r),s);let a=0;o.forEach(S=>{S.left=a,a+=S.realWidth,S.visible=S.left+S.realWidth>=s&&S.left<=s+r});const{rowsHeightTotal:h,rowsHeight:c,rows:u,rowHeight:d}=t,f=Math.min(Math.max(0,h-c),this.state.scrollTop),p=Math.floor(f/d),g=f+c,y=Math.min(u.length,Math.ceil(g/d)),_=[],{rowDataGetter:v}=this.options;for(let S=p;Si.classList.remove(s)),typeof n=="string"&&n.length&&t.querySelectorAll(`.dtable-cell[data-col="${n}"]`).forEach(i=>i.classList.add(s))}const Qf=Rt({name:"col-hover",defaultOptions:{colHover:!1},when:e=>!!e.colHover,events:{mouseover(e){var i;const{colHover:n}=this.options;if(!n)return;const t=(i=e.target)==null?void 0:i.closest(".dtable-cell");if(!t||n==="header"&&!t.closest(".dtable-header"))return;const s=(t==null?void 0:t.getAttribute("data-col"))??!1;Gc(this,s)},mouseleave(){Gc(this,!1)}}},{buildIn:!0}),Sp="";function Zf(e,n){var r,l;typeof e=="boolean"&&(n=e,e=void 0);const t=this.state.checkedRows,s={},{canRowCheckable:i}=this.options,o=(a,h)=>{i&&!i.call(this,a)||!!t[a]===h||(h?t[a]=!0:delete t[a],s[a]=h)};if(e===void 0?(n===void 0&&(n=!Kc.call(this)),(r=this.layout)==null||r.allRows.forEach(({id:a})=>{o(a,!!n)})):(Array.isArray(e)||(e=[e]),e.forEach(a=>{o(a,n??!t[a])})),Object.keys(s).length){const a=(l=this.options.beforeCheckRows)==null?void 0:l.call(this,e,s,t);a&&Object.keys(a).forEach(h=>{a[h]?t[h]=!0:delete t[h]}),this.setState({checkedRows:{...t}},()=>{var h;(h=this.options.onCheckChange)==null||h.call(this,s)})}return s}function td(e){return this.state.checkedRows[e]??!1}function Kc(){var t,s;const e=this.getChecks().length,{canRowCheckable:n}=this.options;return n?e===((t=this.layout)==null?void 0:t.allRows.reduce((i,o)=>i+(n.call(this,o.id)?1:0),0)):e===((s=this.layout)==null?void 0:s.allRows.length)}function ed(){return Object.keys(this.state.checkedRows)}const nd=Rt({name:"checkable",defaultOptions:{checkable:!0},when:e=>!!e.checkable,state(){return{checkedRows:{}}},methods:{toggleCheckRows:Zf,isRowChecked:td,isAllRowChecked:Kc,getChecks:ed},i18n:{zh_cn:{checkedCountInfo:"已选择 {selected} 项",totalCountInfo:"共 {total} 项"},en:{checkedCountInfo:"Selected {selected} items",totalCountInfo:"Total {total} items"}},footer:{checkbox(){const e=this.isAllRowChecked();return[b("div",{style:{padding:"0 calc(3 * var(--space))",display:"flex",alignItems:"center"},onClick:()=>this.toggleCheckRows(),children:b("input",{type:"checkbox",checked:e})})]},checkedInfo(e,n){const t=this.getChecks().length,s=[];return t&&s.push(this.i18n("checkedCountInfo",{selected:t})),s.push(this.i18n("totalCountInfo",{total:n.allRows.length})),[b("div",{children:s.join(", ")})]}},onRenderCell(e,{row:n,col:t}){var l;const{id:s}=n,{canRowCheckable:i}=this.options;if(i&&!i.call(this,s))return e;const{checkbox:o}=t.setting;if(typeof o=="function"?o.call(this,s):o){const a=this.isRowChecked(s),h=((l=this.options.checkboxRender)==null?void 0:l.call(this,a,s))??b("input",{type:"checkbox",checked:a});e.unshift(h),e.push({className:"has-checkbox"})}return e},onRenderHeaderCell(e,{row:n,col:t}){var r;const{id:s}=n,{checkbox:i}=t.setting;if(typeof i=="function"?i.call(this,s):i){const l=this.isAllRowChecked(),a=((r=this.options.checkboxRender)==null?void 0:r.call(this,l,s))??b("input",{type:"checkbox",checked:l});e.unshift(a),e.push({className:"has-checkbox"})}return e},onRenderRow({props:e,row:n}){if(this.isRowChecked(n.id))return{className:O(e.className,"is-checked")}},onHeaderCellClick(e){const n=e.target;if(!n)return;const t=n.closest('input[type="checkbox"],.dtable-checkbox');t&&(this.toggleCheckRows(t.checked),e.stopPropagation())},onRowClick(e,{rowID:n}){const t=e.target;if(!t)return;(t.closest('input[type="checkbox"],.dtable-checkbox')||this.options.checkOnClickRow)&&this.toggleCheckRows(n)}}),Cp="",$p="";var Yc=(e=>(e.unknown="",e.collapsed="collapsed",e.expanded="expanded",e.hidden="hidden",e.normal="normal",e))(Yc||{});function ir(e){const n=this.data.nestedMap.get(e);if(!n||n.state!=="")return n??{state:"normal",level:-1};if(!n.parent&&!n.children)return n.state="normal",n;const t=this.state.collapsedRows,s=n.children&&t&&t[e];let i=!1,{parent:o}=n;for(;o;){const r=ir.call(this,o);if(r.state!=="expanded"){i=!0;break}o=r.parent}return n.state=i?"hidden":s?"collapsed":n.children?"expanded":"normal",n.level=n.parent?ir.call(this,n.parent).level+1:0,n}function sd(e,n){let t=this.state.collapsedRows??{};const{nestedMap:s}=this.data;if(e==="HEADER")if(n===void 0&&(n=!Xc.call(this)),n){const i=s.entries();for(const[o,r]of i)r.state==="expanded"&&(t[o]=!0)}else t={};else{const i=Array.isArray(e)?e:[e];n===void 0&&(n=!t[i[0]]),i.forEach(o=>{const r=s.get(o);n&&(r!=null&&r.children)?t[o]=!0:delete t[o]})}this.update({dirtyType:"layout",state:{collapsedRows:{...t}}},()=>{var i;(i=this.options.onNestedChange)==null||i.call(this)})}function Xc(){const e=this.data.nestedMap.values();for(const n of e)if(n.state==="expanded")return!1;return!0}function Jc(e,n=0,t,s=0){var i;t||(t=[...e.keys()]);for(const o of t){const r=e.get(o);r&&(r.level===s&&(r.order=n++),(i=r.children)!=null&&i.length&&(n=Jc(e,n,r.children,s+1)))}return n}function Qc(e,n,t,s){const i=e.getNestedRowInfo(n);return!i||i.state===""||!i.children||i.children.forEach(o=>{s[o]=t,Qc(e,o,t,s)}),i}function Zc(e,n,t,s,i){var l;const o=e.getNestedRowInfo(n);if(!o||o.state==="")return;((l=o.children)==null?void 0:l.every(a=>{const h=!!(s[a]!==void 0?s[a]:i[a]);return t===h}))&&(s[n]=t),o.parent&&Zc(e,o.parent,t,s,i)}const id=Rt({name:"nested",defaultOptions:{nested:!0,nestedParentKey:"parent",asParentKey:"asParent",nestedIndent:20,canSortTo(e,n){const{nestedMap:t}=this.data,s=t.get(e.id),i=t.get(n.id);return(s==null?void 0:s.parent)===(i==null?void 0:i.parent)},beforeCheckRows(e,n,t){if(!this.options.checkable||!(e!=null&&e.length))return;const s={};return Object.entries(n).forEach(([i,o])=>{const r=Qc(this,i,o,s);r!=null&&r.parent&&Zc(this,r.parent,o,s,t)}),s}},when:e=>!!e.nested,data(){return{nestedMap:new Map}},methods:{toggleRow:sd,isAllCollapsed:Xc,getNestedRowInfo:ir},beforeLayout(){this.data.nestedMap.clear()},onAddRow(e){var i,o;const{nestedMap:n}=this.data,t=(i=e.data)==null?void 0:i[this.options.nestedParentKey??"parent"],s=n.get(e.id)??{state:"",level:0};if(s.parent=t,(o=e.data)!=null&&o[this.options.asParentKey??"asParent"]&&(s.children=[]),n.set(e.id,s),t){let r=n.get(t);r||(r={state:"",level:0},n.set(t,r)),r.children||(r.children=[]),r.children.push(e.id)}},onAddRows(e){return e=e.filter(n=>this.getNestedRowInfo(n.id).state!=="hidden"),Jc(this.data.nestedMap),e.sort((n,t)=>{const s=this.getNestedRowInfo(n.id),i=this.getNestedRowInfo(t.id),o=(s.order??0)-(i.order??0);return o===0?n.index-t.index:o}),e},onRenderCell(e,{col:n,row:t}){var l;const{id:s,data:i}=t,{nestedToggle:o}=n.setting,r=this.getNestedRowInfo(s);if(o&&(r.children||r.parent)&&e.unshift(((l=this.options.onRenderNestedToggle)==null?void 0:l.call(this,r,s,n,i))??b("a",{role:"button",className:`dtable-nested-toggle state${r.children?"":" is-no-child"}`,children:b("span",{className:"toggle-icon"})})),r.level){let{nestedIndent:a=o}=n.setting;a&&(a===!0&&(a=this.options.nestedIndent??12),e.unshift(b("div",{className:"dtable-nested-indent",style:{width:a*r.level+"px"}})))}return e},onRenderHeaderCell(e,{row:n,col:t}){var i;const{id:s}=n;return t.setting.nestedToggle&&e.unshift(((i=this.options.onRenderNestedToggle)==null?void 0:i.call(this,void 0,s,t,void 0))??b("a",{type:"button",className:"dtable-nested-toggle state",children:b("span",{className:"toggle-icon"})})),e},onRenderRow({props:e,row:n}){const t=this.getNestedRowInfo(n.id);return{className:O(e.className,`is-${t.state}`),"data-parent":t.parent}},onRenderHeaderRow({props:e}){return e.className=O(e.className,`is-${this.isAllCollapsed()?"collapsed":"expanded"}`),e},onHeaderCellClick(e){const n=e.target;if(!(!n||!n.closest(".dtable-nested-toggle")))return this.toggleRow("HEADER"),!0},onCellClick(e,{rowID:n}){const t=e.target;if(!(!t||!this.getNestedRowInfo(n).children||!t.closest(".dtable-nested-toggle")))return this.toggleRow(n),!0}}),Tp="",od=Rt({name:"rich",colTypes:{html:{onRenderCell(e){return e[0]={html:e[0]},e}},link:{onRenderCell(e,{col:n,row:t}){const{linkTemplate:s="",linkProps:i}=n.setting,o=st(s,t.data);return e[0]=b("a",{href:o,...i,children:e[0]}),e}},avatar:{onRenderCell(e,{col:n,row:t}){const{data:s}=t,{avatarWithName:i,avatarClass:o="size-xs circle",avatarKey:r=`${n.name}Avatar`}=n.setting,l=b("div",{className:`avatar ${o} flex-none`,children:b("img",{src:s?s[r]:""})});return i?e.unshift(l):e[0]=l,e}},circleProgress:{align:"center",onRenderCell(e,{col:n}){const{circleSize:t=24,circleBorderSize:s=1,circleBgColor:i="var(--color-border)",circleColor:o="var(--color-success-500)"}=n.setting,r=(t-s)/2,l=t/2,a=e[0];return e[0]=b("svg",{width:t,height:t,children:[b("circle",{cx:l,cy:l,r,"stroke-width":s,stroke:i,fill:"transparent"}),b("circle",{cx:l,cy:l,r,"stroke-width":s,stroke:o,fill:"transparent","stroke-linecap":"round","stroke-dasharray":Math.PI*r*2,"stroke-dashoffset":Math.PI*r*2*(100-a)/100,style:{transformOrigin:"center",transform:"rotate(-90deg)"}}),b("text",{x:l,y:l+s,"dominant-baseline":"middle","text-anchor":"middle",style:{fontSize:`${r}px`},children:Math.round(a)})]}),e}},actionButtons:{onRenderCell(e,{col:n,row:t}){var l;const s=(l=t.data)==null?void 0:l[n.name];if(!s)return e;const{actionBtnTemplate:i='',actionBtnData:o={},actionBtnClass:r="btn text-primary square size-sm ghost"}=n.setting;return[{html:s.map(a=>{typeof a=="string"&&(a={action:a});const h=o[a.action];return h&&(a={className:r,...h,...a}),st(i,a)}).join(" ")}]}},format:{onRenderCell(e,{col:n}){let{format:t}=n.setting;if(!t)return e;typeof t=="string"&&(t={type:"text",format:t});const{format:s,type:i}=t,o=e[0];return typeof s=="function"?e[0]=i==="html"?{html:s(o)}:s(o):i==="datetime"?e[0]=Ys(o,s):i==="html"?e[0]={html:st(s,o)}:e[0]=st(s,o),e}}}},{buildIn:!0}),rd=Rt({name:"sort-type",onRenderHeaderCell(e,{col:n}){const{sortType:t}=n.setting;if(t){const{sortLink:s=this.options.sortLink,sortAttrs:i}=n.setting,o=t===!0?"none":t;if(e.push(b("div",{className:`dtable-sort dtable-sort-${o}`}),{outer:!0,attrs:{"data-sort":o}}),s){const r=typeof s=="function"?s.call(this,n,o):s;e.push({tagName:"a",attrs:{href:r,...i}})}}return e}},{buildIn:!0}),ld=Object.freeze(Object.defineProperty({__proto__:null,NestedRowState:Yc,checkable:nd,colHover:Qf,nested:id,rich:od,sortType:rd},Symbol.toStringTag,{value:"Module"}));class qe extends Z{}w(qe,"NAME","dtable"),w(qe,"Component",Jf),w(qe,"definePlugin",Rt),w(qe,"removePlugin",Uc),w(qe,"plugins",ld);function cd(e){const[n,t]=e.split(":"),s=n[0]==="-"?{name:n.substring(1),disabled:!0}:{name:n};return t!=null&&t.length&&(s.type="dropdown",s.items=t.split(",").reduce((i,o)=>(o=o.trim(),o.length&&i.push(o[0]==="-"?{name:o.substring(1),disabled:!0}:{name:o}),i),[])),s}const ad=(e,n)=>{var t;return e.url&&(e.url=st(e.url,n.row.data)),(t=e.dropdown)!=null&&t.items&&(e.dropdown.items=e.dropdown.items.map(s=>(s.url&&(s.url=st(s.url,n.row.data)),s))),e},ud=Rt({name:"actions",colTypes:{actions:{onRenderCell(e,n){var c;const{row:t,col:s}=n;let i=(c=t.data)==null?void 0:c[s.name];if(typeof i=="string"&&(i=i.split("|")),!(i!=null&&i.length))return e;const{actionsSetting:o,actionsMap:r,actionsCreator:l=this.options.actionsCreator,actionItemCreator:a=this.options.actionItemCreator||ad}=s.setting,h={items:(l==null?void 0:l(n))??i.map(u=>{if(u=typeof u=="string"?cd(u):u,!u)return;const{name:d,items:f,...p}=u;if(r&&d&&(Object.assign(p,r[d],{...p}),typeof p.buildProps=="function")){const{buildProps:g}=p;delete p.buildProps,Object.assign(p,g(e,n))}if(f&&p.type==="dropdown"){const{dropdown:g={}}=p;g.menu={className:"menu-dtable-actions",items:f.reduce((y,_)=>{const v=typeof _=="string"?{name:_}:{..._};return v!=null&&v.name&&(r&&"name"in v&&Object.assign(v,r[v.name],{...v}),y.push(v)),y},[])},p.dropdown=g}return a?a(p,n):p}).filter(Boolean),btnProps:{size:"sm",className:"text-primary"},...o};return e[0]=b(oe,{...h}),e}}}}),hd=Rt({name:"toolbar",footer:{toolbar(){const{footToolbar:e}=this.options;return[e?b(oe,{...e}):null]}}}),fd=Rt({name:"pager",footer:{pager(){const{footPager:e}=this.options;return[e?b(vc,{...e}):null]}}}),Op="",ta={name:"zentao",plugins:["checkable","nested",ud,hd,fd],defaultOptions:{footer:["checkbox","checkedInfo"],colHover:!1,rowHeight:36,filterable:!0,striped:!1,responsive:!0,checkable:!1,nested:!1,height:e=>{var n,t;return Math.min(e,window.innerHeight-1-(((n=document.getElementById("header"))==null?void 0:n.clientHeight)??0)-(((t=document.getElementById("mainMenu"))==null?void 0:t.clientHeight)??0))}},colTypes:{status:{width:80,align:"center",sortType:!0,onRenderCell(e,{col:n,row:t}){var r,l;const s=(r=t.data)==null?void 0:r[n.name];let i,o;return typeof s=="string"?(i=s,o=(l=n.setting.statusMap)==null?void 0:l[s]):typeof s=="object"&&s&&({name:i,label:o}=s),e[0]=C("span",{class:`${n.setting.statusClassPrefix??"status-"}${i}`},o??i),e}},avatarBtn:{width:100,sortType:!0,onRenderCell(e,{col:n,row:t}){const{data:s}=t,i=s?s[n.name]:void 0;if(!(i!=null&&i.length))return e;const{avatarClass:o="circle",avatarKey:r=`${n.name}Avatar`,avatarSetting:l,avatarCodeKey:a,avatarNameKey:h=`${n.name}Name`,avatarBtnProps:c}=n.setting,u=(s?s[h]:i)||e[0],d={size:"xs",className:O(o,l==null?void 0:l.className,"flex-none"),src:s?s[r]:void 0,text:u,code:a?s?s[a]:void 0:i,...l},f=typeof c=="function"?c(e,n,t):c||{};return e[0]=C("button",{type:"button",className:"btn btn-avatar",...f},C(yc,{...d}),C("div",null,u)),e}}},onRenderCell(e,{row:n,col:t}){const{iconRender:s}=t.setting;if(typeof s!="function")return e;const i=s(n);return i&&e.unshift(typeof i=="object"?C("i",{...i}):C("i",{className:i})),e}},dd=Rt(ta,{buildIn:!0}),Pp="",Dp="",Hp="",Ip="",jp="",Wp="",Bp="",Fp="",zp="",Up="",Vp="",qp="",Gp="",Kp="";function ea(e){e=e||location.search,e[0]==="?"&&(e=e.substring(1));try{return JSON.parse('{"'+decodeURI(e).replace(/"/g,'\\"').replace(/&/g,'","').replace(/=/g,'":"')+'"}')}catch{return{}}}function pd(e){if(!e)return{url:e};const{config:n}=window;if(/^https?:\/\//.test(e)){const a=window.location.origin;if(!e.includes(a))return{external:!0,url:e};e=e.substring((a+n.webRoot).length)}const t=e.split("#"),s=t[0].split("?"),i=s[1],o=i?ea(i):{};let r=s[0];const l={url:e,isOnlyBody:o.onlybody==="yes",vars:[],hash:t[1]||"",params:o,tid:o.tid||""};if(n.requestType==="GET"){l.moduleName=o[n.moduleVar]||"index",l.methodName=o[n.methodVar]||"index",l.viewType=o[n.viewVar]||n.defaultView;for(const a in o)a!==n.moduleVar&&a!==n.methodVar&&a!==n.viewVar&&a!=="onlybody"&&a!=="tid"&&l.vars.push([a,o[a]])}else{let a=r.lastIndexOf("/");a===r.length-1&&(r=r.substring(0,a),a=r.lastIndexOf("/")),a>=0&&(r=r.substring(a+1));const h=r.lastIndexOf(".");h>=0?(l.viewType=r.substring(h+1),r=r.substring(0,h)):l.viewType=n.defaultView;const c=r.split(n.requestFix);if(l.moduleName=c[0]||"index",l.methodName=c[1]||"index",c.length>2)for(let u=2;u{const d=l[u];u==="tid"||u==="isOnlyBody"||u[0]==="$"||h.push(!c&&!h.includes("?")?"?":"&",u,"=",d)}),r&&a.tabSession&&h.push(!c&&!h.includes("?")?"?":"&","tid=",r),typeof o=="string"&&h.push(o.startsWith("#")?"":"#",o),h.join("")}const md=Object.freeze(Object.defineProperty({__proto__:null,createLink:na,parseLink:pd,parseUrlParams:ea},Symbol.toStringTag,{value:"Module"})),oi=new Map;function gd(e,n,t){const{zui:s}=window;oi.size||Object.keys(s).forEach(o=>{o[0]===o[0].toUpperCase()&&oi.set(o.toLowerCase(),s[o])});const i=oi.get(e.toLowerCase());return i?new i(n,t):null}window.$&&Object.assign(window.$,md),E.$=A,E.ActionMenu=mo,E.ActionMenuNested=go,E.AjaxForm=Ic,E.Avatar=Fo,E.BtnGroup=zo,E.Button=yo,E.ContextMenu=ct,E.DTable=qe,E.Dropdown=it,E.EventBus=Cn,E.Menu=_o,E.MenuTree=tr,E.Messager=We,E.Modal=ot,E.ModalTrigger=Be,E.Nav=Uo,E.NavTabs=Ve,E.Pager=Go,E.Picker=Ko,E.ProgressCircle=Ho,E.QuickMenu=er,E.SearchForm=nr,E.Switch=Io,E.TIME_DAY=kt,E.Toolbar=Yo,E.Tooltip=ft,E.addI18nMap=Fr,E.ajax=Yh,E.browser=Lh,E.bus=Xh,E.calculateTimestamp=qo,E.cash=Pl,E.componentsMap=oi,E.convertBytes=tu,E.create=gd,E.createDate=at,E.formatBytes=Za,E.formatDate=Ys,E.formatDateSpan=mf,E.formatString=st,E.getLangCode=Wr,E.getTimeBeforeDesc=gf,E.i18n=Pe,E.isDBY=pf,E.isObject=xs,E.isSameDay=Fe,E.isSameMonth=wc,E.isSameWeek=uf,E.isSameYear=Vo,E.isToday=hf,E.isTomorrow=df,E.isYesterday=ff,E.mergeDeep=Ss,E.nativeEvents=vs,E.setLangCode=Br,E.store=cc,E.zentao=dd,E.zentaoPlugin=ta,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})}); diff --git a/zin/config.php b/zin/config.php new file mode 100755 index 0000000000..0da4b03096 --- /dev/null +++ b/zin/config.php @@ -0,0 +1,21 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +global $app, $config; + +$config->zin = new \stdClass(); + +$config->zin->lang = $app->getClientLang(); +$config->zin->wgVer = isset($config->wgVer) ? $config->wgVer : '1'; +$config->zin->wgVerMap = isset($config->wgVerMap) ? $config->wgVerMap : array(); +$config->zin->zuiPath = isset($config->zuiPath) ? $config->zuiPath : ($app->getWebRoot() . 'js/zui3/'); diff --git a/zin/core/context.class.php b/zin/core/context.class.php new file mode 100644 index 0000000000..df41184084 --- /dev/null +++ b/zin/core/context.class.php @@ -0,0 +1,154 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'dataset.class.php'; +require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php'; +require_once 'portal.class.php'; + +class context extends \zin\utils\dataset +{ + /** + * @var object + */ + public $root; + + public function __construct($root) + { + $this->root = $root; + } + + public function isRoot($root) + { + if(is_string($root)) return $root === $this->root->gid; + return $root->gid === $this->root->gid; + } + + public function getPortals() + { + return $this->getList('portals'); + } + + public function addPortal($portal) + { + return $this->addToList('portals', $portal); + } + + public function addImport() + { + return $this->addToList('import', func_get_args()); + } + + public function getImportList() + { + return $this->getList('import'); + } + + public function addCSS() + { + return $this->addToList('css', func_get_args()); + } + + public function getCssList() + { + return $this->getList('css'); + } + + public function addJS() + { + return $this->addToList('js', func_get_args()); + } + + public function addJSVar($name, $value) + { + return $this->addToList('jsVar', h::createJsVarCode($name, $value)); + } + + public function addJSCall() + { + $code = call_user_func_array('\zin\h::createJsCallCode', func_get_args()); + \a(array('code', $code, $this->getJsList())); + return $this->addToList('jsCall', $code); + } + + public function getJsList() + { + return array_merge($this->getList('jsVar'), $this->getList('js'), $this->getList('jsCall')); + } + + public static $map = array(); + + public static function portal(/* string $name, mixed ...$children */) + { + $args = func_get_args(); + $name = array_shift($args); + $context = static::current(); + $portal = new portal(set::target($name), $args); + $context->addPortal($portal); + } + + public static function js(/* string ...$code */) + { + $context = static::current(); + call_user_func_array(array($context, 'addJS'), \zin\utils\flat(func_get_args())); + } + + public static function jsCall(/* string ...$code */) + { + $context = static::current(); + call_user_func_array(array($context, 'addJSCall'), func_get_args()); + } + + + public static function jsVar($name, $value) + { + $context = static::current(); + $context->addJSVar($name, $value); + } + + public static function css(/* string ...$code */) + { + $context = static::current(); + call_user_func_array(array($context, 'addCSS'), \zin\utils\flat(func_get_args())); + } + + public static function import(/* string ...$files */) + { + $context = static::current(); + call_user_func_array(array($context, 'addImport'), func_get_args()); + } + + /** + * Get current context + * @return context + */ + public static function current() + { + if(empty(static::$map)) static::$map['current'] = new context(NULL); + return static::$map['current']; + } + + public static function create($wg) + { + $gid = $wg->gid; + if(isset(static::$map[$gid])) return static::$map[$gid]; + $context = new context($wg); + static::$map[$gid] = $context; + return $context; + } + + public static function destroy($gid) + { + if($gid instanceof wg) $gid = $gid->gid; + if(isset(static::$map[$gid])) unset(static::$map[$gid]); + } +} diff --git a/zin/core/context.func.php b/zin/core/context.func.php new file mode 100644 index 0000000000..5d7a770644 --- /dev/null +++ b/zin/core/context.func.php @@ -0,0 +1,44 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'context.class.php'; + +function portal(/* string $name, mixed ...$children */) +{ + call_user_func_array('\zin\context::portal', func_get_args()); +} + +function js() +{ + call_user_func_array('\zin\context::js', func_get_args()); +} + +function jsCall() +{ + call_user_func_array('\zin\context::jsCall', func_get_args()); +} + +function jsVar() +{ + call_user_func_array('\zin\context::jsVar', func_get_args()); +} + +function css() +{ + call_user_func_array('\zin\context::css', func_get_args()); +} + +function import() +{ + call_user_func_array('\zin\context::import', func_get_args()); +} diff --git a/zin/core/data.func.php b/zin/core/data.func.php new file mode 100644 index 0000000000..2b2344f8a9 --- /dev/null +++ b/zin/core/data.func.php @@ -0,0 +1,52 @@ + + * @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) +{ + 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); +} diff --git a/zin/core/directive.class.php b/zin/core/directive.class.php new file mode 100644 index 0000000000..b6afc1f56b --- /dev/null +++ b/zin/core/directive.class.php @@ -0,0 +1,66 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'zin.class.php'; + +class directive +{ + public $type; + + public $data; + + public $options; + + public $parent = NULL; + + /** + * Construct a directive object + * @param string $type + * @param mixed $data + * @param array $options + * @access public + */ + public function __construct($type, $data, $options = NULL) + { + $this->type = $type; + $this->data = $data; + $this->options = $options; + + zin::renderInGlobal($this); + } + + public function __debugInfo() + { + return + [ + 'type' => $this->type, + 'data' => $this->data, + 'options' => $this->options + ]; + } + + public static function is($item, $type = NULL) + { + return is_object($item) && $item instanceof directive && ($type === NULL || $item->type === $type); + } +} + +function directive($type, $data, $options = NULL) +{ + return new directive($type, $data, $options); +} + +function isDirective($item, $type = NULL) +{ + return directive::is($item, $type); +} diff --git a/zin/core/dom.class.php b/zin/core/dom.class.php new file mode 100644 index 0000000000..ae82109830 --- /dev/null +++ b/zin/core/dom.class.php @@ -0,0 +1,354 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'deep.func.php'; +require_once 'selector.func.php'; + +class dom +{ + /** + * @var wg + */ + public $wg; + + public $children = []; + + public $selectors = NULL; + + public $renderInner = false; + + public $renderType; + + public $dataGetters = NULL; + + public $dataCommands; + + /** + * Construct the dom object. + * @param wg $wg + * @param array $children + * @param array|string|object $selectors + * @access public + */ + public function __construct($wg, $children, $selectors = NULL, $renderType = NULL, $dataCommands = NULL) + { + $this->wg = $wg; + $this->renderType = $renderType; + + $this->add($children); + $this->addSelectors($selectors); + $this->addDataCommands($dataCommands); + } + + public function __debugInfo() + { + return + [ + 'gid' => $this->wg->gid, + 'type' => $this->wg->type(), + 'count' => count($this->children), + 'renderInner' => $this->renderInner, + 'renderType' => $this->renderType, + 'selectors' => stringifyWgSelectors($this->selectors) + ]; + } + + public function add($children) + { + if(empty($children)) return; + + if(!is_array($children)) $children = [$children]; + foreach($children as $child) + { + if(is_array($child)) $this->add($child); + elseif(!empty($child)) $this->children[] = $child; + } + } + + public function addDataCommands($commands) + { + if(empty($commands)) return; + + if(is_string($commands)) + { + $commandList = explode(',', $commands); + $commands = []; + foreach($commandList as $command) + { + $parts = explode(':', $command, 2); + $commands[$parts[0]] = count($parts) > 1 ? $parts[1] : $parts[0]; + } + } + + if($this->dataCommands === NULL) $this->dataCommands = []; + $index = 0; + foreach($commands as $key => $command) + { + $this->dataCommands[$index == $key ? $command : $key] = $command; + $index++; + } + } + + public function addSelectors($selectors) + { + if(empty($selectors)) return; + + if($this->selectors === NULL) $this->selectors = []; + $selectors = parseWgSelectors($selectors); + foreach($selectors as $selector) + { + if(isset($selector->command) && !empty($selector->command)) $this->addDataCommands([$selector->tag => $selector->command]); + else $this->selectors[] = $selector; + } + } + + public function isMatch($selector) + { + return $this->wg->isMatch($selector); + } + /** + * Build the children dom list. + * @access public + * @return array + */ + public function build() + { + $list = []; + $children = $this->renderInner ? $this->wg->children() : $this->children; + + if(empty($children)) return $list; + + foreach($children as $child) + { + $list[] = ($child instanceof wg) ? $child->buildDom() : $child; + } + + if(!empty($this->selectors)) + { + $list = static::filter($list, $this->selectors); + } + return $list; + } + + public function render() + { + if($this->renderType === 'json') return $this->renderJson(); + if($this->renderType === 'list') return $this->renderList(); + return $this->renderHtml(); + } + + public function renderJson() + { + $list = $this->build(); + if(empty($list)) return '{}'; + + $output = []; + foreach($list as $name => $item) + { + $output[$name] = static::renderItemToJson($item); + } + + if(!empty($this->dataCommands)) + { + $data = []; + foreach($this->dataCommands as $name => $command) + { + $data[$name] = data($command); + } + $output['data'] = $data; + } + + return json_encode($output); + } + + public function renderHtml() + { + $list = $this->build(); + if(empty($list)) return ''; + + $output = []; + foreach($list as $item) + { + $result = static::renderItemToHtml($item); + if(!is_string($result)) $result = json_encode($result); + $output[] = $result; + } + return implode('', $output); + } + + public function renderList() + { + $list = $this->build(); + if(empty($list)) return '[]'; + + $output = []; + foreach($list as $name => $item) + { + if(is_array($item) && count($item) === 1) $item = $item[0]; + $output[] = ['name' => $name, 'data' => static::renderDomItem($item)]; + } + + if(!empty($this->dataCommands)) + { + foreach($this->dataCommands as $name => $command) + { + $output[] = ['name' => $name, 'data' => data($command)]; + } + } + + return json_encode($output); + } + + public static function renderDomItem($item, $defaultType = 'html') + { + if($item instanceof dom) + { + $renderType = $item->renderType; + if(empty($renderType)) $renderType = $defaultType; + if($renderType === 'json') return dom::renderItemToJson($item); + return dom::renderItemToHtml($item->build()); + } + + $renderType = $defaultType; + if($renderType === 'json') return static::renderItemToJson($item); + return static::renderItemToHtml($item); + } + + public static function renderItemToJson($item) + { + if($item === NULL || is_bool($item)) return NULL; + + if(is_array($item)) + { + $output = []; + foreach($item as $subItem) $output[] = static::renderItemToJson($subItem); + return $output; + } + + if($item instanceof dom) + { + $json = $item->wg->toJsonData(); + if(!empty($item->dataGetters)) + { + $output = []; + $props = explode(',', $item->dataGetters); + foreach($props as $prop) + { + $prop = trim($prop); + if(empty($prop)) continue; + + $parts = explode(':', $prop, 2); + $name = $parts[0]; + $namePath = count($parts) > 1 ? $parts[1] : $parts[0]; + $output[$name] = \zin\utils\deepGet($json, $namePath); + } + return $output; + } + return $json; + } + if($item instanceof wg) return dom::renderDomItem($item, 'json'); + if(is_string($item)) return $item; + + if(is_object($item)) + { + if(isDirective($item, 'html')) return $item->data; + if(isDirective($item, 'text')) return htmlspecialchars($item->data); + if(isset($item->html)) return $item->html; + if(isset($item->text)) return htmlspecialchars($item->text); + if(method_exists($item, 'render')) return $item->render(); + } + + return strval($item); + } + + public static function renderItemToHtml($item) + { + if($item === NULL || is_bool($item)) return ''; + + if(is_array($item)) + { + $output = []; + foreach($item as $subItem) $output[] = static::renderItemToHtml($subItem); + return implode('', $output); + } + + if($item instanceof dom) return dom::renderItemToHtml($item->build()); + if($item instanceof wg) return $item->render(); + if(is_string($item)) return $item; + + if(is_object($item)) + { + if(isDirective($item, 'html')) return $item->data; + if(isDirective($item, 'text')) return htmlspecialchars($item->data); + if(isset($item->html)) return $item->html; + if(isset($item->text)) return htmlspecialchars($item->text); + if(method_exists($item, 'render')) return $item->render(); + } + + return strval($item); + } + + /** + * Filter the dom list with selector. + * @param array $list + * @param object $selector + * @param array $filteredList + * @access public + * @return array + */ + public static function filterList(&$list, $selector, &$filteredList) + { + if(empty($list) || empty($selector)) return []; + + $results = []; + foreach($list as $item) + { + if(!($item instanceof dom) || in_array($item->wg->gid, $filteredList)) continue; + + if($item->wg->isMatch($selector)) + { + $item->renderInner = $selector->inner ?? false; + $item->renderType = $selector->type ?? NULL; + $item->dataGetters = $selector->data ?? NULL; + $filteredList[] = $item->wg->gid; + $results[] = $item; + } + else + { + $children = $item->build(); + if(!empty($children)) + { + $subResults = static::filterList($children, $selector, $filteredList); + foreach($subResults as $subItem) $results[] = $subItem; + } + } + if($selector->first && !empty($results)) break; + } + return $results; + } + + public static function filter(&$domList, $selectors) + { + if(empty($selectors)) return $domList; + + $list = []; + $filteredList = []; + foreach($selectors as $selector) + { + $results = static::filterList($domList, $selector, $filteredList); + if(!empty($results)) $list[$selector->name] = $results; + } + + return $list; + } +} diff --git a/zin/core/h.class.php b/zin/core/h.class.php new file mode 100644 index 0000000000..ce10e91868 --- /dev/null +++ b/zin/core/h.class.php @@ -0,0 +1,307 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php'; +require_once 'wg.class.php'; +require_once 'wg.func.php'; + +class h extends wg +{ + protected static $defineProps = 'tagName, selfClose?:bool=false'; + + public function getTagName() + { + return $this->props->get('tagName'); + } + + public function isDomElement() + { + 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() + { + $events = $this->buildEvents(); + + if($this->isSelfClose()) return array($this->buildSelfCloseTag(), $events); + + return array($this->buildTagBegin(), parent::build(), $this->getPortals(), $this->buildTagEnd(), $events); + } + + public function toJsonData() + { + $data = parent::toJsonData(); + $data['type'] = 'h:' . $this->getTagName(); + return $data; + } + + public function type() + { + return $this->getTagName(); + } + + public function shortType() + { + return $this->getTagName(); + } + + protected function getPropsStr() + { + $propStr = $this->props->toStr(array_keys(static::getDefinedProps())); + if($this->props->hasEvent() && empty($this->id()) && $this->getTagName() !== 'html') $propStr = "$propStr id='$this->gid'"; + return empty($propStr) ? '' : " $propStr"; + } + + protected function buildEvents() + { + $events = $this->props->events(); + if(empty($events)) return NULL; + + $id = $this->id(); + $code = array($this->getTagName() === 'html' ? 'const ele = document;' : 'const ele = document.getElementById("' . (empty($id) ? $this->gid : $id) . '");'); + foreach($events as $event => $bindingList) + { + foreach($bindingList as $binding) + { + $code[] = "ele.addEventListener('$event', function(e) {"; + 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; + unset($binding->selector); + unset($binding->handler); + unset($binding->stop); + unset($binding->prevent); + unset($binding->self); + + if($selector) $code[] = "if(!e.target.closest('$selector')) return;"; + 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)(e);"; + else $code[] = $handler; + + $code[] = '}' . (empty($binding) ? '' : (', ' . json_encode($binding))) . ');'; + } + } + return static::js($code); + } + + protected function buildSelfCloseTag() + { + $tagName = $this->getTagName(); + $propStr = $this->getPropsStr(); + return "<$tagName$propStr />"; + } + + protected function buildTagBegin() + { + $tagName = $this->getTagName(); + $propStr = $this->getPropsStr(); + return "<$tagName$propStr>"; + } + + protected function buildTagEnd() + { + $tagName = $this->getTagName(); + return ""; + } + + public static function create() + { + $args = func_get_args(); + $tagName = array_shift($args); + return new h(is_string($tagName) ? prop('tagName', $tagName) : $tagName, $args); + } + + public static function __callStatic($tagName, $args) + { + return new h(prop('tagName', $tagName), $args); + } + + public static function button() + { + return static::create('button', prop('type', 'button'), func_get_args()); + } + + public static function input() + { + return static::create('input', prop('type', 'text'), func_get_args()); + } + + public static function formHidden($name, $value, ...$args) + { + return static::create('input', prop('type', 'hidden'), set::name($name), set::value($value), $args); + } + + public static function checkbox() + { + return static::create('input', prop('type', 'checkbox'), func_get_args()); + } + + public static function radio() + { + return static::create('input', prop('type', 'radio'), func_get_args()); + } + + public static function date() + { + return static::create('input', prop('type', 'date'), func_get_args()); + } + + public static function file() + { + return static::create('input', prop('type', 'file'), func_get_args()); + } + + public static function textarea(...$args) + { + list($code, $args) = h::splitRawCode($args); + return static::create('textarea', $code, ...$args); + } + + public static function importJs($src, ...$args) + { + return static::create('script', prop('src', $src), ...$args); + } + + public static function importCss($src, ...$args) + { + return static::create('link', prop('rel', 'stylesheet'), prop('href', $src), ...$args); + } + + public static function import($file, $type = NULL, ...$args) + { + if(is_array($file)) + { + $children = array(); + foreach($file as $file) + { + $children[] = static::import($file, $type); + } + return $children; + } + if($type === NULL) $type = pathinfo($file, PATHINFO_EXTENSION); + if($type == 'js' || $type == 'cjs') return static::importJs($file, ...$args); + if($type == 'css') return static::importCss($file, ...$args); + return null; + } + + public static function css(...$args) + { + list($code, $args) = h::splitRawCode($args); + if(empty($code)) return NULL; + return static::create('style', html(implode("\n", $code)), ...$args); + } + + public static function globalJS(...$args) + { + list($code, $args) = h::splitRawCode($args); + if(empty($code)) return NULL; + return static::create('script', html(implode("\n", $code)), ...$args); + } + + public static function js(...$args) + { + + list($code, $args) = h::splitRawCode($args); + if(empty($code)) return NULL; + return static::create('script', html('(function(){'. implode("\n", $code) . '}())'), ...$args); + } + + public static function jsVar($name, $value, ...$directives) + { + return static::js(static::createJsVarCode($name, $value), ...$directives); + } + + public static function jsCall($funcName, ...$args) + { + $funcArgs = []; + $directives = []; + 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); + } + + 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 jsRaw() + { + return 'RAWJS<' . implode("\n", func_get_args()) . '>RAWJS'; + } + + protected static function encodeJsonWithRawJs($data) + { + $json = json_encode($data, JSON_UNESCAPED_UNICODE); + $json = str_replace('"RAWJS<', '', str_replace('>RAWJS"', '', $json)); + return $json; + } + + protected static function splitRawCode($children) + { + $children = \zin\utils\flat($children); + $code = []; + $args = []; + foreach($children as $key => $child) + { + if(is_string($child)) $code[] = $child; + else $args[] = $child; + } + return [$code, $args]; + } + + public static $selfCloseTags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']; +} diff --git a/zin/core/h.func.php b/zin/core/h.func.php new file mode 100644 index 0000000000..983112a15e --- /dev/null +++ b/zin/core/h.func.php @@ -0,0 +1,46 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'h.class.php'; +require_once 'item.class.php'; +require_once 'wg.func.php'; +require_once 'set.class.php'; +require_once 'to.class.php'; +require_once 'data.func.php'; +require_once 'on.class.php'; + +function h() {return call_user_func_array('\zin\h::create', func_get_args());} + +function div() {return call_user_func_array('\zin\h::div', func_get_args());} +function span() {return call_user_func_array('\zin\h::span', func_get_args());} +function code() {return call_user_func_array('\zin\h::code', func_get_args());} +function canvas() {return call_user_func_array('\zin\h::canvas', func_get_args());} +function br() {return call_user_func_array('\zin\h::br', func_get_args());} +function a() {return call_user_func_array('\zin\h::a', func_get_args());} +function p() {return call_user_func_array('\zin\h::p', func_get_args());} +function img() {return call_user_func_array('\zin\h::img', func_get_args());} +function button() {return call_user_func_array('\zin\h::button', func_get_args());} +function h1() {return call_user_func_array('\zin\h::h1', func_get_args());} +function h2() {return call_user_func_array('\zin\h::h2', func_get_args());} +function h3() {return call_user_func_array('\zin\h::h3', func_get_args());} +function h4() {return call_user_func_array('\zin\h::h4', func_get_args());} +function h5() {return call_user_func_array('\zin\h::h5', func_get_args());} +function h6() {return call_user_func_array('\zin\h::h6', func_get_args());} +function ul() {return call_user_func_array('\zin\h::ul', func_get_args());} +function li() {return call_user_func_array('\zin\h::li', func_get_args());} +function template() {return call_user_func_array('\zin\h::template', func_get_args());} +function formHidden() {return call_user_func_array('\zin\h::formHidden', func_get_args());} +function fieldset() {return call_user_func_array('\zin\h::fieldset', func_get_args());} +function legend() {return call_user_func_array('\zin\h::legend', func_get_args());} + +function jsRaw() {return call_user_func_array('\zin\h::jsRaw', func_get_args());} diff --git a/zin/core/item.class.php b/zin/core/item.class.php new file mode 100644 index 0000000000..4eec23e72d --- /dev/null +++ b/zin/core/item.class.php @@ -0,0 +1,32 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'wg.class.php'; +require_once 'wg.func.php'; + +class item extends wg +{ + public function build() + { + if($this->parent instanceof wg && method_exists($this->parent, 'onBuildItem')) + { + return call_user_func(array($this->parent, 'onBuildItem'), $this); + } + return parent::build(); + } +} + +function item() +{ + return new item(func_get_args()); +} diff --git a/zin/core/on.class.php b/zin/core/on.class.php new file mode 100644 index 0000000000..7990c3ea50 --- /dev/null +++ b/zin/core/on.class.php @@ -0,0 +1,23 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'wg.func.php'; + +class on +{ + public static function __callStatic($name, $args) + { + list($callback, $options) = array_merge($args, array(NULL)); + return on($name, $callback, $options); + } +} diff --git a/zin/core/portal.class.php b/zin/core/portal.class.php new file mode 100644 index 0000000000..0d306bcbe9 --- /dev/null +++ b/zin/core/portal.class.php @@ -0,0 +1,24 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'wg.class.php'; + +class portal extends wg +{ + static $defineProps = 'target:string'; + + public static function __callStatic($name, $args) + { + return new portal(set('target', $name), $args); + } +} diff --git a/zin/core/props.class.php b/zin/core/props.class.php new file mode 100755 index 0000000000..863f3deac4 --- /dev/null +++ b/zin/core/props.class.php @@ -0,0 +1,251 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'dataset.class.php'; +require_once dirname(__DIR__) . DS . 'utils' . DS . 'classlist.class.php'; +require_once dirname(__DIR__) . DS . 'utils' . DS . 'style.class.php'; + +/** + * Manage properties for html element and widgets + */ +class props extends \zin\utils\dataset +{ + /** + * Style property + * + * @access public + * @var style + */ + public $style; + + /** + * Class property + * + * @access public + * @var classlist + */ + public $class; + + /** + * Create properties instance + * + * @access public + * @param array $props - Properties list array + */ + public function __construct($props = NULL) + { + $this->style = new \zin\utils\style(); + $this->class = new \zin\utils\classlist(); + + parent::__construct($props); + } + + /** + * Method for sub class to modify value on setting it + * + * @access public + * @param array|string $prop - Property name or properties list + * @param mixed $value - Property value + */ + protected function setVal($prop, $value) + { + if($prop === 'class' || $prop === '.') $this->class->set($value); + elseif($prop === 'style' || $prop === '~') $this->style->set($value); + 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); + else parent::setVal($prop, $value); + return $this; + } + + protected function getVal($prop) + { + if($prop === 'class' || $prop === '.') + { + if(!$this->class->count()) return NULL; + return $this->class->toStr(); + } + if($prop === 'style' || $prop === '~') + { + if(!$this->style->count(true)) return NULL; + return $this->style->toStr(); + } + return parent::getVal($prop); + } + + public function reset($name, $value = NULL) + { + if(is_array($name)) + { + foreach($name as $n) $this->reset($n); + return; + } + if($name === 'class') return $this->class->clear(); + if($name === 'style') return $this->style->clear(); + + $this->remove($name); + if($value) $this->setVal($name, $value); + } + + public function bindEvent($name, $callback = NULL) + { + if(is_array($name)) + { + foreach($name as $key => $value) $this->bindEvent($key, $value); + return; + } + + $events = parent::getVal("@$name") ?? []; + if(is_array($callback)) $events = array_merge($events, $callback); + else $events[] = $callback; + + parent::setVal("@$name", $events); + } + + public function events() + { + $events = array(); + foreach($this->data as $name => $value) + { + if(str_starts_with($name, '@')) $events[substr($name, 1)] = $value; + } + + return $events; + } + + public function hasEvent() + { + foreach($this->data as $name => $value) + { + if(str_starts_with($name, '@')) return true; + } + + return false; + } + + public function hx($name, $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 + * + * Example: + * + * // Properties data map: + * $map = array( + * 'id' => 'sayHelloBtn', + * 'data-title' => 'Say "Hello"!', + * 'data-content' => NULL, + * 'data-show' => true, + * ); + * // Output string: id="sayHelloBtn" data-title="Say "Hello"!" data-show="true" + * + * @access public + */ + public function toStr($skipProps = array()) + { + if(is_string($skipProps)) $skipProps = explode(',', $skipProps); + + $pairs = array(); + + if($this->class->count()) $pairs[] = 'class="' . $this->class->toStr() . '"'; + if($this->style->count(true)) $pairs[] = 'style="' . $this->style->toStr() . '"'; + + foreach($this->data as $name => $value) + { + /* Handle boolean attributes */ + if(in_array($name, static::$booleanAttrs)) $value = $value ? true : NULL; + + /* Skip any null value or events setting */ + if($value === NULL || in_array($name, $skipProps) || $name[0] === '@') continue; + + /* Convert non-string to json */ + if($value === true && !str_starts_with($name, 'data-')) + { + $pairs[] = $name; + } + else + { + if(!is_string($value)) $value = json_encode($value); + + $pairs[] = $name . '="' . htmlspecialchars($value) . '"'; + } + } + + return implode(' ', $pairs); + } + + public function toJsonData() + { + $data = $this->data; + if(!empty($this->style->data)) $data['style'] = $this->style->data; + if(!empty($this->class->list)) $data['class'] = $this->class->toStr(); + return $data; + } + + public function skip($skipProps = array(), $skipFalse = false) + { + if(is_string($skipProps)) $skipProps = explode(',', $skipProps); + + $data = $this->toJsonData(); + if($skipFalse) $data = array_filter($data, function($v) {return $v !== false;}); + foreach($data as $name => $value) + { + if($value === NULL || in_array($name, $skipProps)) unset($data[$name]); + } + + return $data; + } + + public function pick($pickProps = array()) + { + if(is_string($pickProps)) $pickProps = explode(',', $pickProps); + + $data = $this->toJsonData(); + foreach($data as $name => $value) + { + if($value === NULL || !in_array($name, $pickProps)) unset($data[$name]); + } + + return $data; + } + + /** + * Clone a new instance + * + * @access public + * @return object + */ + public function clone() + { + $props = new props($this->data); + $props->style = clone $this->style; + $props->class = clone $this->class; + return $props; + } + + public static $booleanAttrs = ['allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', 'defer', 'disabled', 'formnovalidate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open', 'playsinline', 'readonly', 'required', 'reversed', 'selected']; +} diff --git a/zin/core/render.func.php b/zin/core/render.func.php new file mode 100644 index 0000000000..9c2f567a55 --- /dev/null +++ b/zin/core/render.func.php @@ -0,0 +1,44 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'zin.class.php'; + +function render($wgName = 'page', $options = NULL) +{ + $args = []; + foreach(zin::$globalRenderList as $item) + { + if(is_object($item) && isset($item->parent) && $item->parent) continue; + $args[] = $item; + } + + if(is_string($wgName) && isset(zin::$globalRenderMap[$wgName])) $wgName = zin::$globalRenderMap[$wgName]; + + if($wgName === 'page' || $wgName === 'pagebase') $args[] = set::display(false); + + if($options === NULL) + { + if(isset($_SERVER['HTTP_X_ZIN_OPTIONS']) && !empty($_SERVER['HTTP_X_ZIN_OPTIONS'])) + { + $setting = $_SERVER['HTTP_X_ZIN_OPTIONS']; + $options = $setting[0] === '{' ? json_decode($setting, true) : ['selector' => $setting]; + } + } + + global $app; + data('zinErrors', $app->zinErrors ?? []); + + $wg = createWg($wgName, $args); + if($wgName !== 'page' && $wgName !== 'pagebase') $wg = fragment($wg); + $wg->display($options); +} diff --git a/zin/core/selector.func.php b/zin/core/selector.func.php new file mode 100644 index 0000000000..408f610d8e --- /dev/null +++ b/zin/core/selector.func.php @@ -0,0 +1,151 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +/** + * Parse wg selector + * @param string|object $selector + * @return object|null + */ +function parseWgSelector($selector) +{ + if(is_object($selector)) return $selector; + + $selector = trim($selector); + $len = strlen($selector); + + if($len < 1) return NULL; + + $result = ['class' => [], 'id' => NULL, 'tag' => NULL, 'inner' => false, 'name' => NULL, 'first' => false, 'selector' => $selector]; + if(str_contains($selector, '/')) + { + $parts = explode('/', $selector, 2); + $result['name'] = $parts[0]; + $selector = $parts[1]; + $len = strlen($selector); + } + $selector = str_replace('> *', '>*', $selector); + if(substr($selector, strlen($selector) - 2) == '>*') + { + $result['inner'] = true; + $selector = substr($selector, 0, strlen($selector) - 2); + $len = strlen($selector); + } + + $type = 'tag'; + $current = ''; + $updateResult = function(&$result, $current, $type) + { + if(empty($current)) return; + + if($type === 'class') + { + $result[$type][] = $current; + } + elseif($type === 'option') + { + $options = []; + parse_str($current, $options); + foreach($options as $key => $value) $result[$key] = empty($value) ? true : $value; + } + else + { + $result[$type] = $current; + } + }; + + for($i = 0; $i < $len; $i++) + { + $c = $selector[$i]; + $t = ''; + + if($c === '#' & $type !== 'option') + { + $t = 'id'; + } + elseif($c === '.' & $type !== 'option') + { + $t = 'class'; + } + elseif($c === '(' && $type !== 'option' && str_ends_with($selector, ')')) + { + $command = substr($selector, $i + 1, -1); + if(empty($command)) $command = $current; + $result['command'] = $command; + break; + } + elseif($c === ':') + { + $t = 'option'; + } + + if(empty($t)) + { + $current .= $c; + } + else + { + $updateResult($result, $current, $type); + $current = ''; + $type = $t; + } + } + $updateResult($result, $current, $type); + + if(empty($result['class'])) $result['class'] = NULL; + if(empty($result['name'])) + { + if(!empty($result['id'])) $result['name'] = $result['id']; + elseif(!empty($result['tag'])) $result['name'] = $result['tag']; + else $result['name'] = $selector; + } + + return (object)$result; +} + +/** + * Parse wg selectors + * @param array|string|object $selectors + * @return array + */ +function parseWgSelectors($selectors) +{ + if(is_object($selectors)) return [$selectors]; + if(is_string($selectors)) $selectors = explode(',', trim($selectors)); + $results = []; + foreach($selectors as $selector) + { + $selector = parseWgSelector($selector); + if(is_object($selector)) $results[] = $selector; + } + return $results; +} + +function stringifyWgSelectors($selector) +{ + if(empty($selector)) return ''; + if(is_array($selector)) + { + $result = []; + foreach($selector as $s) $result[] = stringifyWgSelectors($s); + return implode(',', $result); + } + + $result = ''; + if(!empty($selector->name) && $selector->name !== $selector->selector) $result .= $selector->name . '/'; + if(!empty($selector->tag)) $result .= $selector->tag; + if(!empty($selector->id)) $result .= '#' . $selector->id; + if(!empty($selector->class)) $result .= '.' . implode('.', $selector->class); + if(!empty($selector->first)) $result .= ':first'; + if($selector->inner) $result .= '>*'; + return $result; +} diff --git a/zin/core/set.class.php b/zin/core/set.class.php new file mode 100644 index 0000000000..db7d10f589 --- /dev/null +++ b/zin/core/set.class.php @@ -0,0 +1,30 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'directive.class.php'; + +class set +{ + public static function __callStatic($prop, $args) + { + $value = array_shift($args); + if(is_object($value)) $value = (array)$value; + if($prop === '_' && is_array($value)) return directive('prop', $value); + return directive('prop', array($prop => $value)); + } + + public static function class(...$args) + { + return directive('prop', ['class' => $args]); + } +} diff --git a/zin/core/to.class.php b/zin/core/to.class.php new file mode 100644 index 0000000000..b54f50ad44 --- /dev/null +++ b/zin/core/to.class.php @@ -0,0 +1,22 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'directive.class.php'; + +class to +{ + public static function __callStatic($name, $args) + { + return directive('block', array($name => $args)); + } +} diff --git a/zin/core/wg.class.php b/zin/core/wg.class.php new file mode 100644 index 0000000000..cbb6409100 --- /dev/null +++ b/zin/core/wg.class.php @@ -0,0 +1,623 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'props.class.php'; +require_once 'directive.class.php'; +require_once 'zin.class.php'; +require_once 'context.class.php'; +require_once 'selector.func.php'; +require_once 'dom.class.php'; + +class wg +{ + /** + * Define props for the element + * + * @todo @sunhao: Support for using string + * @var array|string + */ + protected static $defineProps = NULL; + + protected static $defaultProps = NULL; + + protected static $defineBlocks = NULL; + + protected static $wgToBlockMap = array(); + + protected static $definedPropsMap = array(); + + private static $gidSeed = 0; + + private static $pageResources = array(); + + /** + * The props of the element + * + * @access public + * @var props + */ + public $props; + + public $blocks = array(); + + public $parent = NULL; + + public $gid; + + public $displayed = false; + + protected $matchedPortals = NULL; + + protected $renderOptions = NULL; + + public function __construct(/* string|element|object|array|null ...$args */) + { + $this->props = new props(); + + $this->gid = self::nextGid(); + $this->setDefaultProps(static::getDefaultProps()); + $this->add(func_get_args()); + $this->created(); + + zin::renderInGlobal($this); + static::checkPageResources(); + } + + public function __debugInfo() + { + return $this->toJsonData(); + } + + public function isDomElement() + { + return false; + } + + /** + * Check if the element is match any of the selectors + * @param string|array|object $selectors + */ + public function isMatch($selectors) + { + $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; + } + + protected function checkPortals() + { + $this->matchedPortals = array(); + $portals = context::current()->getPortals(); + foreach($portals as $portal) + { + if($this->isMatch($portal->prop('target'))) $this->matchedPortals[] = $portal->children(); + } + } + + protected function getPortals() + { + $portals = $this->matchedPortals; + $this->matchedPortals = NULL; + return $portals; + } + + /** + * Build dom object + * @return dom + */ + public function buildDom() + { + $this->checkPortals(); + + $before = $this->buildBefore(); + $children = $this->build(); + $after = $this->buildAfter(); + $portals = $this->getPortals(); + $options = $this->renderOptions; + $selectors = (!empty($options) && isset($options['selector'])) ? $options['selector'] : NULL; + + return new dom + ( + $this, + [$before, $children, $portals, $after], + $selectors, + (!empty($options) && isset($options['type'])) ? $options['type'] : 'html', + (!empty($options) && isset($options['data'])) ? $options['data'] : NULL, + ); + } + + /** + * Render widget to html + * @return string + */ + public function render() + { + $dom = $this->buildDom(); + $html = $dom->render(); + + context::destroy($this->gid); + + return $html; + } + + public function display($options = []) + { + zin::disableGlobalRender(); + + $this->renderOptions = $options; + + echo $this->render(); + + $this->displayed = true; + return $this; + } + + protected function created() {} + + protected function buildBefore() + { + return $this->block('before'); + } + + protected function buildAfter() + { + return $this->block('after'); + } + + protected function build() + { + return $this->children(); + } + + protected function onAddBlock($child, $name) + { + return $child; + } + + protected function onAddChild($child) + { + return $child; + } + + protected function onSetProp($prop, $value) + { + if($prop === 'id' && $value === '$GID') $value = $this->gid; + $this->props->set($prop, $value); + } + + protected function onGetProp($prop, $defaultValue) + { + return $this->props->get($prop, $defaultValue); + } + + public function add($item, $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 wg) $this->addToBlock($blockName, $item); + elseif(is_string($item)) $this->addToBlock($blockName, htmlentities($item)); + elseif(isDirective($item)) $this->directive($item, $blockName); + else $this->addToBlock($blockName, htmlentities(strval($item))); + + zin::enableGlobalRender(); + + return $this; + } + + public function addToBlock($name, $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($child instanceof wg && $child->type() === 'zin\portal') return; + + 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() + { + return $this->block('children'); + } + + public function block($name) + { + return isset($this->blocks[$name]) ? $this->blocks[$name] : array(); + } + + public function hasBlock($name) + { + return isset($this->blocks[$name]); + } + + /** + * Apply directive + * @param object $directive + */ + public function directive(&$directive, $blockName) + { + $data = $directive->data; + $type = $directive->type; + $directive->parent = &$this; + + if($type === 'prop') + { + $this->setProp($data); + return; + } + if($type === 'class' || $type === 'style') + { + $this->setProp($type, $data); + return; + } + if($type === 'cssVar') + { + $this->setProp('--', $data); + return; + } + if($type === 'html') + { + $this->addToBlock($blockName, $directive); + return; + } + if($type === 'text') + { + $this->addToBlock($blockName, htmlspecialchars($data)); + return; + } + if($type === 'block') + { + foreach($data as $blockName => $blockChildren) + { + $this->add($blockChildren, $blockName); + } + return; + } + } + + public function prop($name, $defaultValue = NULL) + { + 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 array|string $prop - Property name or properties list + * @param mixed $value - Property value + * @return dataset + */ + public function setProp($prop, $value = NULL) + { + if($prop instanceof props) $prop = $prop->toJsonData(); + + 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->onSetProp($prop, $value); + return $this; + } + + public function hasProp() + { + $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($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() + { + return $this->props->skip(array_keys(static::getDefinedProps())); + } + + public function type() + { + return get_called_class(); + } + + public function shortType() + { + $type = $this->type(); + $pos = strrpos($type, '\\'); + return $pos === false ? $type : substr($type, $pos + 1); + } + + public function id() + { + return $this->prop('id'); + } + + public function toJsonData() + { + $data = array(); + $data['gid'] = $this->gid; + $data['props'] = $this->props->toJsonData(); + + $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, 'toJsonData'))) + { + $value[$index] = $child->toJsonData(); + } + 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; + } + + protected static function getDefaultProps() + { + $defaultProps = array(); + foreach(static::getDefinedProps() as $name => $definition) + { + if(!isset($definition['default'])) continue; + $defaultProps[$name] = $definition['default']; + } + return $defaultProps; + } + + public static function getPageCSS() {} + + public static function getPageJS() {} + + protected static function checkPageResources() + { + $name = get_called_class(); + if(isset(static::$pageResources[$name])) return; + + static::$pageResources[$name] = true; + + $pageCSS = static::getPageCSS(); + $pageJS = static::getPageJS(); + + if(!empty($pageCSS)) context::css($pageCSS); + if(!empty($pageJS)) context::js($pageJS); + } + + public static function wgBlockMap() + { + $wgName = get_called_class(); + if(!isset(wg::$wgToBlockMap[$wgName])) + { + $wgBlockMap = array(); + if(isset(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) + { + $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; + } + + public static function nextGid() + { + return 'zin' . (++static::$gidSeed); + } + + protected static function getDefinedProps($name = NULL) + { + if($name === NULL) $name = get_called_class(); + + if(!isset(wg::$definedPropsMap[$name]) && $name === get_called_class()) + { + wg::$definedPropsMap[$name] = static::parsePropsDefinition(static::$defineProps); + } + return wg::$definedPropsMap[$name]; + } + + /** + * Parse props definition + * @param $definition + * @example + * + * $definition = 'name,desc:string,title?:string|element,icon?:string="star"' + * $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($definition) + { + $parentClass = get_parent_class(get_called_class()); + $props = $parentClass ? call_user_func("$parentClass::getDefinedProps") : array(); + + if((!is_array($definition) && !is_string($definition)) || ($parentClass && $definition === $parentClass::$defineProps)) + { + if(static::$defaultProps && static::$defaultProps !== $parentClass::$defaultProps) + { + foreach($props as $name => $value) + { + if(is_array(static::$defaultProps) && isset(static::$defaultProps[$name])) + { + $value['default'] = static::$defaultProps[$name]; + $props[$name] = $value; + } + } + } + return $props; + } + + if(is_string($definition)) $definition = explode(',', $definition); + + 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; + } +} diff --git a/zin/core/wg.func.php b/zin/core/wg.func.php new file mode 100644 index 0000000000..8a91e60fbc --- /dev/null +++ b/zin/core/wg.func.php @@ -0,0 +1,170 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'flat.func.php'; +require_once 'props.class.php'; +require_once 'directive.class.php'; +require_once 'wg.class.php'; +require_once 'context.func.php'; + +function set($name, $value = NULL) +{ + 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); + if($props) return directive('prop', $props); +} + +function prop($name, $value = NULL) +{ + return set($name, $value); +} + +function setClass() +{ + return directive('class', func_get_args()); +} + +function setStyle($name, $value = NULL) +{ + return directive('style', is_array($name) ? $name : array($name => $value)); +} + +function setCssVar($name, $value = NULL) +{ + return directive('cssVar', is_array($name) ? $name : array($name => $value)); +} + +function setId($id) +{ + return prop('id', $id); +} + +function setTag($id) +{ + return prop('tagName', $id); +} + +function on($name, $handler, $options = NULL) +{ + if(is_string($options) && is_string($handler)) + { + $options = array('selector' => $handler, 'handler' => $options); + } + elseif(is_bool($options)) + { + $options = array('capture' => $options, 'handler' => $handler); + } + elseif(is_array($options)) + { + $options['handler'] = $handler; + } + else + { + $options = array('handler' => $handler); + } + if(str_contains($name, '__')) + { + list($name, $flags) = explode('__', $name); + if(str_contains($flags, 'capture')) $options['capture'] = true; + if(str_contains($flags, 'stop')) $options['stop'] = true; + if(str_contains($flags, 'prevent')) $options['prevent'] = true; + if(str_contains($flags, 'self')) $options['self'] = true; + } + return set("@$name", (object)$options); +} + +function html(/* string ...$lines */) +{ + return directive('html', implode("\n", \zin\utils\flat(func_get_args()))); +} + +function text(/* string ...$lines */) +{ + return directive('text', implode("\n", \zin\utils\flat(func_get_args()))); +} + +function block($name, $value = NULL) +{ + return directive('block', is_array($name) ? $name : array($name => $value)); +} + +function to($name, $value = NULL) +{ + return block($name, $value); +} + +function before() +{ + return directive('block', array('before' => func_get_args())); +} + +function after() +{ + return directive('block', array('after' => func_get_args())); +} + +function inherit($item) +{ + if(!($item instanceof wg)) $item = new wg($item); + return array(set($item->props), $item->children()); +} + +function divorce($item) +{ + if($item instanceof wg) + { + $item->parent = NULL; + } + else if(is_array($item)) + { + foreach($item as $i) divorce($i); + } + return $item; +} + +function hasWgInList($items, $type) +{ + if(!is_array($items)) $items = array($items); + foreach($items as $item) + { + if($item instanceof wg && $item->type() == $type) return true; + } + return false; +} + +function groupWgInList($items, $types) +{ + 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; +} diff --git a/zin/core/zin.class.php b/zin/core/zin.class.php new file mode 100644 index 0000000000..61cb210a55 --- /dev/null +++ b/zin/core/zin.class.php @@ -0,0 +1,52 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'utils' . DS . 'deep.func.php'; + +class zin +{ + public static $globalRenderList = array(); + + public static $enabledGlobalRender = true; + + public static $globalRenderMap = array(); + + public static $data = array(); + + public static function getData($namePath, $defaultValue = NULL) + { + return \zin\utils\deepGet(self::$data, $namePath, $defaultValue); + } + + public static function setData($namePath, $value) + { + \zin\utils\deepSet(self::$data, $namePath, $value); + } + + public static function enableGlobalRender() + { + self::$enabledGlobalRender = true; + } + + public static function disableGlobalRender() + { + self::$enabledGlobalRender = false; + } + + public static function renderInGlobal() + { + if(!self::$enabledGlobalRender) return false; + + self::$globalRenderList = array_merge(self::$globalRenderList, func_get_args()); + } +} diff --git a/zin/func.php b/zin/func.php new file mode 100644 index 0000000000..514b01b4d1 --- /dev/null +++ b/zin/func.php @@ -0,0 +1,84 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once __DIR__ . DS . 'core' . DS . 'h.func.php'; +require_once __DIR__ . DS . 'core' . DS . 'render.func.php'; +require_once __DIR__ . DS . 'zui' . DS . 'zui.func.php'; +require_once __DIR__ . DS . 'zentao' . DS . 'zentao.func.php'; + +/* Form */ +function input() {return createWg('input', func_get_args());} +function textarea() {return createWg('textarea', func_get_args());} +function radio() {return createWg('radio', func_get_args());} +function switcher() {return createWg('switcher', func_get_args());} +function checkbox() {return createWg('checkbox', func_get_args());} +function form() {return createWg('form', func_get_args());} +function formPanel() {return createWg('formPanel', func_get_args());} +function control() {return createWg('control', func_get_args());} +function select() {return createWg('select', func_get_args());} +function formLabel() {return createWg('formLabel', func_get_args());} +function formGroup() {return createWg('formGroup', func_get_args());} +function formRow() {return createWg('formRow', func_get_args());} +function inputControl() {return createWg('inputControl', func_get_args());} +function inputGroup() {return createWg('inputGroup', func_get_args());} +function checkList() {return createWg('checkList', func_get_args());} +function radioList() {return createWg('radioList', func_get_args());} +function colorPicker() {return createWg('colorPicker', func_get_args());} +function datePicker() {return createWg('datePicker', func_get_args());} +function datetimePicker() {return createWg('datetimePicker', func_get_args());} +function timePicker() {return createWg('timePicker', func_get_args());} +function fileInput() {return createWg('fileInput', func_get_args());} + +function icon() {return createWg('icon', func_get_args());} +function btn() {return createWg('btn', func_get_args());} +function pageBase() {return createWg('pageBase', func_get_args());} +function page() {return createWg('page', func_get_args());} +function fragment() {return createWg('fragment', func_get_args());} +function btnGroup() {return createWg('btnGroup', func_get_args());} +function mainMenu() {return createWg('mainMenu', func_get_args());} +function row() {return createWg('row', func_get_args());} +function col() {return createWg('col', func_get_args());} +function column() {return createWg('column', func_get_args());} +function center() {return createWg('center', func_get_args());} +function cell() {return createWg('cell', func_get_args());} +function actionItem() {return createWg('actionItem', func_get_args());} +function nav() {return createWg('nav', func_get_args());} +function label() {return createWg('label', func_get_args());} +function dtable() {return createWg('dtable', func_get_args());} +function menu() {return createWg('menu', func_get_args());} +function dropdown() {return createWg('dropdown', func_get_args());} +function header() {return createWg('header', func_get_args());} +function heading() {return createWg('heading', func_get_args());} +function navbar() {return createWg('navbar', func_get_args());} +function main() {return createWg('main', func_get_args());} +function sidebar() {return createWg('sidebar', func_get_args());} +function featureBar() {return createWg('featureBar', func_get_args());} +function pageHeading() {return createWg('pageHeading', func_get_args());} +function pageNavbar() {return createWg('pageNavbar', func_get_args());} +function pageToolbar() {return createWg('pageToolbar', func_get_args());} +function avatar() {return createWg('avatar', func_get_args());} +function userAvatar() {return createWg('userAvatar', func_get_args());} +function pager() {return createWg('pager', func_get_args());} +function modal() {return createWg('modal', func_get_args());} +function modalTrigger(){return createWg('modalTrigger', func_get_args());} +function modalDialog() {return createWg('modalDialog', func_get_args());} +function tabs() {return createWg('tabs', func_get_args());} +function panel() {return createWg('panel', func_get_args());} +function tooltip() {return createWg('tooltip', func_get_args());} +function toolbar() {return createWg('toolbar', func_get_args());} +function searchForm() {return createWg('searchForm', func_get_args());} +function searchToggle(){return createWg('searchToggle', func_get_args());} +function programMenu() {return createWg('programMenu', func_get_args());} +function moduleMenu() {return createWg('moduleMenu', func_get_args());} +function assigntoDialog() {return createWg('assigntoDialog', func_get_args());} +function historyRecord() {return createWg('historyRecord', func_get_args());} diff --git a/zin/helper.php b/zin/helper.php new file mode 100755 index 0000000000..5296c973f5 --- /dev/null +++ b/zin/helper.php @@ -0,0 +1,97 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'config.php'; + +function setWgVer($ver, $names = NULL) +{ + global $config; + $zinConfig = $config->zin; + + if(is_string($names)) $names = explode(',', $names); + if(!is_array($names)) return; + + foreach($names as $name) + { + $name = trim($name); + if(!empty($name)) continue; + + $zinConfig->wgVerMap[$name] = $ver; + } +} + +function getWgVer($name) +{ + global $config; + + return isset($config->zin->verMap[$name]) ? $config->zin->verMap[$name] : $config->zin->wgVer; +} + +function createWg($name, $args) +{ + global $app; + + $name = strtolower($name); + $wgVer = getWgVer($name); + + include_once $app->getBasePath() . 'zin' . DS . 'wg' . DS . $name . DS . "v$wgVer.php"; + + $wgName = "\\zin\\$name"; + + return class_exists($wgName) ? (new $wgName($args)) : $wgName($args); +} + +if(!function_exists('str_contains')) +{ + /** + * Determine if a string contains a given substring + * + * @param string $haystack + * @param string $needle + * @return bool + */ + function str_contains($haystack, $needle) + { + return strpos($haystack, $needle) !== false; + } +} + +if(!function_exists('str_starts_with')) +{ + /** + * Checks if a string starts with a given substring + * + * @param string $haystack + * @param string $needle + * @return bool + */ + function str_starts_with($haystack, $needle) + { + return strpos($haystack, $needle) === 0; + } +} + +if(!function_exists('str_ends_with')) +{ + /** + * Checks if a string starts with a given substring + * + * @param string $haystack + * @param string $needle + * @return bool + */ + function str_ends_with($haystack, $needle) + { + return strpos($haystack, $needle) === strlen($haystack) - 1; + } +} diff --git a/zin/utils/classlist.class.php b/zin/utils/classlist.class.php new file mode 100755 index 0000000000..e399988285 --- /dev/null +++ b/zin/utils/classlist.class.php @@ -0,0 +1,313 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +/** + * Manage classname list for html element and widgets + */ +class classlist +{ + /** + * Store classname list, key => value + * + * @access public + * @var array + */ + public $list = array(); + + /** + * Create classname instance + * + * @access public + * @param array ...$list - A string or a class name list + */ + public function __construct(/* ...$list */) + { + $list = func_get_args(); + if(!empty($list)) $this->set($list); + } + + /** + * Convert classnames to string + * + * @access public + * @return string + */ + public function __toString() + { + return $this->toStr(); + } + + /** + * Override __invoke + * + * Example: + * + * $classlist = classlist::create('btn primary'); + * echo $classlist(); // Output: "btn primary" + * + * @access public + * @param array $list - Class name list + * @return string + */ + public function __invoke() + { + $list = func_get_args(); + if(empty($list)) return $this->toStr(); + return $this->set($list); + } + + /** + * Override __call to invoke toggle method conveniently + * + * Example: + * + * $classlist = classlist::new(); + * + * // Add "primary" class + * $classlist->primary(); + * + * // Remove "primary" class + * $classlist->primary(false); + * + * @access public + * @return classlist + */ + public function __call($name, $args) + { + return $this->toggle($name, !count($args) || $args[0]); + } + + /** + * Create classname instance + * + * Example: + * + * // Set class names + * $classlist = new classlist(); + * $classlist->set('btn primary rounded'); + * + * // Set multiple classnames by string list + * $classlist->set(array('btn', 'primary', 'rounded')); + * + * // Set multiple classnames by a mapped array + * $classlist->set(array('btn' => true, 'primary' => true, 'rounded' => $isRounded)); + * + * @access public + * @param string|array $list - A string or a class name list + * @param bool $reset + * @return classlist + */ + public function set($list, $reset = false) + { + if(is_string($list)) $list = explode(' ', $list); + + if(is_array($list)) + { + if($reset) $this->list = array(); + + $expectedKey = 0; + foreach($list as $index => $value) + { + if(is_array($value)) + { + $this->set($value); + continue; + } + + /* If $index is expected numberic key and the $value is string, then use the $value as the name */ + if($expectedKey === $index && is_string($value)) + { + $value = trim($value); + if(strlen($value) > 0) $this->list[$value] = true; + } + /* If index is string, then set $index as name */ + else if(is_string($index)) + { + $index = trim($index); + if(strlen($index) === 0) continue; + + $this->list[$index] = boolval($value); + } + $expectedKey++; + } + } + + return $this; + } + + /** + * Add classnames + * + * Example: + * + * $classlist = new classlist(); + * $classlist->add('btn primary rounded'); + * + * // Add multiple classnames by string list + * $classlist->add('btn', 'primary', 'rounded'); + * + * @access public + * @param array ...$list - classname string joined by space or string array + * @return classlist + */ + public function add(/* ...$list */) + { + return $this->set(func_get_args()); + } + + /** + * Remove classnames + * + * Example: + * + * $classlist = new classlist('btn primary rounded'); + * $classlist->remove('btn primary'); + * + * // Add multiple classnames by string list + * $classlist->remove('btn', 'primary'); + * + * @access public + * @param array|string $list - classname string joined by space or string array + * @return classlist + */ + public function remove($list) + { + if(is_string($list)) $list = explode(' ', $list); + + foreach($list as $name) + { + if(!is_string($name)) continue; + $name = trim($name); + if(!strlen($name)) continue; + + $this->list[$name] = false; + } + return $this; + } + + /** + * Toggle classname + * + * Example: + * + * $classlist = new classlist('btn'); + * $classlist->toggle('btn'); // class list is "" + * + * // Toggle class name by flag + * $classlist->toggle('primary', true); // class list is "primary" + * + * @access public + * @param string $name - classname string + * @return classlist + */ + public function toggle($name, $toggle = NULL) + { + $name = trim($name); + if(strlen($name)) + { + if($toggle === NULL) $toggle = !$this->has($name); + $this->list[$name] = $toggle; + } + return $this; + } + + /** + * Check whether has specific class name + * + * Example: + * + * $classlist = new classlist('btn primary rounded'); + * echo $classlist->has('btn'); // Output true + * + * // Check multiple names + * echo $classlist->has('btn primary'); // Output true + */ + public function has($list) + { + if(is_string($list)) $list = explode(' ', $list); + + foreach($list as $name) + { + if(!is_string($name)) continue; + $name = trim($name); + if(!strlen($name)) continue; + + if(!isset($this->list[$name]) || !$this->list[$name]) return false; + } + return true; + } + + public function clear() + { + $this->list = array(); + } + + /** + * Convert classnames to string + * + * @access public + * @return string + */ + public function toStr() + { + $names = array(); + foreach($this->list as $name => $toggle) + { + if(!$toggle) continue; + + $name = trim($name); + if(!strlen($name)) continue; + + $names[] = str_replace('.', '.\\', $name); + } + return implode(' ', $names); + } + + /** + * Get class names count + * + * @access public + * @return int + */ + public function count() + { + return count($this->list); + } + + /** + * Create an classlist instance + * + * @param string|array $names - A string or a class name list + * @return classlist + */ + static public function new($names = NULL) + { + return (new classlist($names)); + } + + /** + * Stringify class list + * + * @param string|array $names - A string or a class name list + * @return string + */ + static public function str($names) + { + return (new classlist($names))->toStr(); + } + + public function toJSON() + { + return $this->list; + } +} diff --git a/zin/utils/data.class.php b/zin/utils/data.class.php new file mode 100644 index 0000000000..aa85246f8c --- /dev/null +++ b/zin/utils/data.class.php @@ -0,0 +1,83 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +require_once 'dataset.class.php'; + +/** + * Manage data for html element and widgets + */ +class data extends dataset +{ + public function __constructor() + { + $list = func_get_args(); + + foreach($list as $data) $this->set($data); + } + + /** + * Method for sub class to modify value on setting it + * + * @access public + * @param array|string $prop - Property name or properties list + * @param mixed $value - Property value + * @param bool $removeEmpty - Whether to remove empty value + * @return dataset + */ + protected function setVal($prop, $value, $removeEmpty = false) + { + if($prop[0] === '$') $prop = substr($prop, 1); + + if($value === NULL || ($removeEmpty && empty($value))) return $this->remove($prop); + + $names = explode('.', $prop); + $lastName = array_pop($names); + $data = &$this->data; + if(!empty($names)) + { + foreach($names as $name) + { + if(!is_array($data)) + { + return $this; + } + + if(!isset($data[$name])) $data[$name] = array(); + $data = &$data[$name]; + } + } + + if($value === NULL || ($removeEmpty && empty($value))) + { + if(isset($data[$lastName])) unset($data[$lastName]); + return $this; + } + + $data[$lastName] = $value; + return $this; + } + + protected function getVal($prop) + { + if($prop[0] === '$') $prop = substr($prop, 1); + + $names = explode('.', $prop); + $data = &$this->data; + foreach($names as $name) + { + if(!is_array($data)) return NULL; + $data = &$data[$name]; + } + return $data; + } +} diff --git a/zin/utils/dataset.class.php b/zin/utils/dataset.class.php new file mode 100755 index 0000000000..ec20d5ec7e --- /dev/null +++ b/zin/utils/dataset.class.php @@ -0,0 +1,288 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +/** + * Manage dataset properties for html element and widgets + */ +class dataset +{ + /** + * Store dataset properties list in an array + * + * @var array + * @access public + */ + public $data = array(); + + /** + * Create an instance, the initialed data can be passed + * + * @access public + * @param array $data - Properties list array + */ + public function __construct($data = NULL) + { + if($data !== NULL) $this->set($data); + } + + /** + * Override __set + * + * @access public + * @param string $prop - Property name + * @param mixed $value - Property value + * @return void + */ + public function __set($name, $value) + { + $this->set($name, $value); + } + + /** + * Override __get + * + * @access public + * @param string $prop - Property name + * @return mixed + */ + public function __get($name) + { + $this->get($name); + } + + /** + * Override __isset + * + * @access public + * @param string $prop - Property name + * @return bool + */ + public function __isset($name) + { + return $this->has($name); + } + + /** + * Override __unset + * + * @access public + * @param string $prop - Property name + * @return void + */ + public function __unset($name) + { + $this->remove($name); + } + + /** + * Convert dataset to json string + * + * @access public + * @return string + */ + public function __toString() + { + return $this->toStr(); + } + + /** + * Override __invoke + * + * @access public + * @return string + */ + public function __invoke($name = NULL, $value = NULL) + { + if($value !== NULL || is_array($name)) return $this->set($name, $value); + if(is_string($name)) return $this->get($name); + + return $this->toStr(); + } + + /** + * Override __call for setting property conveniently + * + * Example: + * + * $dataset = dataset::new(); + * + * // Set color property + * $dataset->color('red'); + * + * // Get color property + * echo $dataset->color(); // Output "Red" + * + * @access public + * @return mixed + */ + public function __call($name, $args) + { + if(count($args)) return $this->set($name, $args[0]); + + return $this->get($name); + } + + /** + * Method for sub class to modify value on setting it + * + * @access public + * @param array|string $prop - Property name or properties list + * @param mixed $value - Property value + * @return dataset + */ + protected function setVal($prop, $value) + { + $this->data[$prop] = $value; + return $this; + } + + protected function getVal($prop) + { + return isset($this->data[$prop]) ? $this->data[$prop] : NULL; + } + + /** + * Get properties count + * + * @access public + * @param bool $skipEmpty - Whether to skip to count empty value + * @return int + */ + public function count($skipEmpty = false) + { + if(!$skipEmpty) return count($this->data); + + $count = 0; + foreach($this->data as $value) + { + if(!empty($value)) $count++; + } + return $count; + } + + /** + * Convert dataset to json string + * + * @access public + * @return string + */ + public function toStr() + { + return json_encode($this->toJsonData()); + } + + public function toJsonData() { + return $this->data; + } + + /** + * Set property, an array can be passed to set multiple properties + * + * @access public + * @param array|string $prop - Property name or properties list + * @param mixed $value - Property value + * @param bool $removeEmpty - Whether to remove empty value + * @return dataset + */ + public function set($prop, $value = NULL) + { + if(is_array($prop)) + { + foreach($prop as $name => $val) $this->set($name, $val); + return $this; + } + + $value = $this->setVal($prop, $value); + return $this; + } + + /** + * Get property value by name + * + * @access public + * @param string $prop - Property name + * @param mixed $defaultValue - Optional default value if actual value is null + * @return mixed + */ + public function get($prop, $defaultValue = NULL) + { + $val = $this->getVal($prop); + return $val === NULL ? $defaultValue : $val; + } + + public function addToList($prop, $values) + { + if(!is_array($values)) $values = array($values); + + $list = $this->getList($prop); + $this->set($prop, array_merge($list, $values)); + } + + public function getList($prop) + { + return $this->get($prop, array()); + } + + public function list($prop, $values = NULL) + { + if($values === NULL) return $this->getList($prop); + return $this->setList($prop, $values); + } + + /** + * Delete property by name + * + * @access public + * @param string $prop - Property name + * @return dataset + */ + public function remove($prop) + { + return $this->setVal($prop, NULL); + } + + public function clear() + { + $this->data = array(); + } + + /** + * Check whether has specified property + * + * @access public + * @param string $prop - Property name + * @return boolean + */ + public function has($prop) + { + return $this->getVal($prop) !== NULL; + } + + /** + * Clone a new instance + * + * @access public + * @return object + */ + public function clone() + { + $className = get_called_class(); + return new $className($this->data); + } + + public function merge($data) + { + if(is_object($data) && isset($data->data)) return $this->set($data->data); + return $this->set($data); + } +} diff --git a/zin/utils/debug.func.php b/zin/utils/debug.func.php new file mode 100644 index 0000000000..2df10ef8bf --- /dev/null +++ b/zin/utils/debug.func.php @@ -0,0 +1,44 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +$logs = array(); + +function log($type, $msg = NULL, $file) +{ + global $config; + + if(!$config->debug) return; + + if($msg === NULL) + { + $msg = $type; + $type = 'i'; + } + + if(is_array($msg)) + { + $msgLines = array(); + foreach($msg as $m) $msgLines[] = strval($m); + $msg = implode(' ', $msgLines); + } + else + { + $msg = strval($msg); + } + + $logs[] = array(array('type' => strtolower($type), 'msg' => $msg)); +} + +function logInfo($msg, $file = NULL) {log('i', $msg, $file);}; +function logWarn($msg, $file = NULL) {log('w', $msg, $file);}; +function logError($msg, $file = NULL) {log('e', $msg, $file);}; diff --git a/zin/utils/deep.func.php b/zin/utils/deep.func.php new file mode 100644 index 0000000000..1c09201d0a --- /dev/null +++ b/zin/utils/deep.func.php @@ -0,0 +1,37 @@ +$name)) return $defaultValue; + $data = &$data->$name; + continue; + } + if(!is_array($data) || !isset($data[$name])) return $defaultValue; + $data = &$data[$name]; + } + return $data === NULL ? $defaultValue : $data; +} + +function deepSet(&$data, $namePath, $value) +{ + $names = explode('.', $namePath); + $lastName = array_pop($names); + if(!empty($names)) + { + foreach($names as $name) + { + if(!is_array($data)) return; + + if(!isset($data[$name])) $data[$name] = array(); + $data = &$data[$name]; + } + } + + $data[$lastName] = $value; +} diff --git a/zin/utils/flat.func.php b/zin/utils/flat.func.php new file mode 100644 index 0000000000..d4cfce2baf --- /dev/null +++ b/zin/utils/flat.func.php @@ -0,0 +1,19 @@ + $value) + { + if(is_array($value)) + { + $result = array_merge($result, flat($value, $prefix . $key . $separator)); + } + else + { + $result[$prefix . $key] = $value; + } + } + return $result; +} diff --git a/zin/utils/hx.class.php b/zin/utils/hx.class.php new file mode 100755 index 0000000000..3eed344b8b --- /dev/null +++ b/zin/utils/hx.class.php @@ -0,0 +1,125 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +require_once 'dataset.class.php'; + +/** + * Manage hx for html element and widgets + * + * Example: + * + * // Create a hx object an convert to str string + * $hx = hx::new()->boost(); + * + * echo $hx(); // Output 'hx-boost="true"' + * + * @see https://htmx.org/ + * @todo @sunhao: Validate hx properties on modifying + */ +class hx extends dataset +{ + /** + * Method for sub class to modify value on setting it + * + * @access public + * @param array|string $prop - Property name or properties list + * @param mixed $value - Property value + * @param bool $removeEmpty - Whether to remove empty value + * @return hx + */ + protected function setVal($prop, $value, $removeEmpty = false) + { + if(str_starts_with($prop, 'hx-')) $prop = substr($prop, 3); + return parent::setVal($prop, $value); + } + + /** + * Set ajax request + * + * @access public + * @param string $url - The request url + * @param string $trigger - The trigget + * @param string $target - A css selector to specific a element to load remote content + * @param string $method - The request method, default value is "get" + * @return hx + * @see https://htmx.org/docs/#ajax + */ + public function ajax($url, $trigger = '', $target = '', $method = 'get') + { + if(is_array($url)) return $this->set($url); + + return $this->set(array('url' => $url, 'trigger' => $trigger, 'target' => $target, 'method' => $method)); + } + + /** + * Set ajax post request + * + * @access public + * @param string $url - The request url + * @param string $trigger - The trigget + * @param string $target - A css selector to specific a element to load remote content + * @return hx + * @see https://htmx.org/docs/#ajax + */ + public function post($url, $trigger = '', $target = '') + { + return $this->ajax($url, $trigger, $target, 'post'); + } + + /** + * Convert hx properties to str string + * + * @access public + * @return string + */ + public function toStr() + { + $pairs = array(); + + foreach($this->data as $name => $value) + { + /* Skip any null value */ + if($value === NULL) continue; + + /* Convert non-string to json */ + if(!is_string($value)) $value = json_encode($value); + + $pairs[] = 'hx-' . $name . '="' . htmlspecialchars($value) . '"'; + } + + return implode(' ', $pairs); + } + + /** + * Create an instance + * + * @param string $hx - CSS hx list + * @return hx + */ + static public function new($hx) + { + return new hx($hx); + } + + /** + * Create properties string from hx list + * + * @access public + * @param string $hx - CSS hx list + * @return string + */ + static public function str($props) + { + return (new hx($props))->toStr(); + } +} diff --git a/zin/utils/style.class.php b/zin/utils/style.class.php new file mode 100755 index 0000000000..09c48d65c0 --- /dev/null +++ b/zin/utils/style.class.php @@ -0,0 +1,173 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin\utils; + +require_once 'dataset.class.php'; + +/** + * Manage style for html element and widgets + * + * Example: + * + * // Create a style object an convert to css string + * $style = style::create(array('color' => 'red')); + * echo $style(); // Output "color:red" + * + * // Above example same as: + * echo style::css(array('color' => 'red')); + * + * // Modifier style + * $style = style::create(array('color' => 'red')); + * $style->set('background', 'green'); + * + * // Modifier style with property name directly + * $style->background = 'green'; + * + * // Get style value + * echo $style->get('background'); // Output "green" + * + * // Get style value with property name directly + * echo $style->background; // Output "green" + * + * @todo @sunhao: Validate style properties on modifying + */ +class style extends dataset +{ + /** + * Set or get css variable, an array can be passed to set multiple variables + * If only pass variable name, then the variable value will be returned + * If no params passed, then return all setted variables with an array + * + * Notice: no need to prepend prefix '--' to variable name, the method will prepend it automatically, if prepended already, the method will skip to prepend smartly + * + * Example: + * + * // Create a style object and set + * $style = new style(); + * $style->cssVar('text-size', '14px'); + * + * // Set multiple variables + * $style->cssVar(array('text-color' => 'yellow', 'background-image': 'none')); + * + * // Get variable value + * echo $style->cssVar('text-size'); // Output "14px" + * + * // Get all variables value + * echo $style->cssVar(); + * // Output array('text-size' => '14px', 'color' => 'yellow', 'background': 'none'); + * + * // Remove variable by setting value with an empty string + * $style->cssVar('text-color', ''); + * + * @access public + * @param array|string $name - Variable name or variables list + * @param mixed $value - Property value + * @return mixed + */ + public function cssVar($name = '', $value = NULL) + { + /* Support for setting multiple variables by an array */ + if(is_array($name)) + { + foreach($name as $n => $value) $this->set(style::formatVarName($n), $value); + return $this; + } + + /* Return all setted variables without passed any params */ + if(empty($name)) + { + $vars = array(); + foreach ($this->data as $prop => $value) + { + if(!str_starts_with($name, '--')) continue; + $vars[substr($prop, 2)] = $value; + } + return $vars; + } + + $varName = style::formatVarName($name); + + /* Return the specific variable value by name */ + if($value === NULL) return $this->get($varName); + + /* Set the specific variable value and return style object self */ + $this->set($varName, $value === '' ? NULL : $value); + return $this; + } + + /** + * Convert to string + * + * @access public + * @return string + */ + public function toStr() + { + return $this->toCss(); + } + + /** + * Convert style to css string + * + * @access public + * @return string + */ + public function toCss() + { + $pairs = array(); + + foreach($this->data as $prop => $value) + { + /* Skip any empty value */ + if(empty($value)) continue; + + $pairs[] = $prop . ': ' . strval($value) . ';'; + } + + return implode(' ', $pairs); + } + + /** + * Create an instance + * + * @param string $style - CSS style list + * @return style + */ + static public function new($style = NULL) + { + return new style($style); + } + + /** + * Create css from style list + * + * @access public + * @param string $style - CSS style list + * @return string + */ + static public function css($style) + { + return (new style($style))->toCss(); + } + + /** + * Format CSS variable name with prefix "--" + * + * @access public + * @param string $name - CSS variable name + * @return string + */ + static public function formatVarName($name) + { + return \zin\str_starts_with($name, '--') ? $name : "--$name"; + } +} diff --git a/zin/wg/actionitem/v1.php b/zin/wg/actionitem/v1.php new file mode 100644 index 0000000000..a53f41a93b --- /dev/null +++ b/zin/wg/actionitem/v1.php @@ -0,0 +1,114 @@ +prop(array('icon', 'text', 'trailingIcon')); + + return h::div + ( + set($this->props->skip(array_keys(actionItem::getDefinedProps()))), + set($this->prop('props')), + $icon ? icon($icon) : NULL, + empty($text) ? NULL : span($text, setClass('text')), + $this->children(), + $trailingIcon ? icon($trailingIcon) : NULL, + ); + } + + protected function buildDropdownItem() + { + $dropdown = new dropdown + ( + set($this->props->skip(array_keys(actionItem::getDefinedProps()))), + set($this->prop('props')), + $this->children() + ); + return $dropdown; + } + + protected function buildBtnItem() + { + return new btn($this->props->skip('tagName,type,name,outerTag,outerProps,props'), set($this->prop('props')),$this->children()); + } + + protected function buildCheckboxItem() + { + return new checkbox($this->props->skip('tagName,type,name,outerTag,outerProps,props'), set($this->prop('props')),$this->children()); + } + + protected function buildBtnGroupItem() + { + return new btnGroup($this->props->skip('tagName,type,name,outerTag,outerProps,props'), set($this->prop('props')),$this->children()); + } + + protected function buildItem() + { + $type = $this->prop('type'); + $methodName = "build{$type}Item"; + if(method_exists($this, $methodName)) return $this->$methodName(); + + list($tagName, $icon, $text, $trailingIcon, $url, $target, $active, $disabled, $badge) = $this->prop(array('tagName', 'icon', 'text', 'trailingIcon', 'url', 'target', 'active', 'disabled', 'badge')); + + if(is_string($badge)) $badge = label($badge); + else if(is_array($badge)) $badge = label(set($badge)); + + return h::create + ( + $tagName, + set($tagName === 'a' ? array('href' => $url, 'target' => $target) : array('data-url' => $url, 'data-target' => $target)), + setClass(array('active' => $active, 'disabled' => $disabled)), + set($this->props->skip(array_keys(actionItem::getDefinedProps()))), + set($this->prop('props')), + $icon ? icon($icon) : NULL, + $text, + $badge, + $this->children(), + $trailingIcon ? icon($trailingIcon) : NULL, + ); + } + + protected function build() + { + list($name, $type, $outerTag, $outerProps, $outerClass) = $this->prop(array('name', 'type', 'outerTag', 'outerProps', 'outerClass')); + + return h::create + ( + $outerTag, + setClass("$name-$type", $outerClass), + set($outerProps), + $this->buildItem() + ); + } +} diff --git a/zin/wg/assigntodialog/css/v1.css b/zin/wg/assigntodialog/css/v1.css new file mode 100644 index 0000000000..ecdde118e6 --- /dev/null +++ b/zin/wg/assigntodialog/css/v1.css @@ -0,0 +1,66 @@ +.assignto-dialog { + z-index: 20; + display: flex; +} + +.assignto-dialog .modal-dialog { + width: auto; +} + +.assignto-dialog textarea { + width: 726px; + height: 188px; +} + +.assignto-dialog #mailto { + width: 726px; +} + +.assignto-dialog select, +.assignto-dialog .input-control.has-suffix { + width: 205px; + display: flex; +} +.assignto-dialog .input-control.has-suffix input.form-control { + z-index: 1; + padding-right: 6px; +} + +.assignto-dialog .modal-header { + gap: 10px; +} + +.assignto-dialog .input-control-suffix { + position: static; + border-radius: 0px 2px 2px 0px; + border: 1px solid #dcdcdc; + border-left: 0; +} + +.assignto-dialog .modal-title { + font-size: 14px; +} + +.assignto-dialog .modal-divider { + position: absolute; + left: 20px; + right: 20px; + bottom: 0; + height: 1px; + background: #eee; +} + +.assignto-dialog .modal-body { + padding: 20px 40px; +} + +.assignto-dialog button[type="submit"] { + min-width: 120px; +} + +.assignto-dialog .input-control-suffix { + justify-content: center; + width: auto; + opacity: 1; + background-color: #eee; +} diff --git a/zin/wg/assigntodialog/v1.php b/zin/wg/assigntodialog/v1.php new file mode 100644 index 0000000000..a542b648ce --- /dev/null +++ b/zin/wg/assigntodialog/v1.php @@ -0,0 +1,143 @@ +prop('useLeft'); + $useMailto = $this->prop('useMailto'); + + return div + ( + setClass('modal assignto-dialog'), + div + ( + setClass('modal-dialog'), + div + ( + setClass('modal-content'), + div + ( + setClass('modal-header'), + label($this->prop('assignID')), + div + ( + setClass('modal-title'), + $this->prop('title'), + ), + btn + ( + setClass('square ghost'), + set('data-dismiss', 'modal'), + span(setClass('close')) + ), + div(setClass('modal-divider')) + ), + div + ( + setClass('modal-body'), + formGrid + ( + set::action($this->prop('action')), + set::method('POST'), + formGroup + ( + formLabel($lang->assignedToAB), + formCell + ( + select + ( + set::name('assignedTo'), + set::id('assignedTo'), + set::items($this->prop('assignedTo')), + ), + ) + ), + $useLeft === true + ? formGroup + ( + formLabel($lang->task->left), + formCell + ( + div + ( + setClass('input-control has-suffix'), + formInput + ( + set::type('number'), + set::min(0), + set::name('left'), + set::id('left'), + ), + h::label + ( + setClass('input-control-suffix'), + '小时' + ) + ) + ) + ) + : null, + $useMailto === true + ? formGroup + ( + formLabel($lang->bug->mailto), + formCell + ( + select + ( + set::name('mailto[]'), + set::id('mailto'), + set::items($this->prop('mailto')) + ), + ) + ) + : null, + formGroup + ( + formLabel($lang->comment), + formCell + ( + textarea + ( + setClass('form-control'), + set::name('comment'), + set::id('comment') + ) + ) + ), + formGroup + ( + setClass('justify-center'), + button + ( + set::type('submit'), + setClass('btn primary'), + $lang->save + ) + ) + ) + ) + ) + ) + ); + } +} diff --git a/zin/wg/avatar/v1.php b/zin/wg/avatar/v1.php new file mode 100644 index 0000000000..5ba1dea17f --- /dev/null +++ b/zin/wg/avatar/v1.php @@ -0,0 +1,288 @@ + 20, 'sm' => 24, 'lg' => 48, 'xl' => 80); + private $actualSize = 32; + private $finalClass = array('avatar'); + private $finalStyle; + + protected function onAddChild($child) + { + if(is_string($child) && !$this->props->has('text')) + { + $this->setProp('text', $child); + return false; + } + + return $child; + } + + protected function build() + { + /* Attach classes. */ + $this->finalClass[] = $this->prop('className'); + + /* Init style. */ + $this->finalStyle = new stdClass(); + $this->finalStyle->background = $this->prop('background'); + $this->finalStyle->color = $this->prop('foreColor'); + + foreach($this->props->style->data as $attr => $val) $this->finalStyle->{$attr} = $val; + + /* Init avatar size. */ + $this->initSize(); + /* Init avatar shape. */ + $this->initShape(); + + $content = $this->getContent(); + $finalStyle = json_decode(json_encode($this->finalStyle), true); + return h::div + ( + setClass($this->finalClass), + setStyle($finalStyle), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $content, + $this->children() + ); + } + + private function initSize() + { + $size = $this->prop('size'); + $this->actualSize = $size; + + if(!$size) return; + + if(is_numeric($size)) + { + $fontSize = intval($size/2) > 12 ? intval($size/2) : 12; + $this->finalStyle->width = "{$size}px"; + $this->finalStyle->height = "{$size}px"; + $this->finalStyle->{'font-size'} = "{$fontSize}px"; + + return; + } + + $this->finalClass[] = "size-{$size}"; + $this->actualSize = isset($this->sizeMap[$size]) ? $this->sizeMap[$size] : 20; + } + + private function initShape() + { + $circle = $this->prop('circle'); + $rounded = $this->prop('rounded'); + + /* Set circle. */ + if($circle) + { + $this->finalClass[] = 'circle'; + } + else if($rounded) + { + if(is_numeric($rounded)) $this->finalStyle->{'border-radius'} = "{$rounded}px"; + else $this->finalClass[] = "rounded-{$rounded}"; + } + } + + private function getAvatarText() + { + $maxTextLen = intval($this->prop('maxTextLength')); + $text = strtoupper($this->prop('text', '')); + $this->textLen = strlen($text); + + if(preg_match('/[\x{4e00}-\x{9fa5}\s]+$/u', $text)) + { + $this->textLen = mb_strlen($text); + $text = $this->textLen <= $maxTextLen ? $text : mb_substr($text, $this->textLen - $maxTextLen); + $this->displayTextLen = mb_strlen($text); + return $text; + } + + if(preg_match('/[A-Za-z\d\s]+$/', $text)) + { + $this->displayTextLen = 1; + return substr($text, 0, 1); + } + + return $this->textLen <= $maxTextLen ? $text : substr($text, 0, $maxTextLen); + } + + /** + * Convert HSL values to RGB value. + * + * @param int $h + * @param number $s + * @param number $l + * @access private + * @return array + */ + private function hslToRgb($h, $s, $l) + { + $h = ($h % 360) / 360; + $s = ($s > 0 ? $s : 0); + $s = ($s > 255) ? 255 : $s; + $l = ($l > 0 ? $l : 0); + $l = ($l > 255) ? 255 : $l; + + $m2 = ($l <= 0.5) ? ($l * ($s + 1)) : ($l + $s - $l * $s); + $m1 = $l * 2 - $m2; + + $hueFn = function($val, $m1, $m2) + { + $val = $val < 0 ? $val + 1 : ($val > 1 ? $val - 1 : $val); + + if($val * 6 < 1) return $m1 + ($m2 - $m1) * $val * 6; + elseif($val * 2 < 1) return $m2; + elseif($val * 3 < 2) return $m1 + ($m2 - $m1) * (2/3 - $val) * 6; + + return $m1; + }; + + return array( + 'r' => $hueFn($h + 1/3, $m1, $m2) * 255, + 'g' => $hueFn($h, $m1, $m2) * 255, + 'b' => $hueFn($h - 1/3, $m1, $m2) * 255 + ); + } + + private function hex2Rgb($hex) + { + if(!str_starts_with($hex, '#') || !preg_match('/#[0-9A-F]{3,6}$/', $hex)) throw new \Exception('incorrect data format'); + + $r = 0; + $g = 0; + $b = 0; + if(strlen($hex) == 4) list($r, $g, $b) = sscanf($hex, "#%01x%01x%01x"); + elseif(strlen($hex) == 7) list($r, $g, $b) = sscanf($hex, "#%02x%02x%02x"); + else throw new \Exception('incorrect RGB value'); + + return array( + 'r' => $r, + 'g' => $g, + 'b' => $b + ); + } + + /* + * Get contrast color. + * + * @param array|string $rgb + * @param string $theme dark|light + * @access private + * @return string + */ + private function contrastColor($rgb, $themeDark = null, $themeLight = null) + { + $rgb = is_array($rgb) ? $rgb : $this->hex2Rgb($rgb); + + $r = $rgb['r']; + $g = $rgb['g']; + $b = $rgb['b']; + if(($r * 0.299 + $g * 0.587 + $b * 0.114) > 186) + { + /* Is light color. */ + return $themeDark ? $themeDark : '#333333'; + } + + return $themeLight ? $themeLight : '#ffffff'; + } + + private function getTextStyle() + { + $hueDistance = intval($this->prop('hueDistance')); + $saturation = $this->prop('saturation'); + $lightness = $this->prop('lightness'); + $background = $this->prop('background'); + $foreColor = $this->prop('foreColor'); + $code = $this->prop('code'); + $avatarCode = $code ? $code : $this->prop('text'); + + if(!$background) + { + $val = 0; + if(is_numeric($avatarCode)) $val = intval($avatarCode); + else for($i = 0; $i < strlen($avatarCode); $i++) $val += ord($avatarCode[$i]); + + $hue = $val * $hueDistance % 360; + $actualSat = $saturation * 100; + $actualLight = $lightness * 100; + $this->finalStyle->background = "hsl({$hue}, {$actualSat}%, {$actualLight}%)"; + + if(!$foreColor) + { + $rgb = $this->hslToRgb($hue, $saturation, $lightness); + $this->finalStyle->color = $this->contrastColor($rgb); + } + } + elseif (!$foreColor and $background) $this->finalStyle->color = $this->contrastColor($background); + + $textStyle = null; + if($this->actualSize and $this->actualSize < (14 * $this->displayTextLen)) + { + $textStyle = array( + 'transform' => 'scale(' . $this->actualSize / (14 * $this->displayTextLen) . ')', + 'white-space' => 'nowrap' + ); + } + + return $textStyle; + } + + private function getContent() + { + $src = $this->prop('src'); + $text = $this->prop('text'); + + /* With avatar. */ + if($src) + { + $this->finalClass[] = 'has-img'; + + return h::img + ( + setClass('avatar-img'), + set('src', $src ), + set('alt', $text) + ); + } + + /* Without text and image. */ + if(!$text) return null; + + $displayText = $this->getAvatarText(); + + $this->finalClass[] = 'has-text'; + $this->finalClass[] = 'has-text-' . $this->textLen; + + $textStyle = $this->getTextStyle(); + return h::div + ( + setClass('avatar-text'), + set('data-actualSize', $this->actualSize), + set('style', $textStyle), + $displayText + ); + } +} diff --git a/zin/wg/btn/v1.php b/zin/wg/btn/v1.php new file mode 100755 index 0000000000..a3292c7f35 --- /dev/null +++ b/zin/wg/btn/v1.php @@ -0,0 +1,117 @@ +props->has('text')) + { + $this->props->set('text', $child); + return false; + } + } + + private function getProps() + { + $props = $this->props->skip(array_keys(static::getDefinedProps())); + + $url = $this->prop('url'); + $target = $this->prop('target'); + + if(empty($url)) + { + $props['type'] = $this->prop('btnType') ?? 'button'; + if(!isset($props['data-url'])) $props['data-url'] = $url; + if(!isset($props['data-target'])) $props['data-target'] = $target; + } + else + { + $props['tagName'] = 'a'; + if(!isset($props['href'])) $props['href'] = $url; + if(!isset($props['target'])) $props['target'] = $target; + } + $props['title'] = $this->prop('hint'); + + return $props; + } + + private function getChildren() + { + $caret = $this->prop('caret'); + $text = $this->prop('text'); + $icon = $this->prop('icon'); + $trailingIcon = $this->prop('trailingIcon'); + + $children = array(); + if(!empty($icon)) $children[] = icon($icon); + if(!empty($text)) $children[] = h::span($text, setClass('text')); + $children[] = parent::build(); + if(!empty($trailingIcon)) $children[] = icon($trailingIcon); + if(!empty($caret)) $children[] = h::span(setClass(is_string($caret) ? "caret-$caret" : 'caret')); + + return $children; + } + + private function getClassList() + { + $url = $this->prop('url'); + $type = $this->prop('type'); + $caret = $this->prop('caret'); + $text = $this->prop('text'); + $icon = $this->prop('icon'); + $trailingIcon = $this->prop('trailingIcon'); + $onlyCaret = empty($text) && !empty($caret) && empty($icon) && empty($trailingIcon); + + $classList = array + ( + 'btn' => true, + 'disabled' => $this->prop('disabled'), + 'active' => $this->prop('active'), + 'btn-caret' => $onlyCaret, + 'square' => $this->prop('square') + ); + + if(!empty($type)) $classList[$type] = true; + elseif(!empty($url)) $classList['btn-default'] = true; + + $size = $this->prop('size'); + if(!empty($size)) $classList["size-$size"] = true; + + return $classList; + } + + /** + * @return builder + */ + protected function build() + { + $props = $this->getProps(); + $children = $this->getChildren(); + $classList = $this->getClassList(); + + return button + ( + set($props), + setClass($classList), + $children + ); + } +} diff --git a/zin/wg/btngroup/v1.php b/zin/wg/btngroup/v1.php new file mode 100644 index 0000000000..e098aad88e --- /dev/null +++ b/zin/wg/btngroup/v1.php @@ -0,0 +1,36 @@ +prop('items'); + $disabled = $this->prop('disabled'); + $size = $this->prop('size'); + + $classList = 'btn-group'; + if(!empty($disabled)) $classList .= ' disabled'; + if(!empty($size)) $classList .= " size-$size"; + + return div + ( + setClass($classList), + set($this->props->skip(array_keys(static::getDefinedProps()))), + is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : NULL, + $this->children() + ); + } +} diff --git a/zin/wg/cell/v1.php b/zin/wg/cell/v1.php new file mode 100644 index 0000000000..2a45d57bc8 --- /dev/null +++ b/zin/wg/cell/v1.php @@ -0,0 +1,30 @@ +prop('width')) ? 'auto' : $this->prop('width'); + if(is_numeric($basis)) $basis .= 'px'; + elseif(preg_match('/^(\d+)\/(\d+)$/', $basis, $matches) !== 0) $basis = ((int)$matches[1] / (int)$matches[2] * 100) . '%'; + + $style = array(); + $style['order'] = $this->prop('order'); + $style['flex-grow'] = $this->prop('grow'); + $style['flex-shrink'] = $this->prop('shrink'); + $style['flex-basis'] = $basis; + $style['align-self'] = $this->prop('align'); + $style['flex'] = $this->prop('flex'); + + return div + ( + setStyle($style), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $this->children() + ); + } +} diff --git a/zin/wg/center/v1.php b/zin/wg/center/v1.php new file mode 100644 index 0000000000..a1d950db4f --- /dev/null +++ b/zin/wg/center/v1.php @@ -0,0 +1,16 @@ +props->skip(array_keys(static::getDefinedProps()))), + $this->children() + ); + } +} diff --git a/zin/wg/checkbox/v1.php b/zin/wg/checkbox/v1.php new file mode 100644 index 0000000000..a32705d19d --- /dev/null +++ b/zin/wg/checkbox/v1.php @@ -0,0 +1,72 @@ +props->has('text')) + { + $this->props->set('text', $child); + return false; + } + } + + protected function buildPrimary() + { + list($id, $text, $name, $checked, $disabled, $type, $typeClass, $rootClass, $value) = $this->prop(array('id', 'text', 'name', 'checked', 'disabled', 'type', 'typeClass', 'rootClass', 'value')); + + if(empty($typeClass)) $typeClass = $type; + if(empty($id)) $id = $name . '_' . $value; + + return div + ( + setClass("$typeClass-primary", $rootClass, array('disabled' => $disabled)), + h::input + ( + set::type($type), + set::id($id), + set::name($name), + set($this->props->skip('text,primary,typeClass,rootClass,id')), + ), + h::label + ( + set::for($id), + $text, + ), + $this->children() + ); + } + + protected function build() + { + if($this->prop('primary')) return $this->buildPrimary(); + list($text, $type, $typeClass) = $this->prop(array('text', 'type', 'typeClass')); + + return h::label + ( + setClass(empty($typeClass) ? $type : $typeClass), + h::input + ( + set::type($type), + set($this->props->skip('text,primary,typeClass')), + ), + is_string($text) ? span($text, set::class('text')) : $text, + $this->children() + ); + } +} diff --git a/zin/wg/checklist/v1.php b/zin/wg/checklist/v1.php new file mode 100644 index 0000000000..89a1604eab --- /dev/null +++ b/zin/wg/checklist/v1.php @@ -0,0 +1,64 @@ +prop('value'); + if($this->prop('type') === 'checkbox') return is_array($value) ? $value : explode(',', $value); + return [$value]; + } + + public function onBuildItem($item) + { + if($item instanceof item) $item = $item->props->toJsonData(); + + if(!isset($item['checked'])) + { + $value = isset($item['value']) ? $item['value'] : ''; + $valueList = $this->getValueList(); + + $item['checked'] = in_array($value, $valueList); + } + + $props = $this->props->pick(['primary', 'type', 'name']); + return new checkbox(set($props), set($item)); + } + + protected function build() + { + list($items, $inline) = $this->prop(['items', 'inline']); + + if(!empty($items)) + { + $valueList = $this->getValueList(); + foreach($items as $key => $item) + { + if(!is_array($item)) $item = ['text' => $item, 'value' => $key]; + if(!isset($item['checked'])) $item['checked'] = in_array($item['value'], $valueList); + $items[$key] = $this->onBuildItem($item); + } + } + + return div + ( + setClass($inline ? 'check-list-inline' : 'check-list'), + set($this->getRestProps()), + $items, + $this->children() + ); + } +} diff --git a/zin/wg/col/v1.php b/zin/wg/col/v1.php new file mode 100644 index 0000000000..c69f7fd268 --- /dev/null +++ b/zin/wg/col/v1.php @@ -0,0 +1,23 @@ +prop(array('justify', 'align')); + if(!empty($justify)) $classList .= ' justify-' . $justify; + if(!empty($align)) $classList .= ' items-' . $align; + + return div + ( + setClass($classList), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $this->children() + ); + } +} diff --git a/zin/wg/colorpicker/v1.php b/zin/wg/colorpicker/v1.php new file mode 100644 index 0000000000..97ed3e40bf --- /dev/null +++ b/zin/wg/colorpicker/v1.php @@ -0,0 +1,12 @@ + 'color' + ]; +} diff --git a/zin/wg/control/v1.php b/zin/wg/control/v1.php new file mode 100644 index 0000000000..f046a67260 --- /dev/null +++ b/zin/wg/control/v1.php @@ -0,0 +1,119 @@ +setDefaultProps(['id' => $this->prop('name')]); + } + + protected function buildTextarea() + { + return new textarea(set($this->props->skip('type'))); + } + + protected function buildInputControl() + { + $controlProps = []; + $allProps = $this->props->skip('type'); + $propsNames = array_keys(inputControl::getDefinedProps()); + + foreach($propsNames as $propName) + { + if(isset($allProps[$propName])) + { + $controlProps[$propName] = $allProps[$propName]; + unset($allProps[$propName]); + } + } + + return new inputControl + ( + set($controlProps), + new input(set($allProps)), + ); + } + + protected function buildCheckbox() + { + if($this->hasProp('items')) return $this->buildCheckList(); + return new checkList + ( + new checkbox(set($this->props->skip('type'))) + ); + } + + protected function buildCheckList() + { + return new checkList + ( + set($this->props->skip('type')) + ); + } + + protected function buildRadioList() + { + return new radioList + ( + set($this->props->skip('type')) + ); + } + + protected function buildCheckListInline() + { + return new checkList + ( + set::inline(true), + set($this->props->skip('type')) + ); + } + + protected function buildRadioListInline() + { + return new radioList + ( + set::inline(true), + set($this->props->skip('type')) + ); + } + + protected function build() + { + $type = $this->prop('type'); + if(empty($type)) + { + $type = $this->hasProp('items') ? 'select' : 'text'; + } + + $methodName = "build{$type}"; + if(method_exists($this, $methodName)) return $this->$methodName(); + + $wgName = "\\zin\\$type"; + if(class_exists($wgName)) return new $wgName(set($this->props->skip('type')), $this->children()); + + return new input(set($this->props)); + } +} diff --git a/zin/wg/datepicker/v1.php b/zin/wg/datepicker/v1.php new file mode 100644 index 0000000000..de13de4821 --- /dev/null +++ b/zin/wg/datepicker/v1.php @@ -0,0 +1,12 @@ + 'date' + ]; +} diff --git a/zin/wg/datetimepicker/v1.php b/zin/wg/datetimepicker/v1.php new file mode 100644 index 0000000000..9a78881f63 --- /dev/null +++ b/zin/wg/datetimepicker/v1.php @@ -0,0 +1,12 @@ + 'datetime-local' + ]; +} diff --git a/zin/wg/dropdown/v1.php b/zin/wg/dropdown/v1.php new file mode 100644 index 0000000000..54498e535e --- /dev/null +++ b/zin/wg/dropdown/v1.php @@ -0,0 +1,152 @@ + array('map' => 'btn,a'), + 'menu' => array('map' => 'menu'), + 'items' => array('map' => 'item') + ); + + protected function build() + { + list($items, $placement, $strategy, $offset, $flip, $subMenuTrigger, $arrow, $trigger, $menuProps, $target, $id, $menuClass, $hasIcons, $staticMenu) = $this->prop(array('items', 'placement', 'strategy', 'offset', 'flip', 'subMenuTrigger', 'arrow', 'trigger', 'menuProps', 'target', 'id', 'menuClass', 'hasIcons', 'staticMenu')); + + $triggerBlock = $this->block('trigger'); + $menu = $this->block('menu'); + $itemsList = $this->block('items'); + + if(empty($id)) $id = $this->gid; + if(empty($target)) $target = "#$id"; + + if(empty($triggerBlock)) $triggerBlock = h::a($this->children()); + elseif(is_array($triggerBlock)) $triggerBlock = $triggerBlock[0]; + $triggerID = ''; + if($triggerBlock instanceof wg) + { + if($triggerBlock instanceof btn) $triggerBlock->setDefaultProps(array('caret' => true)); + $triggerBlock->setProp($this->props->skip(array_keys(static::getDefinedProps()))); + + $triggerProps = array + ( + 'data-target' => $triggerBlock->hasProp('target', 'href') ? NULL : $target, + 'data-toggle' => 'dropdown', + 'data-placement' => $placement, + 'data-strategy' => $strategy, + 'data-offset' => $offset, + 'data-flip' => $flip, + 'data-subMenuTrigger' => $subMenuTrigger, + 'data-arrow' => $arrow, + 'data-trigger' => $trigger + ); + $triggerBlock->setProp($triggerProps); + + $triggerID = $triggerBlock->id(); + if(empty($triggerID)) + { + $triggerID = "$id-toggle"; + $triggerBlock->setProp('id', $triggerID); + } + } + + if(empty($menu)) + { + if($staticMenu) + { + $menu = new menu + ( + setClass('dropdown-menu'), + set::items($items), + divorce($itemsList), + ); + + if($hasIcons === NULL) + { + if(is_array($items)) + { + foreach($items as $item) + { + if((is_array($item) and isset($item['icon'])) || (($item instanceof wg) && $item->hasProp('icon'))) + { + $hasIcons = true; + break; + } + } + } + if(!$hasIcons) + { + foreach($itemsList as $item) + { + if(($item instanceof wg) && $item->hasProp('icon')) + { + $hasIcons = true; + break; + } + } + } + } + } + else + { + if(empty($items)) $items = array(); + if(!empty($itemsList)) + { + foreach($itemsList as $item) + { + if(!($item instanceof item)) continue; + $items[] = $item->props->toJsonData(); + } + } + foreach($items as $index => $item) + { + if(!isset($item['icon']) || empty($item['icon']) || str_starts_with($item['icon'], 'icon-')) continue; + $items[$index]['icon'] = 'icon-' . $item['icon']; + } + + if(!is_array($menuProps)) $menuProps = array(); + $menuProps['items'] = $items; + + $menu = zui::dropdown + ( + set(array + ( + '_to' => "#$triggerID", + 'trigger' => $trigger, + 'placement' => $placement, + 'strategy' => $strategy, + 'arrow' => $arrow, + 'flip' => $flip, + 'subMenuTrigger' => $subMenuTrigger, + 'trigger' => $trigger, + 'offset' => $offset, + 'target' => $target, + 'className' => $menuClass, + 'hasIcons' => $hasIcons, + 'menu' => $menuProps + )) + ); + } + } + elseif(is_array($menu)) + { + $menu = $menu[0]; + } + + if($menu instanceof menu) + { + $menu->setProp($menuProps); + $menu->setProp('class', $menuClass); + $menu->setProp('id', $id); + if($hasIcons) $menu->setProp('class', 'has-icons'); + } + + return array($triggerBlock, $menu); + } +} diff --git a/zin/wg/dtable/css/v1.css b/zin/wg/dtable/css/v1.css new file mode 100644 index 0000000000..5f1714c784 --- /dev/null +++ b/zin/wg/dtable/css/v1.css @@ -0,0 +1,5 @@ +.menu.menu-dtable-actions {display: flex; min-width: auto;} +.menu.menu-dtable-actions .icon {position: static!important; opacity: 1!important;} +.menu.menu-dtable-actions span.text {display: none;} +.menu.menu-dtable-actions > .menu-item > a {padding: 0;} +.menu.menu-dtable-actions > .menu-item > a:hover {background: none; color: var(--menu-hover-bg);} diff --git a/zin/wg/dtable/v1.php b/zin/wg/dtable/v1.php new file mode 100644 index 0000000000..58acda81e5 --- /dev/null +++ b/zin/wg/dtable/v1.php @@ -0,0 +1,25 @@ +setDefaultProps(['id' => static::$dtableID ? static::$dtableID : 'dtable']); + static::$dtableID++; + } + + public static function getPageCSS() + { + return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css'); + } + + protected function build() + { + return zui::dtable(inherit($this)); + } +} diff --git a/zin/wg/editor/v1.php b/zin/wg/editor/v1.php new file mode 100644 index 0000000000..3919aafebc --- /dev/null +++ b/zin/wg/editor/v1.php @@ -0,0 +1,8 @@ + array('map' => 'nav'), + 'leading' => array(), + 'trailing' => array(), + ); + + protected function getItems() + { + $items = $this->prop('items'); + if(!empty($items)) return $items; + + global $app, $lang; + $currentModule = $app->rawModule; + $currentMethod = $app->rawMethod; + + \common::sortFeatureMenu($currentModule, $currentMethod); + + $rawItems = \customModel::getFeatureMenu($app->rawModule, $app->rawMethod); + if(!is_array($rawItems)) return NULL; + + $current = $this->prop('current', data('browseType', '')); + $recTotal = data('recTotal'); + $items = array(); + $link = $this->prop('link'); + $currentStory = $this->prop('currentStory', data('storyBrowseType') ?? ''); + + data('activeFeature', $current); + + if(empty($link)) + { + $linkParams = $this->prop('linkParams'); + if(empty($linkParams)) $linkParams = 'browseType={key}&orderBy=' . data('orderBy') ?? ''; + $link = createLink($currentModule, $currentMethod, $linkParams); + } + + foreach($rawItems as $item) + { + if(isset($item->hidden)) continue; + + $isActive = $item->name == $current; + + if($item->name == 'more' && !empty($lang->product->moreSelects)) + { + + $subItems = array(); + $callback = $this->prop('moreMenuLinkCallback'); + $callback = isset($callback[0]) ? $callback[0] : null; + + foreach($lang->product->moreSelects as $key => $text) + { + $subItems[] = array + ( + 'text' => $text, + 'active' => $key == $currentStory, + 'url' => ($callback instanceof \Closure) ? $callback($key, $text) : createLink($app->rawModule, $app->rawMethod), + 'props' => ['data-id' => $key, 'data-load' => 'table'] + ); + } + + $items[] = array + ( + 'text' => $item->text, + 'active' => $isActive, + 'url' => str_replace('{key}', $item->name, $link), + 'badge' => $isActive && !empty($recTotal) ? array('text' => $recTotal, 'class' => 'size-sm circle white') : NULL, + 'type' => 'dropdown', + 'items' => $subItems, + 'props' => ['data-id' => $item->name, 'data-load' => 'table'] + ); + + continue; + } + + + $items[] = array + ( + 'text' => $item->text, + 'active' => $isActive, + 'url' => str_replace('{key}', $item->name, $link), + 'badge' => $isActive && !empty($recTotal) ? array('text' => $recTotal, 'class' => 'size-sm circle white') : NULL, + 'props' => ['data-id' => $item->name, 'data-load' => 'table'] + ); + } + + return $items; + } + + protected function buildNav() + { + $nav = $this->block('nav'); + if(!empty($nav) && $nav[0] instanceof nav) return $nav; + return new nav + ( + set::class('nav-feature'), + set::items($this->getItems()), + divorce($this->children()) + ); + } + + protected function build() + { + return div + ( + set::id('featureBar'), + $this->block('leading'), + $this->buildNav(), + $this->block('trailing') + ); + } +} diff --git a/zin/wg/fileinput/v1.php b/zin/wg/fileinput/v1.php new file mode 100644 index 0000000000..ae0076e963 --- /dev/null +++ b/zin/wg/fileinput/v1.php @@ -0,0 +1,12 @@ + 'file' + ]; +} diff --git a/zin/wg/form/v1.php b/zin/wg/form/v1.php new file mode 100644 index 0000000000..a92810c046 --- /dev/null +++ b/zin/wg/form/v1.php @@ -0,0 +1,100 @@ + true, + 'method' => 'post', + 'target' => 'ajax', + 'actions' => ['submit', 'cancel'], + ]; + + public function onBuildItem($item) + { + if(!($item instanceof item)) + { + if($item instanceof wg) return $item; + $item = item(set($item)); + } + + if($this->prop('grid')) return new formRow(inherit($item)); + + return new formGroup(inherit($item)); + } + + protected function buildFormActions() + { + $actions = $this->prop('actions'); + if(empty($actions)) return NULL; + + global $lang; + foreach($actions as $key => $action) + { + if($action === 'submit') $actions[$key] = ['text' => $this->prop('submitBtnText') ?? $lang->save, 'btnType' => 'submit', 'type' => 'primary']; + elseif($action === 'cancel') $actions[$key] = ['text' => $this->prop('cancelBtnText') ?? $lang->goback, 'url' => html::getGobackLink()]; + elseif(is_string($action)) $actions[$key] = ['text' => $action]; + } + + return toolbar + ( + set::class('form-actions form-group gap-4 no-label'), + set::items($actions) + ); + } + + protected function build() + { + list($items, $grid, $labelWidth, $url, $target, $method, $id) = $this->prop(['items', 'grid', 'labelWidth', 'url', 'target', 'method', 'id']); + + $actions = $this->buildFormActions(); + if($grid && !empty($actions)) $actions = div(setClass('form-row'), $actions); + + $list = is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : []; + $children = $this->children(); + if(!empty($children)) $list = array_merge($list, $children); + + if($grid) + { + foreach($list as $key => $item) + { + if($item instanceof formGroup) $list[$key] = new formRow($item); + } + } + $isAjax = $target === 'ajax'; + if($isAjax) + { + $target = NULL; + if(empty($id)) $id = $this->gid; + } + if(empty($url)) $url = $_SERVER['REQUEST_URI']; + + return h::form + ( + set::class('form load-indicator', $grid ? 'form-grid' : NULL, $isAjax ? 'form-ajax' : ''), + set(['id' => $id, 'action' => $url, 'target' => $target, 'method' => $method]), + set($this->getRestProps()), + empty($labelWidth) ? NULL : setCssVar('form-label-width', $labelWidth), + $list, + $actions, + $isAjax ? zui::ajaxForm(set::_to("#$id")) : NULL + ); + } +} diff --git a/zin/wg/formgroup/v1.php b/zin/wg/formgroup/v1.php new file mode 100644 index 0000000000..1e6dc5c18f --- /dev/null +++ b/zin/wg/formgroup/v1.php @@ -0,0 +1,70 @@ +prop(['name', 'label', 'labelClass', 'labelProps', 'required', 'tip', 'tipClass', 'tipProps', 'control', 'width', 'strong', 'value', 'disabled', 'items', 'placeholder']); + + if($required === 'auto') $required = isFieldRequired($name); + + if(is_string($control)) $control = ['type' => $control, 'name' => $name]; + elseif(empty($control) && $name !== NULL) $control = ['name' => $name]; + + if(!empty($control)) + { + if($required !== NULL) $control['required'] = $required; + if($name !== NULL) $control['name'] = $name; + if($value !== NULL) $control['value'] = $value; + if($disabled !== NULL) $control['disabled'] = $disabled; + if($items !== NULL) $control['items'] = $items; + if($placeholder !== NULL) $control['placeholder'] = $placeholder; + } + + return div + ( + set::class('form-group', $required ? 'required' : NULL, ($label === false || $label === NULL) ? 'no-label' : NULL, empty($width) ? NULL : 'grow-0'), + zui::width($width), + set($this->getRestProps()), + empty($label) ? null : new formLabel + ( + set::class($labelClass, $strong ? 'font-bold' : NULL), + set::required($required), + set($labelProps), + $label + ), + empty($control) ? NULL : new control(set($control)), + (isset($control['disabled']) && $control['disabled'] && isset($control['name']) && isset($control['value'])) ? h::input(set::type('hidden'), set::name($control['name']), set::value($control['value'])) : NULL, + $this->children(), + empty($tip) ? null : div + ( + set::class($tipClass), + set($tipProps), + $tip + ) + ); + } +} diff --git a/zin/wg/formlabel/v1.php b/zin/wg/formlabel/v1.php new file mode 100644 index 0000000000..d131932080 --- /dev/null +++ b/zin/wg/formlabel/v1.php @@ -0,0 +1,29 @@ +props->has('text')) + { + $this->props->set('text', $child); + return false; + } + } + + protected function build() + { + list($text, $required, $for) = $this->prop(['text', 'required', 'for']); + return h::label + ( + setClass('form-label', $required ? 'required' : NULL), + set('for', $for), + set($this->getRestProps()), + $text, + $this->children(), + ); + } +} diff --git a/zin/wg/formpanel/v1.php b/zin/wg/formpanel/v1.php new file mode 100644 index 0000000000..8eaeb6fee9 --- /dev/null +++ b/zin/wg/formpanel/v1.php @@ -0,0 +1,46 @@ + 'panel-form rounded-md shadow ring-0 canvas px-4 pb-4 mb-4 mx-auto', + 'size' => 'lg' + ]; + + protected function created() + { + $this->setDefaultProps(['title' => data('title')]); + } + + protected function buildBody() + { + $props = $this->props->pick(['method', 'url', 'actions', 'target', 'items', 'grid', 'labelWidth']); + return div + ( + setClass('panel-body'), + new form + ( + set($props), + $this->children() + ) + ); + } +} diff --git a/zin/wg/formrow/v1.php b/zin/wg/formrow/v1.php new file mode 100644 index 0000000000..854acd8547 --- /dev/null +++ b/zin/wg/formrow/v1.php @@ -0,0 +1,34 @@ +prop(['width', 'items']); + + return div + ( + set::class('form-row', empty($width) ? NULL : 'grow-0'), + zui::width($width), + is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : null, + set($this->getRestProps()), + $this->children() + ); + } +} diff --git a/zin/wg/fragment/v1.php b/zin/wg/fragment/v1.php new file mode 100644 index 0000000000..c3da4b1f07 --- /dev/null +++ b/zin/wg/fragment/v1.php @@ -0,0 +1,21 @@ +getCssList(); + $js = $context->getJsList(); + $imports = $context->getImportList(); + + return array + ( + empty($css) ? NULL : h::css($css), + empty($imports) ? NULL : h::import($imports), + $this->children(), + empty($js) ? NULL : h::js($js) + ); + } +} diff --git a/zin/wg/header/v1.php b/zin/wg/header/v1.php new file mode 100644 index 0000000000..6d8e1a7131 --- /dev/null +++ b/zin/wg/header/v1.php @@ -0,0 +1,437 @@ + array('map' => 'toolbar'), + 'navbar' => array('map' => 'nav'), + 'toolbar' => array('map' => 'btn') + ); + + protected function buildHeading() + { + $heading = $this->block('heading'); + if(empty($heading)) $heading = new heading(); + return $heading; + } + + protected function buildNavbar() + { + $navbar = $this->block('navbar'); + if(empty($navbar)) $navbar = new navbar(); + return $navbar; + } + + protected function buildToolbar() + { + $toolbar = $this->block('toolbar'); + if(empty($toolbar)) + { + $toolbar = new toolbar + ( + setClass('gap-5'), + static::quickAddMenu(), + static::userBar(), + static::visionSwitcher() + ); + } + return h::div + ( + set::id('toolbar'), + $toolbar + ); + } + + /** + * Build. + * + * @access protected + * @return object + */ + protected function build() + { + return h::header + ( + setId('header'), + h::div + ( + setClass('container'), + $this->buildHeading(), + $this->buildNavbar(), + $this->buildToolbar() + ) + ); + } + + static function visionSwitcher() + { + global $lang, $app, $config; + + if(!isset($app->user)) return; + + if(!isset($app->user->visions)) $app->user->visions = trim($config->visions, ','); + $currentVision = $app->config->vision; + $userVisions = array_filter(explode(',', $app->user->visions)); + $configVisions = array_filter(explode(',', trim($config->visions, ','))); + + /* The standalone lite version removes the lite interface button */ + if(trim($config->visions, ',') == 'lite') return true; + + if(count($userVisions) < 2 || count($configVisions) < 2) return btn($lang->visionList[$currentVision]); + + $items = array(); + foreach($userVisions as $vision) + { + $items[] = array + ( + 'active' => $currentVision == $vision, + 'url' => createLink('my', 'ajaxSwitchVision', "vision=$vision"), + 'data-type' => 'ajax', + 'text' => $lang->visionList[$vision], + ); + } + + return dropdown + ( + btn + ( + setClass('bg-white ring-0 rounded bg-opacity-30'), + set::text($lang->visionList[$currentVision]), + set::caret(false) + ), + + set::id('versionMenu'), + set::trigger('hover'), + set::placement('bottom'), + set::menuProps(array('style' => array('color' => 'var(--color-fore)'))), + set::arrow(true), + set::items($items) + ); + } + + static function userBar() + { + global $lang, $app, $config; + + if(!isset($app->user)) return; + + $user = $app->user; + $isGuest = $user->account == 'guest'; + $items = array(); + + if(!$isGuest) + { + $noRole = empty($user->role) || !isset($lang->user->roleList[$user->role]); + $items[] = array + ( + 'type' => 'custom', + 'tag' => 'a', + 'href' => createLink('my', 'profile', '', '', true), + 'className' => 'items-center gap-2 px-2 py-1 row text-inherit', + 'renders' => array(array('__html' => implode('', array + ( + userAvatar(set::user($user), setClass('flex-none'))->render(), + div + ( + setClass('flex-auto'), + div(setClass('text-lg'), empty($user->realname) ? $user->account : $user->realname), + $noRole ? NULL : div(setClass('text-gray text-sm'), $lang->user->roleList[$user->role]) + )->render() + )))), + ); + + $items[] = array('type' => 'divider'); + + $items[] = array + ( + 'url' => createLink('my', 'profile', '', '', true), + 'icon' => 'account', + 'text' => $lang->profile, + 'class' => 'iframe', + 'data-width' => 700 + ); + + if($app->config->vision === 'rnd') + { + if(!commonModel::isTutorialMode()) + { + $items[] = array + ( + 'url' => createLink('tutorial', 'start'), + 'icon' => 'guide', + 'text' => $lang->tutorialAB, + 'class' => '800', + 'outerClass' => 'user-tutorial', + 'data-width' => 700, + 'data-class-name' => 'modal-inverse', + 'data-headerless' => true, + 'data-backdrop' => true, + 'data-keyboard' => true + ); + } + + $items[] = array + ( + 'url' => createLink('my', 'preference', 'showTip=false', '', true), + 'icon' => 'controls', + 'text' => $lang->preference, + 'class' => 'iframe', + 'data-width' => 700 + ); + } + + if(common::hasPriv('my', 'changePassword')) + { + $items[] = array + ( + 'url' => createLink('my', 'changepassword', '', '', true), + 'icon' => 'cog-outline', + 'text' => $lang->changePassword, + 'class' => 'iframe', + 'data-width' => 600 + ); + } + + $items[] = array('type' => 'divider'); + } + + $themeItems = array(); + foreach($app->lang->themes as $key => $value) + { + $themeItems[] = array('text' => $value, 'data-value' => $key, 'url' => "javascript:selectTheme(\"$key\")", 'active' => $app->cookie->theme == $key); + } + $items[] = array + ( + 'text' => $lang->theme, + 'icon' => 'theme', + 'items' => $themeItems + ); + + $langItems = array(); + foreach ($app->config->langs as $key => $value) + { + $langItems[] = array('text' => $value, 'data-value' => $key, 'url' => "javascript:selectLang(\"$key\")", 'active' => $app->cookie->lang == $key); + } + $items[] = array('text' => $lang->lang, 'icon' => 'lang', 'items' => $langItems); + + $helpItems = array(); + $manualUrl = ((!empty($config->isINT)) ? $config->manualUrl['int'] : $config->manualUrl['home']) . '&theme=' . $_COOKIE['theme']; + $helpItems[] = array('text' => $lang->manual, 'url' => $manualUrl, 'attrs' => array('data-app' => 'help')); + $helpItems[] = array('text' => $lang->changeLog, 'url' => createLink('misc', 'changeLog')); + $items[] = array('text' => $lang->help, 'icon' => 'help', 'items' => $helpItems); + + /* printClientLink */ + + $items[] = array('text' => $lang->aboutZenTao, 'icon' => 'about', 'url' => createLink('misc', 'about')); + $items[] = array('type' => 'html', 'className' => 'menu-item', 'html' => $lang->designedByAIUX); + + $items[] = array('type' => 'divider'); + + if($isGuest) + { + $items[] = array('text' => $lang->login, 'url' => createLink('user', 'login'), 'target' => '_top'); + } + else + { + $items[] = array('text' => $lang->logout, 'url' => createLink('user', 'logout'), 'target' => '_top', 'icon' => 'exit'); + } + + return dropdown + ( + a + ( + setClass('circle'), + userAvatar + ( + set::circle(true), + set::size(28), + set::user($user) + ), + set::square(true), + set::caret(false) + ), + + set::id('userMenu'), + set::trigger('hover'), + set::placement('bottom'), + set::menuProps(array('style' => array('color' => 'var(--color-fore)'))), + set::strategy('fixed'), + set::arrow(true), + set::items($items) + ); + } + + static function quickAddMenu() + { + global $app, $config, $lang; + + /* Initialize the default values. */ + $showCreateList = $needPrintDivider = false; + + /* Get default product id. */ + $productID = isset($_SESSION['product']) ? $_SESSION['product'] : 0; + if($productID) + { + $product = $app->dbh->query("SELECT id FROM " . TABLE_PRODUCT . " WHERE `deleted` = '0' and vision = '{$config->vision}' and id = '{$productID}'")->fetch(); + if(empty($product)) $productID = 0; + } + if(!$productID and $app->user->view->products) + { + $product = $app->dbh->query("SELECT id FROM " . TABLE_PRODUCT . " WHERE `deleted` = '0' and vision = '{$config->vision}' and id " . helper::dbIN($app->user->view->products) . " order by `order` desc limit 1")->fetch(); + if($product) $productID = $product->id; + } + + if($config->vision == 'lite') + { + $condition = " WHERE `deleted` = '0' AND `vision` = 'lite' AND `model` = 'kanban'"; + if(!$app->user->admin) $condition .= " AND `id` " . helper::dbIN($app->user->view->projects); + + $object = $app->dbh->query("select id from " . TABLE_PROJECT . $condition . ' LIMIT 1')->fetch(); + if(empty($object)) unset($lang->createIcons['story'], $lang->createIcons['task'], $lang->createIcons['execution']); + } + + if($config->edition == 'open') unset($lang->createIcons['effort']); + if($config->systemMode == 'light') unset($lang->createIcons['program']); + + /* Check whether the creation permission is available, and print create buttons. */ + $items = array(); + foreach($lang->createIcons as $objectType => $objectIcon) + { + $createMethod = 'create'; + $module = $objectType == 'kanbanspace' ? 'kanban' : $objectType; + if($objectType == 'effort') $createMethod = 'batchCreate'; + if($objectType == 'kanbanspace') $createMethod = 'createSpace'; + if(str_contains('|bug|execution|kanbanspace|', "|$objectType|")) $needPrintDivider = true; + + if(!common::hasPriv($module, $createMethod)) continue; + + if($objectType == 'doc' and !common::hasPriv('doc', 'tableContents')) continue; + + /* Determines whether to print a divider. */ + if($needPrintDivider and $showCreateList) + { + $items[] = array('type' => 'divider'); + $needPrintDivider = false; + } + + $showCreateList = true; + $isOnlyBody = false; + $item = array('icon' => $objectIcon, 'text' => $lang->createObjects[$objectType]); + + $params = ''; + switch($objectType) + { + case 'doc': + $params = "objectType=&objectID=0&libID=0"; + $createMethod = 'selectLibType'; + $isOnlyBody = true; + $item['class'] = 'iframe'; + $item['data-width'] = '700px'; + break; + case 'project': + if($config->vision == 'lite') + { + $params = "model=kanban"; + } + else if(!defined('TUTORIAL')) + { + $params = "programID=0&from=global"; + $createMethod = 'createGuide'; + $item['data-toggle'] = 'modal'; + } + else + { + $params = "model=scrum&programID=0©ProjectID=0&extra=from=global"; + } + + break; + case 'bug': + $params = "productID=$productID&branch=&extras=from=global"; + break; + case 'story': + if(!$productID and $config->vision == 'lite') + { + $module = 'project'; + $params = "model=kanban"; + } + else + { + $params = "productID=$productID&branch=0&moduleID=0&storyID=0&objectID=0&bugID=0&planID=0&todoID=0&extra=from=global"; + if($config->vision == 'lite') + { + $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0; + $projects = $app->dbh->query("SELECT t2.id FROM " . TABLE_PROJECTPRODUCT . " AS t1 LEFT JOIN " . TABLE_PROJECT . " AS t2 ON t1.project = t2.id WHERE t1.`product` = '{$productID}' and t2.`type` = 'project' and t2.id " . helper::dbIN($app->user->view->projects) . " ORDER BY `order` desc")->fetchAll(); + + $projectIdList = array(); + foreach($projects as $project) $projectIdList[$project->id] = $project->id; + if($projectID and !isset($projectIdList[$projectID])) $projectID = 0; + if(empty($projectID)) $projectID = key($projectIdList); + + $params = "productID={$productID}&branch=0&moduleID=0&storyID=0&objectID={$projectID}&bugID=0&planID=0&todoID=0&extra=from=global"; + } + } + + break; + case 'task': + $params = "executionID=0&storyID=0&moduleID=0&taskID=0&todoID=0&extra=from=global"; + break; + case 'testcase': + $params = "productID=$productID&branch=&moduleID=0&from=¶m=0&storyID=0&extras=from=global"; + break; + case 'execution': + $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0; + $params = "projectID={$projectID}&executionID=0©ExecutionID=0&planID=0&confirm=no&productID=0&extra=from=global"; + break; + case 'product': + $params = "programID=&extra=from=global"; + break; + case 'program': + $params = "parentProgramID=0&extra=from=global"; + break; + case 'kanbanspace': + $isOnlyBody = true; + $item['class'] = 'iframe'; + $item['data-width'] = '75%'; + break; + case 'kanban': + $isOnlyBody = true; + $item['class'] = 'iframe'; + $item['data-width'] = '75%'; + break; + } + + $item['url'] = createLink($module, $createMethod, $params, '', $isOnlyBody); + + $items[] = $item; + } + + if(!$showCreateList) return ''; + + return dropdown + ( + btn + ( + icon('plus', set::size('lg')), + setClass('bg-white ring-0 rounded bg-opacity-20'), + set::square(true), + set::size('sm'), + set::caret(false) + ), + + set::id('quickAddMenu'), + set::menuProps(array('style' => array('color' => 'var(--color-fore)'))), + set::trigger('hover'), + set::placement('bottom'), + set::strategy('fixed'), + set::arrow(true), + set::items($items) + ); + } +} diff --git a/zin/wg/heading/v1.php b/zin/wg/heading/v1.php new file mode 100644 index 0000000000..f7e5cb4f70 --- /dev/null +++ b/zin/wg/heading/v1.php @@ -0,0 +1,61 @@ +navIcons, $tab, ''); + + if(!in_array($tab, array('program', 'product', 'project'))) + { + $nav = $lang->mainNav->$tab; + list($title, $currentModule, $currentMethod, $vars) = explode('|', $nav); + if($tab == 'execution') $currentMethod = 'all'; + } + else + { + $currentModule = $tab; + if($tab == 'program' or $tab == 'project') $currentMethod = 'browse'; + if($tab == 'product') $currentMethod = 'all'; + } + + $url = createLink($currentModule, $currentMethod); + return item + ( + set::url($url), + set::hint($lang->$tab->common), + $tab == 'devops' ? set::class('num') : NULL, + html($icon), + span(set::class('text'), $lang->$tab->common), + ); + } + + /** + * Build. + * + * @access protected + * @return object + */ + protected function build() + { + $showAppName = $this->prop('showAppName'); + + return div + ( + set::id('heading'), + new toolbar + ( + $showAppName ? $this->buildAppName() : NULL, + set::btnClass('primary'), + set::items($this->prop('items')), + $this->children() + ) + ); + } +} diff --git a/zin/wg/historyrecord/css/v1.css b/zin/wg/historyrecord/css/v1.css new file mode 100644 index 0000000000..38a6ccf1fe --- /dev/null +++ b/zin/wg/historyrecord/css/v1.css @@ -0,0 +1,186 @@ +.detail { + padding: 10px; +} + +.detail-title { + font-size: 14px; + font-weight: 700; + line-height: 20px; +} + +.histories .btn-mini { + width: 16px; + min-width: 16px; + height: 16px; + overflow: hidden; + line-height: 16px; + color: #cbd0db; + vertical-align: -8%; + border-radius: 1px; + font-size: 12px; +} + +.histories .btn { + background-color: #fff; + display: inline-block; + margin-bottom: 0; + font-weight: 400; + text-align: center; + white-space: nowrap; + cursor: pointer; + user-select: none; + border: 1px solid #d8dbde; + transition: .4s cubic-bezier(.175,.885,.32,1); + transition-property: background,border,box-shadow,outline,opacity,-webkit-box-shadow; +} + +.histories .icon { + font-family: ZentaoIcon; + font-size: 14px; + font-style: normal; + font-weight: 400; + font-variant: normal; + line-height: 1; + text-transform: none; + -webkit-font-smoothing: antialiased; +} + +.btn-icon { + padding-right: 0; + padding-left: 0; +} + +.detail-title > span { + margin-right: 10px; +} + +.detail-title > .pull-right { + position: relative; + top: -8px; +} + +.histories .btn-link { + padding-right: 6px; + padding-left: 6px; + font-weight: 400; + color: #313c52; + text-shadow: none; + cursor: pointer; + background: 0 0; + box-shadow: none; + border-color: transparent; +} + +.detail-content { + padding: 0; + margin-top: 10px; +} + +.histories-list { + padding-left: 15px; + margin-bottom: 0; + margin-top: 0; + list-style: decimal; + display: flex; + flex-direction: column; +} + +.histories-list.sort-reverse { + flex-direction: column-reverse; +} + +.histories-list > li { + word-break: break-word; + word-wrap: break-word; + position: relative; +} + +.histories-list > li strong { + color: #313c52; +} + +.history-changes { + display: none; + padding: 5px; + margin-bottom: -5px; + margin-left: 5px; + font-size: 12px; + line-height: 20px; +} + +.history-changes.show { + display: block; +} + +.histories-list .btn-edit-comment { + position: absolute; + top: 28px; + right: 2px; + z-index: 100; +} + +.btn-icon.btn-sm { + width: 24px; + min-width: 24px; + height: 24px; + padding-left: 0; + padding-right: 0; +} + +.btn-sm { + padding: 3px 8px; + font-size: 12px; + line-height: 18px; + border-radius: 4px; +} + +.histories-list .comment, +.histories-list .show-form .comment-edit-form { + padding: 5px 5px 5px 10px; + margin: 5px 0 0; + background-color: rgba(0,0,0,.025); + border: 1px solid #eee; +} + +.article-content, .article > .content { + word-wrap: break-word; +} + +.article-content { + overflow: auto; + font-size: 14px; + line-height: 1.57142857; +} + +.comment .comment-content { + width: 98%; +} + +.form-actions .btn { + margin-right: 10px; +} + +.btn-wide { + min-width: 120px; +} + +.btn-primary { + color: #fff; + background-color: #2e7fff; + border-color: transparent; +} + +.form-actions { + margin-top: 20px; + margin-bottom: 0; +} + +.form-group { + margin-bottom: 10px; +} + +.histories-list .comment-edit-form, +.histories-list .show-form .btn-edit-comment, +.histories-list .show-form .comment { + display: none; +} diff --git a/zin/wg/historyrecord/v1.php b/zin/wg/historyrecord/v1.php new file mode 100644 index 0000000000..9e2a25297b --- /dev/null +++ b/zin/wg/historyrecord/v1.php @@ -0,0 +1,271 @@ +prop('methodName') ?? data('methodName'); + + return (!isset($canBeChanged) || !empty($canBeChanged)) + && end($actions) == $action + && trim($action->comment) !== '' + && str_contains(',view,objectlibs,viewcard,', ",$methodName,") + && $action->actor == $app->user->account + && common::hasPriv('action', 'editComment'); + } + + private function createExpandBtn($i) + { + global $lang; + + return button + ( + setClass('btn btn-mini switch-btn btn-icon btn-expand'), + set::type('button'), + set::title($lang->switchDisplay), + h::i(setClass('change-show icon icon-plus icon-sm')), + on::click(<<action->editComment), + h::i(setClass('icon icon-pencil')), + ); + } + + private function createHistoryChangesView($action, $i) + { + global $app; + + return div + ( + setClass('history-changes'), + set::id("changeBox$i"), + html($app->loadTarget('action')->renderChanges($action->objectType, $action->history)), + ); + } + + private function createActionItemView($action, $i) + { + global $app; + + return li + ( + set::value($i), + html($app->loadTarget('action')->renderAction($action)) + ); + } + + private function generateComment($action) + { + if(str_contains($action->comment, '
    '))
    +        {
    +            $before   = explode('
    ', $action->comment);
    +            $after    = explode('
    ', $before[1]); + $htmlCode = $after[0]; + return $before[0] . htmlspecialchars($htmlCode) . $after[1]; + } + + return strip_tags($action->comment) === $action->comment + ? nl2br($action->comment) + : $action->comment; + } + + private function createCommentView($action) + { + $comment = $this->generateComment($action); + + return div + ( + setClass('article-content comment'), + div + ( + setClass('comment-content'), + $comment, + ), + ); + } + + private function createCommentEditForm($action) + { + global $lang; + + return form + ( + setClass('comment-edit-form'), + set::method('post'), + set::action(createLink('action', 'editComment', "actionID=$action->id")), + div + ( + setClass('form-group'), + textarea + ( + htmlSpecialString($action->comment), + set::name('lastComment'), + set::rows('8'), + set::autofocus('autofocus'), + ), + ), + div + ( + setClass('form-group form-actions'), + button + ( + setClass('btn btn-wide btn-primary'), + set::type('submit'), + set::id('submit'), + $lang->save, + ), + button + ( + setClass('btn btn-wide btn-hide-form'), + $lang->close, + ), + ), + ); + } + + private function buildHistoriesList() + { + $actions = $this->prop('actions') ?? data('actions'); + $users = $this->prop('users') ?? data('users'); + $historiesListView = h::ol(setClass('histories-list')); + $i = 0; + + foreach($actions as $action) + { + if($action->action === 'assigned' || $action->action === 'toaudit') + $action->extra = zget($users, $action->extra); + + $action->actor = zget($users, $action->actor); + if(str_contains($action->actor, ':')) + $action->actor = substr($action->actor, strpos($action->actor, ':') + 1); + + $i++; + $actionItemView = $this->createActionItemView($action, $i); + + if(!empty($action->history)) + { + $allExpandBtn = $this->createExpandBtn($i); + $actionItemView->add($allExpandBtn); + + $historyChangesView = $this->createHistoryChangesView($action, $i); + $actionItemView->add($historyChangesView); + } + if(strlen(trim(($action->comment))) !== 0) + { + $canEditComment = $this->checkEditCommentPriv($action); + + if($canEditComment) + { + $editCommentBtn = $this->createEditCommentBtn(); + $actionItemView->add($editCommentBtn); + } + + $commentView = $this->createCommentView($action); + $actionItemView->add($commentView); + + if($canEditComment) + { + $commentEditForm = $this->createCommentEditForm($action); + $actionItemView->add($commentEditForm); + } + } + $historiesListView->add($actionItemView); + } + + return $historiesListView; + } + + protected function build() + { + global $lang; + return div + ( + setClass('detail histories'), + set::id('actionbox'), + set('data-textdiff', $lang->action->textDiff), + set('data-original', $lang->action->original), + div + ( + setClass('detail-title'), + span($lang->history), + button + ( + setClass('btn btn-mini btn-icon btn-reverse'), + setStyle('margin-right', '4px'), + set::type('button'), + set::title($lang->reverse), + h::i(setClass('icon icon-arrow-up icon-sm')), + on::click(<<switchDisplay), + h::i(setClass('icon icon-plus icon-sm')), + on::click(<<action->create) + ), + ), + div(setClass('detail-content'), $this->buildHistoriesList()) + ); + } +} diff --git a/zin/wg/icon/v1.php b/zin/wg/icon/v1.php new file mode 100644 index 0000000000..e43903aa91 --- /dev/null +++ b/zin/wg/icon/v1.php @@ -0,0 +1,32 @@ +props->has('name')) + { + $this->props->set('name', $child); + return false; + } + } + + protected function build() + { + list($name, $size) = $this->prop(array('name', 'size')); + return h::i + ( + setClass('icon', empty($name) ? NULL : "icon-$name"), + is_numeric($size) + ? setStyle('font-size', "{$size}px") + : (is_string($size) + ? setClass("icon-$size") + : NULL), + set($this->props->skip(array_keys(icon::getDefinedProps()))), + $this->children() + ); + } +} diff --git a/zin/wg/input/v1.php b/zin/wg/input/v1.php new file mode 100644 index 0000000000..c47f4757b0 --- /dev/null +++ b/zin/wg/input/v1.php @@ -0,0 +1,34 @@ + 'text', + 'class' => 'form-control', + ]; + + protected function build() + { + $props = $this->props->skip('required'); + $required = $this->prop('required'); + if(!$this->hasProp('id') && isset($props['name'])) $props['id'] = $props['name']; + if(is_bool($props['autocomplete'])) $props['autocomplete'] = $props['autocomplete'] ? 'on' : 'off'; + return h::input(set($props), $required ? setClass('is-required') : NULL); + } +} diff --git a/zin/wg/inputcontrol/v1.php b/zin/wg/inputcontrol/v1.php new file mode 100644 index 0000000000..ef52616647 --- /dev/null +++ b/zin/wg/inputcontrol/v1.php @@ -0,0 +1,73 @@ + [], + 'suffix' => [], + ]; + + protected function build() + { + list($prefix, $suffix, $prefixWidth, $suffixWidth) = $this->prop(['prefix', 'suffix', 'prefixWidth', 'suffixWidth']); + + if(empty($prefix)) $prefix = $this->block('prefix'); + if(empty($suffix)) $suffix = $this->block('suffix'); + + $class = ['input-control']; + $vars = []; + if(!empty($prefix)) + { + if(is_numeric($prefixWidth)) + { + $vars['input-control-prefix'] = $prefixWidth . 'px'; + $class[] = 'has-prefix'; + } + elseif(!empty($prefixWidth)) + { + $class[] = "has-prefix-$prefixWidth"; + } + else + { + $class[] = 'has-prefix'; + } + } + if(!empty($suffix)) + { + if(is_numeric($suffixWidth)) + { + $vars['input-control-suffix'] = $suffixWidth . 'px'; + $class[] = 'has-suffix'; + } + elseif(!empty($suffixWidth)) + { + $class[] = "has-suffix-$suffixWidth"; + } + else + { + $class[] = 'has-suffix'; + } + } + + return div + ( + setClass($class), + empty($vars) ? NULL : setCssVar($vars), + $this->children(), + empty($prefix) ? NULL : div(setClass('input-control-prefix'), $prefix), + empty($suffix) ? NULL : div(setClass('input-control-suffix'), $suffix) + ); + } +} diff --git a/zin/wg/inputgroup/v1.php b/zin/wg/inputgroup/v1.php new file mode 100644 index 0000000000..7251d89fad --- /dev/null +++ b/zin/wg/inputgroup/v1.php @@ -0,0 +1,50 @@ + 'addon', 'text' => $item])); + elseif(is_array($item)) $item = new item(set($item)); + elseif($item instanceof wg) return $item; + + $type = $item->prop('type'); + + if($type === 'addon') return h::span(setClass('input-group-addon'), set($item->props->skip('type,text')), $item->prop('text')); + + if($type === 'btn') return new btn(set($item->props->skip('type'))); + + if($type === 'inputControl') + { + $propNames = array_keys(inputControl::getDefinedProps()); + return new inputControl + ( + set($item->props->pick($propNames)), + new input(set($item->props->skip(array_merge($propNames, ['type'])))) + ); + } + + return new input(inherit($item)); + } + + protected function build() + { + list($items, $seg) = $this->prop(['items', 'seg']); + $children = $this->children(); + + return div + ( + setClass('input-group', $seg ? 'input-group-segment' : NULL), + set($this->getRestProps()), + is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : NULL, + is_array($children) ? array_map(array($this, 'onBuildItem'), $children) : NULL, + ); + } +} diff --git a/zin/wg/label/v1.php b/zin/wg/label/v1.php new file mode 100644 index 0000000000..99993ac308 --- /dev/null +++ b/zin/wg/label/v1.php @@ -0,0 +1,27 @@ +props->has('text')) + { + $this->props->set('text', $child); + return false; + } + } + + public function build() + { + return span + ( + setClass('label'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $this->prop('text'), + $this->children() + ); + } +} diff --git a/zin/wg/main/v1.php b/zin/wg/main/v1.php new file mode 100644 index 0000000000..81eb38087d --- /dev/null +++ b/zin/wg/main/v1.php @@ -0,0 +1,78 @@ + array('map' => 'featureBar,nav,toolbar'), + 'sidebar' => array('map' => 'sidebar') + ); + + protected function buildMenu() + { + $menuBlocks = $this->block('menu'); + if(empty($menuBlocks)) return NULL; + + list($featureBarList, $navList, $toolbarList, $restList) = groupWgInList($menuBlocks, array('featureBar', 'nav', 'toolbar')); + + $featureBar = NULL; + if(!empty($featureBarList)) $featureBar = $featureBarList[0]; + elseif(!empty($navList)) $featureBar = new featureBar($navList); + + $toolbar = NULL; + if(!empty($toolbarList)) $toolbar = $toolbarList[0]; + if($toolbar instanceof wg && !$toolbar->hasProp('id')) $toolbar->setProp('id', 'actionBar'); + + return div + ( + set::id('mainMenu'), + $featureBar, + $toolbar, + $restList + ); + } + + protected function buildContent() + { + $leftSides = array(); + $rightSides = array(); + $sidebars = $this->block('sidebar'); + + if(!empty($sidebars)) + { + foreach($sidebars as $sidebar) + { + if($sidebar instanceof wg && $sidebar->prop('side') === 'left') $leftSides[] = $sidebar; + else $rightSides[] = $sidebar; + } + } + + return div + ( + set::id('mainContent'), + $leftSides, + set::class(empty($leftSides) && empty($rightSides) ? '' : 'row', empty($leftSides) ? '' : 'has-sidebar-left', empty($rightSides) ? '' : 'has-sidebar-right'), + $this->children(), + $rightSides + ); + } + + protected function build() + { + return div + ( + set::id('main'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + div + ( + set::class('container'), + $this->buildMenu(), + $this->buildContent() + ) + ); + } +} diff --git a/zin/wg/mainmenu/v1.php b/zin/wg/mainmenu/v1.php new file mode 100644 index 0000000000..a4e6fab4f1 --- /dev/null +++ b/zin/wg/mainmenu/v1.php @@ -0,0 +1,67 @@ +prop('others'); + + if(empty($others)) + { + $otherElms = null; + } + else + { + $otherElms = array(); + foreach($others as $item) $otherElms[] = $this->buildOther($item); + } + + + return div + ( + setId('mainMenu'), + setClass('flex justify-between'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + div + ( + setClass('flex'), + div + ( + toolbar(set(array('items' => $this->prop('statuses')))) + ), + $otherElms + ), + div + ( + setId('featureBarBtns'), + toolbar + ( + setClass('toolbar-btn-group'), + setStyle('gap', '0.625rem'), + set(array('items' => $this->prop('btnGroup'))) + ) + ) + ); + } +} diff --git a/zin/wg/menu/v1.php b/zin/wg/menu/v1.php new file mode 100644 index 0000000000..609ffe18ad --- /dev/null +++ b/zin/wg/menu/v1.php @@ -0,0 +1,34 @@ +prop('items'); + return h::menu + ( + setClass('menu'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + is_array($items) ? array_map(array($this, 'onBuildItem'), $this->prop('items')) : NULL, + $this->children(), + ); + } +} diff --git a/zin/wg/modal/v1.php b/zin/wg/modal/v1.php new file mode 100644 index 0000000000..05b510dd28 --- /dev/null +++ b/zin/wg/modal/v1.php @@ -0,0 +1,24 @@ +prop(array('id', 'modalProps')); + + $this->setProp($modalProps); + + return div + ( + setClass('modal'), + set::id($id), + set($this->props->skip(array_merge(array_keys($modalProps), array_keys(static::getDefinedProps())))), + parent::build() + ); + } +} diff --git a/zin/wg/modaldialog/v1.php b/zin/wg/modaldialog/v1.php new file mode 100644 index 0000000000..c1895b8d36 --- /dev/null +++ b/zin/wg/modaldialog/v1.php @@ -0,0 +1,105 @@ + [], + 'actions' => [], + 'footer' => ['map' => 'toolbar'] + ]; + + protected function buildHeader() + { + $title = $this->prop('title'); + $itemID = $this->prop('itemID'); + $headerBlock = $this->block('header'); + + if(empty($title) && empty($headerBlock)) return null; + + return div + ( + setClass('modal-header', $this->prop('headerClass')), + set($this->prop('headerProps')), + empty($itemID) ? NULL : label($itemID, setStyle(['min-width' => '30px']), setClass('justify-center')), + empty($title) ? NULL : div(setClass('modal-title'), $title), + $headerBlock + ); + } + + protected function buildActions() + { + list($actions, $closeBtn) = $this->prop(array('actions', 'closeBtn')); + $actionsBlock = $this->block('actions'); + + if(empty($actions) && empty($actionsBlock) && !$closeBtn) return; + + return div + ( + setClass('modal-actions'), + empty($actions) ? NULL : toolbar(set::items($actions)), + $actionsBlock, + $closeBtn ? btn + ( + set('data-dismiss', 'modal'), + set::square(true), + is_array($closeBtn) ? set($closeBtn) : setClass('ghost'), + span(setClass('close')) + ) : NULL + ); + } + + protected function buildFooter() + { + list($footerActions) = $this->prop(array('footerActions')); + $footerBlock = $this->block('footer'); + + if(empty($footerActions) && empty($footerBlock)) return; + + return div + ( + setClass('modal-footer', $this->prop('footerClass')), + set($this->prop('footerProps')), + $footerBlock, + empty($footerActions) ? NULL : toolbar(set::items($footerActions)) + ); + } + + protected function buildBody() + { + return div + ( + setClass('modal-body'), + $this->children() + ); + } + + protected function build() + { + return div + ( + setClass('modal-dialog'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + div + ( + setClass('modal-content'), + $this->buildHeader(), + $this->buildActions(), + $this->buildBody(), + $this->buildFooter() + ) + ); + } +} diff --git a/zin/wg/modaltrigger/v1.php b/zin/wg/modaltrigger/v1.php new file mode 100644 index 0000000000..929dc3c8b7 --- /dev/null +++ b/zin/wg/modaltrigger/v1.php @@ -0,0 +1,89 @@ + array('map' => 'btn,a'), + 'modal' => array('map' => 'modal') + ]; + + protected function build() + { + list($target, $url, $type) = $this->prop(['target', 'url', 'type']); + + $triggerBlock = $this->block('trigger'); + $modalBlock = $this->block('modal'); + + if(empty($target) && !empty($modalBlock)) + { + $modal = $modalBlock[0]; + $target = $modal->id(); + if(empty($target)) + { + $target = $modal->gid; + $modal->setProp('id', $target); + } + $target = "#$target"; + } + if(!empty($url) && empty($type)) $type = 'ajax'; + + if(empty($triggerBlock)) $triggerBlock = h::a($this->children()); + elseif(is_array($triggerBlock)) $triggerBlock = $triggerBlock[0]; + + if($triggerBlock instanceof wg) + { + $triggerBlock->setProp($this->props->skip(array_keys(static::getDefinedProps()))); + + $triggerProps = [ + 'data-toggle' => 'modal', + 'data-target' => $triggerBlock->hasProp('target', 'href') ? NULL : $target, + 'data-type' => $type, + 'data-url' => $url, + 'data-position' => $this->prop('position'), + 'data-size' => $this->prop('size'), + 'data-backdrop' => $this->prop('backdrop'), + 'data-keyboard' => $this->prop('keyboard'), + 'data-moveable' => $this->prop('moveable'), + 'data-animation' => $this->prop('animation'), + 'data-trans-time' => $this->prop('transTime'), + 'data-responsive' => $this->prop('responsive'), + 'data-loading-text' => $this->prop('loadingText'), + 'data-loadTimeout' => $this->prop('loadTimeout'), + 'data-failed-tip' => $this->prop('failedTip'), + 'data-timeout-tip' => $this->prop('timeoutTip'), + 'data-title' => $this->prop('title'), + 'data-content' => $this->prop('content'), + 'data-custom' => $this->prop('custom'), + 'data-request' => $this->prop('request'), + 'data-data-type' => $this->prop('dataType') + ]; + $triggerBlock->setProp($triggerProps); + } + + return array($triggerBlock, $modalBlock); + } +} diff --git a/zin/wg/modulemenu/css/v1.css b/zin/wg/modulemenu/css/v1.css new file mode 100644 index 0000000000..6a426d0577 --- /dev/null +++ b/zin/wg/modulemenu/css/v1.css @@ -0,0 +1,67 @@ +.module-menu { + max-height: 100%; + display: flex; + flex-direction: column; + border-radius: 2px; +} + +.module-menu > header { + height: 40px; + display: flex; + align-items: center; + padding-left: 12px; + flex: none; +} + +.module-menu .module-title { + font-size: 13; + line-height: 20px; + font-weight: bold; +} + +.module-menu > header span { + margin-right: 12px; +} + +.module-menu > header i { + padding: 2px; +} + +.module-menu > main { + display: flex; + flex: 1 1 auto; + overflow: hidden; + flex-direction: column; +} + +.module-menu > main > .menu { + border: none; + box-shadow: none; + flex: 1 1 auto; + overflow-y: auto; +} + +.setting-btns { + display: flex; + flex-direction: column; + padding: 10px 30px; + gap: 8px; +} + +.module-menu .menu-item > a:hover { + background: #EFF5FF; + color: #313C52; +} + +.module-menu, +.module-menu .has-nested-menu > .menu.menu-nested { + background-color: #fff; +} + +.module-menu .menu { + padding: 0; +} + +.module-menu .menu-item.active { + color: #2e7fff; +} diff --git a/zin/wg/modulemenu/v1.php b/zin/wg/modulemenu/v1.php new file mode 100644 index 0000000000..a1f6309c75 --- /dev/null +++ b/zin/wg/modulemenu/v1.php @@ -0,0 +1,111 @@ +getChildModule($parentID); + if(count($children) === 0) return []; + + foreach($children as $child) + { + $item = array('key' => $child->id, 'text' => $child->name, 'items' => []); + $items = $this->buildMenuTree($item['items'], $child->id); + if(count($items) !== 0) $item['items'] = $items; + else unset($item['items']); + $parentItems[] = $item; + } + return $parentItems; + } + + private function getChildModule($id) + { + return array_filter($this->modules, fn($module) => $module->parent == $id); + } + + private function setMenuTreeProps() + { + global $app; + $id = $this->prop('productID'); + $this->setProp('productID', null); + $this->modules = $app->loadTarget('tree')->getProductStructure($id, 'story'); + $this->setProp('items', $this->buildMenuTree([], 0)); + $this->setDefaultProps(array('activeClass' => 'active')); + } + + private function getTitle($activeKey) + { + foreach($this->modules as $module) + if($module->id == $activeKey) + return $module->name; + } + + protected function build() + { + global $app; + $lang = $app->loadLang('datatable')->datatable; + $this->setMenuTreeProps(); + $activeKey = $this->prop('activeKey'); + $title = $this->getTitle($activeKey); + $closeBtn = null; + if(!empty($activeKey)) + { + $closeBtn = a + ( + set('href', $this->prop('closeLink')), + h::i + ( + setClass('icon icon-close'), + setStyle('color', '#313C52') + ) + ); + } + return div + ( + setClass('module-menu rounded shadow-sm'), + h::header + ( + span + ( + setClass('module-title'), + $title + ), + $closeBtn + ), + h::main + ( + zui::menutree(inherit($this)) + ), + div + ( + setClass('setting-btns'), + a + ( + setClass('btn'), + setStyle('background', '#EEF5FF'), + setStyle('border', 'none'), + $lang->moduleSetting + ), + a + ( + setClass('btn white'), + $lang->displaySetting + ), + ) + ); + } +} diff --git a/zin/wg/nav/v1.php b/zin/wg/nav/v1.php new file mode 100755 index 0000000000..38ca91b667 --- /dev/null +++ b/zin/wg/nav/v1.php @@ -0,0 +1,33 @@ +prop('items'); + return h::menu + ( + setClass('nav'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : NULL, + $this->children() + ); + } +} diff --git a/zin/wg/navbar/v1.php b/zin/wg/navbar/v1.php new file mode 100644 index 0000000000..8d8be6c4d5 --- /dev/null +++ b/zin/wg/navbar/v1.php @@ -0,0 +1,300 @@ +dbh->query('SELECT project,type FROM ' . TABLE_EXECUTION . " WHERE `id` = '$executionID'")->fetch(); + if(empty($object)) return; + + $executionPairs = array(); + $userCondition = !$app->user->admin ? " AND `id` " . helper::dbIN($app->user->view->sprints) : ''; + $orderBy = $object->type == 'stage' ? 'ORDER BY `id` ASC' : 'ORDER BY `id` DESC'; + $executionList = $app->dbh->query("SELECT id,name,parent FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' AND `deleted` = '0' $userCondition $orderBy")->fetchAll(); + foreach($executionList as $execution) + { + if(isset($executionPairs[$execution->parent])) unset($executionPairs[$execution->parent]); + if($execution->id == $executionID) continue; + $executionPairs[$execution->id] = $execution->name; + } + + if(empty($executionPairs)) return; + + $dropItems = array(); + foreach($executionPairs as $executionID => $executionName) + { + $dropItems[] = array + ( + 'url' => createLink('execution', 'task', "executionID=$executionID"), + 'text' => $executionName, + 'hint' => $executionName, + 'class' => 'text-ellipsis' + ); + + if(count($dropItems) >= 10) break; + } + + if(count($executionPairs) > 10) + { + $dropItems[] = array + ( + 'url' => createLink('project', 'execution', "status=all&projectID={$object->project}"), + 'text' => "$lang->preview $lang->more", + 'hint' => $lang->more, + 'data-app' => 'project' + ); + } + + return array + ( + 'type' => 'dropdown', + 'items' => $dropItems, + 'text' => $lang->more, + 'trigger' => 'hover', + 'menuProps' => array('style' => array('max-width' => '300px')) + ); + } + + protected function getAppBtnItem() + { + if(defined('TUTORIAL')) return; + global $app, $config, $lang; + + $condition = ''; + if(!$app->user->admin) + { + $types = ''; + foreach($config->pipelineTypeList as $pipelineType) + { + if(commonModel::hasPriv($pipelineType, 'browse')) $types .= "'$pipelineType',"; + } + if(empty($types)) return; + $condition .= ' AND `type` in (' . trim($types, ',') . ')'; + } + $pipelineList = $app->dbh->query("SELECT type,name,url FROM " . TABLE_PIPELINE . " WHERE `deleted` = '0' $condition order by type")->fetchAll(); + if(empty($pipelineList)) return; + + $dropItems = array(); + foreach($pipelineList as $pipeline) + { + $dropItems[] = array + ( + 'url' => $pipeline->url, + 'text' => "[{$pipeline->type}] {$pipeline->name}", + 'hint' => $pipeline->name, + 'class' => 'text-ellipsis', + 'target' => '_blank' + ); + } + + return array + ( + 'type' => 'dropdown', + 'items' => $dropItems, + 'text' => $lang->app->common, + 'trigger' => 'hover', + 'menuProps' => array('style' => array('max-width' => '300px')) + ); + } + + protected function getItems() + { + $items = $this->prop('items'); + if(!empty($items)) return $items; + + commonModel::setMainMenu(); + commonModel::checkMenuVarsReplaced(); + + global $app, $lang; + $isTutorialMode = commonModel::isTutorialMode(); + $currentModule = $app->rawModule; + $currentMethod = $app->rawMethod; + + if($isTutorialMode and defined('WIZARD_MODULE')) $currentModule = WIZARD_MODULE; + if($isTutorialMode and defined('WIZARD_METHOD')) $currentMethod = WIZARD_METHOD; + + $menu = \customModel::getMainMenu(); + $tab = $app->tab; + $activeMenu = ''; + $items = array(); + foreach ($menu as $menuItem) + { + if(isset($menuItem->hidden) and $menuItem->hidden and (!isset($menuItem->tutorial) or !$menuItem->tutorial)) continue; + if(empty($menuItem->link)) continue; + + if($menuItem->divider) $items[] = array('type' => 'divider'); + + /* Init the these vars. */ + $subModule = isset($menuItem->subModule) ? explode(',', $menuItem->subModule) : array(); + $class = isset($menuItem->class) ? $menuItem->class : ''; + $exclude = isset($menuItem->exclude) ? $menuItem->exclude : ''; + $isActive = false; + + if($menuItem->name == $currentModule and !str_contains(",$exclude,", ",$currentModule-$currentMethod,")) + { + $isActive = true; + } + elseif($subModule and in_array($currentModule, $subModule) and !str_contains(",$exclude,", ",$currentModule-$currentMethod,")) + { + $isActive = true; + } + + if($menuItem->link['module'] == 'execution' and $menuItem->link['method'] == 'more') + { + $executionID = $menuItem->link['vars']; + $executionMoreItem = $this->getExecutionMoreItem($executionID); + if(!empty($executionMoreItem)) + { + $items[] = array('type' => 'divider'); + $items[] = $executionMoreItem; + } + } + elseif($menuItem->link['module'] == 'app' and $menuItem->link['method'] == 'serverlink') + { + $appBtnItem = $this->getAppBtnItem(); + if(!empty($appBtnItem)) $items[] = $appBtnItem; + } + elseif($menuItem->link) + { + $alias = isset($menuItem->alias) ? $menuItem->alias : ''; + $target = ''; + $module = ''; + $method = ''; + $label = $menuItem->text; + + if(is_array($menuItem->link)) + { + if(isset($menuItem->link['target'])) $target = $menuItem->link['target']; + if(isset($menuItem->link['module'])) $module = $menuItem->link['module']; + if(isset($menuItem->link['method'])) $method = $menuItem->link['method']; + } + + if($module == $currentModule and ($method == $currentMethod or str_contains(",$alias,", ",$currentMethod,")) and !str_contains(",$exclude,", ",$currentMethod,")) + { + $isActive = true; + } + + $dataApp = (isset($lang->navGroup->$module) and $tab != $lang->navGroup->$module) ? $tab : NULL; + if($isActive && empty($activeMenu)) $activeMenu = $menuItem->name; + else $isActive = false; + + /* Print drop menus. */ + if(isset($menuItem->dropMenu)) + { + $dropItems = array(); + foreach($menuItem->dropMenu as $dropMenuName => $dropMenuItem) + { + if(empty($dropMenuItem)) continue; + if(isset($dropMenuItem->hidden) and $dropMenuItem->hidden) continue; + + /* Parse drop menu link. */ + $dropMenuLink = zget($dropMenuItem, 'link', $dropMenuItem); + + list($subLabel, $subModule, $subMethod, $subParams) = explode('|', $dropMenuLink); + if(!common::hasPriv($subModule, $subMethod)) continue; + + $subLink = createLink($subModule, $subMethod, $subParams); + + $subActive = false; + $activeMainMenu = false; + if($currentModule == strtolower($subModule) and $currentMethod == strtolower($subMethod)) + { + $activeMainMenu = true; + } + else + { + $subModule = isset($dropMenuItem['subModule']) ? explode(',', $dropMenuItem['subModule']) : array(); + if($subModule and in_array($currentModule, $subModule) and !str_contains(",$exclude,", ",$currentModule-$currentMethod,")) $activeMainMenu = true; + } + + if($activeMainMenu) + { + $activeMenu = $dropMenuName; + $isActive = true; + $subActive = true; + $label = $subLabel; + } + + $dropItems[] = array + ( + 'active' => $subActive, + 'data-id' => $dropMenuName, + 'url' => $subLink, + 'text' => $subLabel, + 'data-app' => $dataApp + ); + } + + if(empty($dropItems)) continue; + $items[] = array + ( + 'type' => 'dropdown', + 'items' => $dropItems, + 'class' => $class, + 'active' => $isActive, + 'target' => $target, + 'text' => $label, + 'data-id' => $menuItem->name, + 'data-app' => $dataApp, + 'trigger' => 'hover' + ); + } + else + { + $items[] = array + ( + 'class' => $class, + 'text' => $label, + 'url' => commonModel::createMenuLink($menuItem, $tab), + 'active' => $isActive, + 'target' => $target, + 'data-id' => $menuItem->name, + 'data-app' => $dataApp + ); + } + } + else + { + $items[] = array + ( + 'class' => $class, + 'text' => $menuItem->text, + 'active' => $isActive, + ); + } + } + + /* Set active menu to global data, make it accessible to other widgets */ + useData('activeMenu', $activeMenu); + + return $items; + } + + /** + * Build. + * + * @access protected + * @return object + */ + protected function build() + { + return h::nav + ( + set::id('navbar'), + new nav + ( + set::items($this->getItems()), + $this->children() + ) + ); + } +} diff --git a/zin/wg/page/v1.php b/zin/wg/page/v1.php new file mode 100644 index 0000000000..55134707a7 --- /dev/null +++ b/zin/wg/page/v1.php @@ -0,0 +1,42 @@ + true); + + static $defineBlocks = + [ + 'head' => array(), + 'header' => array('map' => 'header'), + 'main' => array('map' => 'main'), + 'footer' => array(), + ]; + + protected function buildBody() + { + $header = $this->hasBlock('header') ? $this->block('header') : new header(); + + if($this->hasBlock('main')) + { + return array + ( + $header, + $this->block('main'), + $this->children(), + $this->block('footer') + ); + } + + return array + ( + $header, + new main($this->children()), + $this->block('footer'), + ); + } +} diff --git a/zin/wg/pagebase/v1.php b/zin/wg/pagebase/v1.php new file mode 100644 index 0000000000..cbfcbb8630 --- /dev/null +++ b/zin/wg/pagebase/v1.php @@ -0,0 +1,90 @@ + false, + 'display' => true, + 'metas' => array('', '', '', '') + ); + + static $defineBlocks = array('head' => array()); + + protected function created() + { + if($this->prop('display')) $this->display(); + } + + protected function buildHead() + { + return $this->block('head'); + } + + protected function buildBody() + { + return $this->children(); + } + + protected function build() + { + global $lang, $config, $app; + + $zui = $this->prop('zui'); + $head = $this->buildHead(); + $body = $this->buildBody(); + + $context = context::current(); + $css = array_merge([data('pageCSS') ?? ''], $context->getCssList()); + $js = array_merge($context->getJsList(), [data('pageJS') ?? '']); + $imports = $context->getImportList(); + $jsConfig = \js::getJSConfigVars(); + $bodyProps = $this->prop('bodyProps'); + $bodyClass = $this->prop('bodyClass'); + $metas = $this->prop('metas'); + $title = $this->props->get('title', data('title')) . " - $lang->zentaoPMS"; + $attrs = $this->props->skip(array_keys(static::getDefinedProps())); + + $jsConfig->zin = true; + if($config->debug) + { + $js[] = h::createJsVarCode('window.zin', ['page' => $this->toJsonData(), 'definedProps' => wg::$definedPropsMap, 'wgBlockMap' => wg::$wgToBlockMap, 'config' => jsRaw('window.config')]); + $js[] = 'console.log("[ZIN] ", window.zin)'; + } + else + { + $js[] = h::createJsVarCode('window.zin', []); + } + + return h::html + ( + before(html('')), + set($attrs), + h::head + ( + html($metas), + h::title($title), + $this->block('headBefore'), + $zui ? h::importCss($config->zin->zuiPath . 'zui.zentao.css', set::id('zuiCSS')) : null, + $zui ? h::importJs($config->zin->zuiPath . 'zui.zentao.umd.cjs', set::id('zuiJS')) : null, + $zui ? h::importJs($app->getWebRoot() . 'js/zui3/zin.js', set::id('zinJS')) : null, + $head, + ), + h::body + ( + empty($imports) ? NULL : h::import($imports), + h::jsVar('window.config', $jsConfig, set::id('configJS')), + set($bodyProps), + set::class($bodyClass), + empty($css) ? NULL : h::css($css, set::id('pageCSS')), + $body, + empty($js) ? NULL : h::js($js, set::id('pageJS')), + ) + ); + } +} diff --git a/zin/wg/pageheading/v1.php b/zin/wg/pageheading/v1.php new file mode 100644 index 0000000000..3730b449a2 --- /dev/null +++ b/zin/wg/pageheading/v1.php @@ -0,0 +1,50 @@ +props->has('text')) + { + $this->props->set('text', $child); + return false; + } + + return $child; + } + + /** + * Build. + * + * @access protected + * @return object + */ + protected function build() + { + $icon = $this->prop('icon'); + $text = $this->prop('text'); + $url = $this->prop('url'); + + /* Generate button with url. */ + if(!empty($url)) $child = btn($text, set('url', $url), setClass('primary')); + else $child = h::span($text, setClass('text')); + + return h::div + ( + setId('heading'), + setClass('primary'), + icon(set('name', $icon)), + $child + ); + } +} diff --git a/zin/wg/pagenavbar/v1.php b/zin/wg/pagenavbar/v1.php new file mode 100644 index 0000000000..442b99fdf9 --- /dev/null +++ b/zin/wg/pagenavbar/v1.php @@ -0,0 +1,8 @@ +prop('create'); + + if(!isset($props['data-arrow'])) $props['data-arrow'] = true; + if(!isset($props['data-toggle'])) $props['data-toggle'] = 'dropdown'; + if(!isset($props['data-trigger'])) $props['data-trigger'] = 'hover'; + if(!isset($props['href'])) $props['href'] = '#globalCreateMenu'; + + return h::div + ( + setClass('globalCreate'), + h::div + ( + set($props), + setClass('rounded-sm btn square size-sm secondary'), + icon('plus') + ) + ); + } + + private function buildSwitcher() + { + $props = $this->prop('switcher'); + + if(!isset($props['data-arrow'])) $props['data-arrow'] = true; + if(!isset($props['data-toggle'])) $props['data-toggle'] = 'dropdown'; + if(!isset($props['data-trigger'])) $props['data-trigger'] = 'hover'; + if(!isset($props['href'])) $props['href'] = '#globalCreateMenu'; + + return h::div + ( + setClass('vision-switcher'), + h::div + ( + set($props), + setClass('switcher-text'), + $props['text'] + ) + ); + } + + protected function build() + { + return h::div + ( + setId('toolbar'), + $this->buildGlobalCreate(), + $this->block('avatar'), + $this->buildSwitcher() + ); + } +} diff --git a/zin/wg/panel/v1.php b/zin/wg/panel/v1.php new file mode 100644 index 0000000000..2febabb655 --- /dev/null +++ b/zin/wg/panel/v1.php @@ -0,0 +1,101 @@ + array(), + 'headingActions' => array('map' => 'toolbar'), + 'footer' => array('map' => 'nav') + ); + + protected function buildHeadingActions() + { + $actionsBlock = $this->block('headingActions'); + $actions = $this->prop('headingActions'); + + if(empty($actions) && empty($actionsBlock)) return NULL; + + return div + ( + setClass('panel-actions'), + empty($actions) ? NULL : toolbar(set::items($actions)), + $actionsBlock + ); + } + + protected function buildHeading() + { + list($title, $size) = $this->prop(['title', 'size']); + $headingBlock = $this->block('heading'); + $actions = $this->buildHeadingActions(); + + if(empty($title) && empty($headingBlock) && empty($actions)) return NULL; + + return div + ( + setClass('panel-heading', $this->prop('headingClass')), + set($this->prop('headingProps')), + empty($title) ? NULL : div(setClass('panel-title', $this->prop('titleClass', empty($size) ? NULL : "text-$size")), $title, set($this->prop('titleProps'))), + $headingBlock, + $actions + ); + } + + protected function buildBody() + { + return div + ( + setClass('panel-body'), + $this->children() + ); + } + + protected function buildFooter() + { + list($footerActions) = $this->prop(array('footerActions')); + $footerBlock = $this->block('footer'); + + if(empty($footerActions) && empty($footerBlock)) return; + + return div + ( + setClass('panel-footer', $this->prop('footerClass')), + set($this->prop('footerProps')), + $footerBlock, + empty($footerActions) ? NULL : toolbar(set::items($footerActions)) + ); + } + + protected function build() + { + list($class, $size) = $this->prop(['class', 'size']); + return div + ( + setClass('panel', $class, empty($size) ? NULL : "size-$size"), + set($this->getRestProps()), + + $this->buildHeading(), + $this->buildBody(), + $this->buildFooter() + ); + } +} diff --git a/zin/wg/picker/v1.php b/zin/wg/picker/v1.php new file mode 100644 index 0000000000..1b26b3a3a8 --- /dev/null +++ b/zin/wg/picker/v1.php @@ -0,0 +1,8 @@ + a:hover { + background: #EFF5FF; + color: #313C52; +} + +.program-menu .has-nested-menu > .menu.menu-nested { + background-color: #fff; +} + +.program-menu .menu { + padding: 0; +} + +.program-menu .menu-item.active { + color: #2e7fff; +} + +.program-menu { + width: 200px; + max-height: 100%; + display: flex; + flex-direction: column; + flex-shrink: 0; + margin: -5px 0; +} + +.program-menu > header { + height: 40px; + border: 1px solid #2e7fff; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + padding-left: 12px; + flex: none; + border-radius: 2px; +} + +.program-menu > header .icon-close { + cursor: pointer; + padding: 12px; +} + +.program-menu > .menu { + border: 1px solid #E6EAF1; + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + flex: 1 1 auto; + flex-direction: column; + overflow-y: auto; + width: 200px !important; +} + +.program-menu > .menu.show { + display: flex; +} + +.program-menu-subtitle { + padding: 8px 8px 4px 8px; + flex: none; + z-index: 10; + background-color: #fff; + width: 180px; +} + +.program-menu .title-container { + display: flex; + column-gap: 8px; +} + +.program-menu .title-container > span { + font-size: 13px; + line-height: 20px; + font-weight: bold; +} + +.program-menu .icon-container { + width: 20px; + height: 20px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + border: 1px solid #0066fa; +} + +.program-menu .icon-container.down { + background-color: inherit; +} + +.program-menu .icon-container.up { + background-color: #0066fa; +} + +.program-menu [data-toggle="dropdown"] .icon-container.up { + display: none; +} + +.program-menu [data-toggle="dropdown"] .icon-container.down { + display: flex; +} + +.program-menu .with-dropdown-show[data-toggle="dropdown"] .icon-container.down { + display: none; +} + +.program-menu .with-dropdown-show[data-toggle="dropdown"] .icon-container.up { + display: flex; +} diff --git a/zin/wg/programmenu/v1.php b/zin/wg/programmenu/v1.php new file mode 100644 index 0000000000..96f3d1baef --- /dev/null +++ b/zin/wg/programmenu/v1.php @@ -0,0 +1,117 @@ +getChildProgram($parentID); + if(count($children) === 0) return array(); + + foreach($children as $child) + { + $item = array('key' => $child->id, 'text' => $child->name, 'items' => array()); + $items = $this->buildMenuTree($item['items'], $child->id); + if(count($items) !== 0) $item['items'] = $items; + else unset($item['items']); + $parent[] = $item; + } + return $parent; + } + + private function getTitle($activeKey) + { + global $lang; + + if(empty($activeKey)) return $lang->program->all; + + foreach($this->programs as $program) + { + if($program->id == $activeKey) return $program->name; + } + return $lang->program->all; + } + + private function getChildProgram($id) + { + return array_filter($this->programs, function($program) use($id) {return $program->parent == $id;}); + } + + private function setMenuTreeProps() + { + if(!empty($this->prop('programs'))) $this->programs = $this->prop('programs'); + $this->setProp('programs', null); + $items = $this->buildMenuTree(array(), 0); + array_unshift($items, array('type' => 'heading', 'text' => '筛选项目集')); + $this->setProp('items', $items); + $this->setProp('commonItemProps', array('item' => array('className' => 'not-hide-menu'))); + $this->setProp('isDropdownMenu', true); + $this->setProp('_to', "[data-zin-id='$this->gid']"); + $this->setDefaultProps(array('activeClass' => 'active', 'activeIcon' => 'check')); + } + + protected function build() + { + $this->setMenuTreeProps(); + + $activeKey = $this->prop('activeKey'); + $title = $this->getTitle($activeKey); + $closeBtn = null; + + if(!empty($activeKey)) + { + $closeBtn = a + ( + set('href', $this->prop('closeLink')), + h::i + ( + setClass('icon icon-close'), + setStyle('color', '#313C52'), + ) + ); + } + + return div + ( + setClass('program-menu'), + set('data-zin-id', $this->gid), + h::header + ( + set('data-toggle', 'dropdown'), + div + ( + setClass('title-container'), + div + ( + setClass('icon-container down'), + h::i(setClass('gg-chevron-down')), + ), + div + ( + setClass('icon-container up'), + h::i(setClass('gg-chevron-up')), + ), + span($title) + ), + $closeBtn + ), + zui::menutree(inherit($this)) + ); + } +} diff --git a/zin/wg/radio/v1.php b/zin/wg/radio/v1.php new file mode 100644 index 0000000000..12affe7801 --- /dev/null +++ b/zin/wg/radio/v1.php @@ -0,0 +1,12 @@ + 'radio' + ); +} diff --git a/zin/wg/radiolist/v1.php b/zin/wg/radiolist/v1.php new file mode 100644 index 0000000000..2e7f134b4d --- /dev/null +++ b/zin/wg/radiolist/v1.php @@ -0,0 +1,12 @@ + 'radio' + ); +} diff --git a/zin/wg/row/v1.php b/zin/wg/row/v1.php new file mode 100644 index 0000000000..7c6c1a7bf3 --- /dev/null +++ b/zin/wg/row/v1.php @@ -0,0 +1,22 @@ +prop(array('justify', 'align')); + if(!empty($justify)) $classList .= ' justify-' . $justify; + if(!empty($align)) $classList .= ' items-' . $align; + + return div + ( + setClass($classList), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $this->children() + ); + } +} diff --git a/zin/wg/searchform/v1.php b/zin/wg/searchform/v1.php new file mode 100644 index 0000000000..dca4507b59 --- /dev/null +++ b/zin/wg/searchform/v1.php @@ -0,0 +1,10 @@ +
    ').insertAfter('#mainMenu'); + if(!$form.data('loaded')) + { + const url = $.createLink('search', 'buildForm', 'module=' + config.currentModule); + fetch(url).then(response => response.text()).then(html => + { + $form.html(html).data('loaded', true); + zui.bus.emit('searchform.loaded'); + }); + } +}; diff --git a/zin/wg/searchtoggle/v1.php b/zin/wg/searchtoggle/v1.php new file mode 100644 index 0000000000..18351111fa --- /dev/null +++ b/zin/wg/searchtoggle/v1.php @@ -0,0 +1,30 @@ +searchAB), + on::click('window.toggleSearchForm'), + $this->prop('open') ? h::jsCall('~window.toggleSearchForm') : NULL + ); + } +} diff --git a/zin/wg/select/v1.php b/zin/wg/select/v1.php new file mode 100644 index 0000000000..509b6ed4f6 --- /dev/null +++ b/zin/wg/select/v1.php @@ -0,0 +1,83 @@ +props->toJsonData(); + + $text = isset($item['text']) ? $item['text'] : ''; + unset($item['text']); + + if(!isset($item['selected'])) + { + $value = isset($item['value']) ? $item['value'] : ''; + $valueList = $this->getValueList(); + + $item['selected'] = in_array($value, $valueList); + } + + return h::option(set($item), $text); + } + + public function isMultiple() + { + $multiple = $this->prop('multiple'); + if($multiple === NULL) + { + $name = $this->prop('name'); + $multiple = str_contains($name, '['); + } + return $multiple; + } + + public function getValueList() + { + $value = $this->prop('value'); + if($this->isMultiple()) return is_array($value) ? $value : explode(',', $value); + return [$value]; + } + + protected function build() + { + list($items) = $this->prop(['items']); + + if(!empty($items)) + { + $valueList = $this->getValueList(); + foreach($items as $key => $item) + { + if(!is_array($item)) $item = ['text' => $item, 'value' => $key]; + if(!isset($item['selected'])) $item['selected'] = in_array($item['value'], $valueList); + $items[$key] = $this->onBuildItem($item); + } + } + + $props = $this->props->skip(['items', 'value', 'multiple', 'required']); + $required = $this->prop('required'); + if(!$this->hasProp('id') && isset($props['name'])) $props['id'] = $props['name']; + + return h::select + ( + setClass('form-control', $required ? 'is-required' : ''), + set::multiple($this->isMultiple()), + set($props), + $items, + $this->children() + ); + } +} diff --git a/zin/wg/sidebar/css/v1.css b/zin/wg/sidebar/css/v1.css new file mode 100644 index 0000000000..029801fc5a --- /dev/null +++ b/zin/wg/sidebar/css/v1.css @@ -0,0 +1,97 @@ +.sidebar { + flex: none !important; + position: relative; + transition-duration: .15s; + transition-property: width; + transition-timing-function: cubic-bezier(.4, 0, .2, 1); + width: var(--zt-sidebar-width); +} + +.sidebar-toggle { + align-items: center; + border-radius: var(--radius); + bottom: 0; + cursor: pointer; + display: flex; + justify-content: center; + position: absolute; + top: 0; + transition-duration: 1s; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-timing-function: cubic-bezier(.4, 0, .2, 1); + width: 1rem; +} + +.sidebar-toggle > .icon { + align-items: center; + background-color: rgb(var(--color-canvas-rgb)); + border-color: rgb(212, 212, 216); + border-width: 1px; + display: flex; + height: 2rem; + justify-content: center; + width: 0.75rem; +} + +.sidebar-toggle:hover > .icon { + border-color: rgba(var(--color-primary-500-rgb)); + color: rgba(var(--color-primary-500-rgb)); +} + +.sidebar-left > .sidebar-toggle > .icon { + border-bottom-left-radius: var(--radius-lg); + border-top-left-radius: var(--radius-lg); +} + +.sidebar-right > .sidebar-toggle > .icon { + border-top-right-radius: var(--radius-lg); + border-bottom-right-radius: var(--radius-lg); +} + +.sidebar-left > .sidebar-toggle { + right: -1rem; +} + +.sidebar-right > .sidebar-toggle { + left: -1rem; +} + +.sidebar-toggle:hover { + background-color: #3341550d; +} + +.hide-sidebar-left .sidebar-left > *, +.hide-sidebar-right .sidebar-right > * { + display: none; +} + +.hide-sidebar-left .sidebar.sidebar-left, +.hide-sidebar-right .sidebar.sidebar-right { + margin-left: -0.5rem; + margin-right: -0.5rem; + width: 0; +} + +.hide-sidebar-left .sidebar-left > .sidebar-toggle { + display: flex; + right: -0.5rem; +} +.hide-sidebar-right .sidebar-right > .sidebar-toggle { + display: flex; + left: -0.5rem; +} +.hide-sidebar-left .sidebar-left > .sidebar-toggle > .icon { + transform: rotate(180deg); + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; +} + +.hide-sidebar-right .sidebar-right > .sidebar-toggle > .icon { + transform: rotate(180deg); + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; +} diff --git a/zin/wg/sidebar/js/v1.js b/zin/wg/sidebar/js/v1.js new file mode 100644 index 0000000000..b08e5936ad --- /dev/null +++ b/zin/wg/sidebar/js/v1.js @@ -0,0 +1,13 @@ +/** + * @param {{side?: 'left' | 'right', toggle?: boolean, container?: HTMLElement}=} options + */ +function toggleSidebar(options) { + const {side = 'left', toggle, container = document.body} = options || {}; + container.classList.toggle(`hide-sidebar-${side}`, typeof toggle === 'boolean' ? !toggle : undefined); +} + +zui.toggleSidebar = toggleSidebar; + +zui.bus.on('zt_toggleSidebar', (event) => { + toggleSidebar(event.detail); +}); diff --git a/zin/wg/sidebar/v1.php b/zin/wg/sidebar/v1.php new file mode 100644 index 0000000000..667c2a86eb --- /dev/null +++ b/zin/wg/sidebar/v1.php @@ -0,0 +1,34 @@ +prop(array('side', 'showToggle')); + return div + ( + setClass("sidebar sidebar-$side"), + set($this->props->skip(array_keys(static::getDefinedProps()))), + $this->children(), + $showToggle ? div + ( + set::class("sidebar-toggle sidebar-$side-toggle"), + icon("angle-$side"), + on::click("zui.toggleSidebar({side: '$side'})") + ) : NULL + ); + } +} diff --git a/zin/wg/switcher/v1.php b/zin/wg/switcher/v1.php new file mode 100644 index 0000000000..786ec7215c --- /dev/null +++ b/zin/wg/switcher/v1.php @@ -0,0 +1,12 @@ + 'switch switch' + ); +} diff --git a/zin/wg/tabs/v1.php b/zin/wg/tabs/v1.php new file mode 100644 index 0000000000..b0941fbe17 --- /dev/null +++ b/zin/wg/tabs/v1.php @@ -0,0 +1,87 @@ +prop('items'); + $direction = $this->prop('direction'); + $activeId = $this->prop('activeId'); + + if(empty($items)) return null; + + $lables = array(); + $content = array(); + $actived = false; + foreach($items as $item) + { + /* Get ID. */ + $id = isset($item['id']) ? $item['id'] : ''; + if(empty($id)) $id = isset($item['label']) ? $item['label'] : ''; + if(empty($id)) $id = $this->gid; + + $active = isset($item['active']) ? !empty($item['active']) : null; + if($active === null and !empty($activeId) and $activeId == $id) $active = true; + if($active === true) $actived = true; + + $lables[] = h::li + ( + setClass('nav-item'), + $active === true ? setClass('active') : null, + h::a + ( + set('data-toggle', 'tab'), + set('href', '#' . $id), + isset($item['label']) ? $item['label'] : null + ) + ); + + $content[] = h::div + ( + setClass('tab-pane'), + setId($id), + $active === true ? setClass('active') : null, + isset($item['data']) ? $item['data'] : null + ); + } + + /* There is no active item, then set index 0 to be actived. */ + if(!$actived) + { + $l = $lables[0]; + $l->setProp('class', 'active'); + $lables[0] = $l; + + $c = $content[0]; + $c->setProp('class', 'active'); + $content[0] = $c; + } + + return h::div + ( + set($this->props->skip(array_keys(static::getDefinedProps()))), + $direction == 'v' ? setClass('flex') : null, + /* Tabs. */ + h::ul( + setClass('nav nav-tabs'), + $direction == 'v' ? setClass('nav-stacked') : null, + $lables + ), + /* Content. */ + h::div + ( + setClass('tab-content'), + $content + ) + ); + } +} diff --git a/zin/wg/textarea/v1.php b/zin/wg/textarea/v1.php new file mode 100644 index 0000000000..30836ac7e4 --- /dev/null +++ b/zin/wg/textarea/v1.php @@ -0,0 +1,28 @@ + 'form-control', + 'rows' => 10 + ]; + + protected function build() + { + return h::textarea(set($this->props)); + } +} diff --git a/zin/wg/timepicker/v1.php b/zin/wg/timepicker/v1.php new file mode 100644 index 0000000000..d969943e56 --- /dev/null +++ b/zin/wg/timepicker/v1.php @@ -0,0 +1,12 @@ + 'time' + ]; +} diff --git a/zin/wg/toolbar/v1.php b/zin/wg/toolbar/v1.php new file mode 100644 index 0000000000..e9c1008e02 --- /dev/null +++ b/zin/wg/toolbar/v1.php @@ -0,0 +1,42 @@ +prop('type'); + if($type === 'divider') return div(setClass('toolbar-divider')); + if($type === 'btnGroup') return new btnGroup(inherit($item)); + + list($btnClass, $btnProps) = $this->prop(array('btnClass', 'btnProps')); + return new btn + ( + setClass('toolbar-item', $btnClass), + is_array($btnProps) ? set($btnProps) : NULL, + inherit($item) + ); + } + + protected function build() + { + $items = $this->prop('items'); + return div + ( + setClass('toolbar'), + set($this->props->skip(array_keys(static::getDefinedProps()))), + is_array($items) ? array_map(array($this, 'onBuildItem'), $items) : null, + $this->children() + ); + } +} diff --git a/zin/wg/tooltip/v1.php b/zin/wg/tooltip/v1.php new file mode 100644 index 0000000000..42772ff14e --- /dev/null +++ b/zin/wg/tooltip/v1.php @@ -0,0 +1,12 @@ +account)) + { + $this->props->set('user', $child); + return false; + } + return parent::onAddChild($child); + } + + protected function build() + { + list($user, $avatar, $account, $realname) = $this->prop(array('user', 'avatar', 'account', 'realname')); + if(is_array($user)) + { + $avatar = isset($user['avatar']) ? $user['avatar'] : $avatar; + $account = isset($user['account']) ? $user['account'] : $account; + $realname = isset($user['realname']) ? $user['realname'] : $realname; + } + elseif(is_object($user)) + { + $avatar = isset($user->avatar) ? $user->avatar : $avatar; + $account = isset($user->account) ? $user->account : $account; + $realname = isset($user->realname) ? $user->realname : $realname; + } + + return avatar + ( + set::src($avatar), + set::code($account), + set::text(empty($realname) ? $account : $realname), + set($this->props->skip(array('avatar', 'account', 'realname', 'user'))) + ); + } +} diff --git a/zin/zentao/pager.func.php b/zin/zentao/pager.func.php new file mode 100644 index 0000000000..e105304ef3 --- /dev/null +++ b/zin/zentao/pager.func.php @@ -0,0 +1,41 @@ +setParams(); + $params = $pager->params; + foreach($params as $key => $value) + { + if(strtolower($key) == 'recperpage') $params[$key] = '{recPerPage}'; + if(strtolower($key) == 'pageid') $params[$key] = '{page}'; + } + + $setting = new \stdClass(); + $setting->pageID = $pager->pageID; + $setting->recTotal = $pager->recTotal; + $setting->recPerPage = $pager->recPerPage; + $setting->linkCreator = createLink($pager->moduleName, $pager->methodName, $params); + $setting->items = array(); + $setting->btnProps= ['data-load' => 'table']; + + if($pager->recTotal == 0) + { + $setting->items[] = array('type' => 'info', 'text' => $pager->lang->pager->noRecord); + } + else + { + $setting->items[] = array('type' => 'info', 'text' => $pager->lang->pager->totalCountAB); + $setting->items[] = array('type' => 'size-menu', 'text' => str_replace('', '', str_replace('', '', $pager->lang->pager->pageSize)), 'dropdown' => array('placement' => 'top')); + $setting->items[] = array('type' => 'link', 'page' => 'first', 'hint' => $pager->lang->pager->firstPage, 'icon' => 'icon-first-page'); + $setting->items[] = array('type' => 'link', 'page' => 'prev', 'hint' => $pager->lang->pager->previousPage, 'icon' => 'icon-angle-left'); + $setting->items[] = array('type' => 'info', 'text' => '{page}/{pageTotal}'); + $setting->items[] = array('type' => 'link', 'page' => 'next', 'hint' => $pager->lang->pager->nextPage, 'icon' => 'icon-angle-right'); + $setting->items[] = array('type' => 'link', 'page' => 'last', 'hint' => $pager->lang->pager->lastPage, 'icon' => 'icon-last-page'); + } + + return $setting; +} diff --git a/zin/zentao/zentao.func.php b/zin/zentao/zentao.func.php new file mode 100644 index 0000000000..9ef1443a8e --- /dev/null +++ b/zin/zentao/zentao.func.php @@ -0,0 +1,65 @@ +moduleName; + $methodName = $app->methodName; + $required = false; + if(isset($config->$moduleName->$methodName->requiredFields)) $required = in_array($name, explode(',', $config->$moduleName->$methodName->requiredFields)); + + return $required; +} diff --git a/zin/zin.php b/zin/zin.php new file mode 100755 index 0000000000..7ce17dee1d --- /dev/null +++ b/zin/zin.php @@ -0,0 +1,16 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once __DIR__ . DS . 'config.php'; +require_once __DIR__ . DS . 'helper.php'; +require_once __DIR__ . DS . 'func.php'; diff --git a/zin/zui/toggle.class.php b/zin/zui/toggle.class.php new file mode 100644 index 0000000000..91c0b88378 --- /dev/null +++ b/zin/zui/toggle.class.php @@ -0,0 +1,22 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once 'toggle.func.php'; + +class toggle +{ + public static function __callStatic($name, $args) + { + return toggle($name, empty($args) ? NULL : $args[0]); + } +} diff --git a/zin/zui/toggle.func.php b/zin/zui/toggle.func.php new file mode 100644 index 0000000000..e50df31603 --- /dev/null +++ b/zin/zui/toggle.func.php @@ -0,0 +1,24 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ +namespace zin; + +function toggle($name, $options = NULL) +{ + $props = array('data-toggle' => $name); + if (is_array($options)) + { + foreach ($options as $key => $value) + { + $props["data-$key"] = $value; + } + } + return set($props); +} diff --git a/zin/zui/zui.class.php b/zin/zui/zui.class.php new file mode 100644 index 0000000000..6e011219ea --- /dev/null +++ b/zin/zui/zui.class.php @@ -0,0 +1,175 @@ + + * @package zin + * @version $Id + * @link https://www.zentao.net + */ + +namespace zin; + +require_once dirname(__DIR__) . DS . 'core' . DS . 'wg.class.php'; +require_once dirname(__DIR__) . DS . 'core' . DS . 'wg.func.php'; +require_once dirname(__DIR__) . DS . 'core' . DS . 'wg.func.php'; +require_once 'toggle.func.php'; +require_once 'toggle.class.php'; + +class zui extends wg +{ + static $defineProps = '_name:string, _to?:string, _tag:string="div", _toProps?: array'; + + protected function build() + { + list($name, $target, $tagName, $targetProps) = $this->prop(array('_name', '_to', '_tag', '_toProps')); + $selector = empty($target) ? "[data-zin-id='$this->gid']" : $target; + $options = $this->props->skip(array_keys(static::getDefinedProps())); + return array + ( + empty($target) ? h + ( + $tagName, + set($targetProps), + set('data-zin-id', $this->gid) + ) : NULL, + $this->children(), + h::jsCall('~zui.create', $name, $selector, $options) + ); + } + + public static function __callStatic($name, $args) + { + return new zui(set('_name', $name), $args); + } + + public static function toggle($name, $options = NULL) + { + return toggle($name, $options); + } + + public static function setClass($name, ...$args) + { + $class = [$name => true]; + foreach($args as $arg) + { + if(is_bool($arg)) $class[$name] = $arg; + else $class["$name-$arg"] = true; + } + if(isset($class[$name]) && $class[$name] === false) return NULL; + return setClass($class); + } + + public static function skin($name, $flag = true, $falseValue = NULL, $cssProp = NULL) + { + if($flag === NULL) return NULL; + + if(is_array($flag)) + { + return array_map(function($value) use($name, $cssProp) {return zui::skin($name, $value, NULL, $cssProp);}, $flag); + } + + if($flag === false) + { + if(empty($falseValue)) return NULL; + $flag = 'none'; + } + elseif($cssProp !== NULL && is_string($flag) && (str_ends_with($flag, 'px') || str_starts_with($flag, '#') || str_contains($flag, '.') || str_contains($flag, '('))) + { + if(str_starts_with($flag, '(')) $flag = substr($flag, 1, -1); + return setStyle($cssProp, $flag); + } + return setClass($flag === true ? $name : "$name-$flag"); + } + + public static function rounded($value = true) + { + return zui::skin('rounded', $value, 'none', 'border-radius'); + } + + public static function shadow($value = true) + { + return zui::skin('shadow', $value, 'none'); + } + + public static function primary($value = true) + { + return zui::skin('primary', $value); + } + + public static function secondary($value = true) + { + return zui::skin('secondary', $value); + } + + public static function success($value = true) + { + return zui::skin('success', $value); + } + + public static function warning($value = true) + { + return zui::skin('warning', $value); + } + + public static function danger($value = true) + { + return zui::skin('danger', $value); + } + + public static function important($value = true) + { + return zui::skin('important', $value); + } + + public static function special($value = true) + { + return zui::skin('special', $value); + } + + public static function bg($value = NULL) + { + return zui::skin('bg', $value, 'transparent', 'background'); + } + + public static function text($value = NULL) + { + return zui::skin('text', $value, 'fore', 'color'); + } + + public static function muted($value = true) + { + return $value ? setClass('muted') : NULL; + } + + public static function opacity($value) + { + return zui::skin('opacity', $value, '0', 'opacity'); + } + + public static function disabled($value = true) + { + return $value ? setClass('disabled') : NULL; + } + + public static function width($value) + { + return zui::skin('w', $value, '0', 'width'); + } + + public static function height($value) + { + return zui::skin('h', $value, '0', 'width'); + } + + public static function ring(...$args) + { + return zui::skin('ring', $args, '0'); + } + + public static function border(...$args) + { + return zui::skin('border', $args, 'none', 'border'); + } +} diff --git a/zin/zui/zui.func.php b/zin/zui/zui.func.php new file mode 100644 index 0000000000..60ef2c8cc4 --- /dev/null +++ b/zin/zui/zui.func.php @@ -0,0 +1,21 @@ +