| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- <?php
- namespace zin;
- require_once dirname(__DIR__) . DS . 'btn' . DS . 'v1.php';
- require_once dirname(__DIR__) . DS . 'sidebar' . DS . 'v1.php';
- require_once dirname(__DIR__) . DS . 'dropdown' . DS . 'v1.php';
- class moduleMenu extends wg
- {
- /**
- * @var mixed[]
- */
- private static $filterMap = array();
- /**
- * @var mixed[]
- */
- protected static $defineProps = array(
- 'modules: array',
- 'activeKey?: int|string',
- 'settingLink?: string',
- 'settingApp?: string=""',
- 'closeLink: string',
- 'showDisplay?: bool=true',
- 'allText?: string',
- 'title?: string',
- 'titleShow?: bool=true',
- 'app?: string=""',
- 'checkbox?: bool',
- 'preserve?: string|bool',
- 'tree?: array',
- 'checkOnClick?: bool|string',
- 'appendSettingItems?: array',
- 'onCheck?: function',
- 'toggleSidebar?: bool=true',
- 'isInModal?: bool=false',
- 'onClickItem?: function'
- );
- /**
- * @var mixed[]
- */
- protected static $defineBlocks = array
- (
- 'header' => array(),
- 'footer' => array()
- );
- public static function getPageCSS()
- {
- return <<<'CSS'
- .module-menu {max-height: calc(100vh - 79px); display: flex; flex-direction: column; min-height: 32px; --menu-selected-bg: none;}
- .module-menu header a:hover > .icon {color: var(--color-primary-600) !important;}
- .module-menu .tree-item * {white-space: nowrap;}
- .module-menu .tree-item .item-content {color: var(--color-gray-700)}
- .module-menu .tree-item > .selected .item-content {color: var(--color-fore)}
- .module-menu > .tree.has-nested-items {padding-left: calc(2 * var(--space))}
- .has-module-menu-header #mainMenu {padding-left: 180px;}
- .module-menu-header.is-fixed {position: absolute; left: 0; top: -44px; width: 160px; height: 32px; border: 1px solid var(--color-border); justify-content: center; padding: 0 24px; border-right: 0;}
- .module-menu-header.is-fixed::before,
- .module-menu-header.is-fixed::after {content: ''; position: absolute; top: 0; right: -12px; width: 0; height: 0; border-style: solid; border-color: transparent transparent transparent var(--color-border); border-width: 15px 0 15px 12px;}
- .module-menu-header.is-fixed::after {right: -11px; border-color: transparent transparent transparent var(--color-canvas);}
- .has-module-menu-header.is-sidebar-left-collapsed .module-menu-header.is-fixed {left: var(--gutter-width)}
- .module-menu-header.is-fixed .module-title {font-size: var(--font-size-base);}
- .module-menu-header.is-fixed > .btn-close {position: absolute; right: 0; font-weight: normal;}
- .module-menu-header.is-fixed > .btn-close:not(:hover) {opacity: .5;}
- .sidebar > .module-menu-header.is-fixed {display: flex!important;}
- .sidebar-left > .module-menu {margin-right: -8px}
- .sidebar-left.is-expanded > .module-menu ~ .sidebar-gutter {margin-left: 4px}
- .sidebar-right.is-expanded > .module-menu ~ .sidebar-gutter {margin-right: 4px}
- .is-expanded > .module-menu ~ .sidebar-gutter > .gutter-toggle {opacity: 0}
- .has-module-menu-header .sidebar-left {transition-property: width;}
- .has-module-menu-header .module-menu {max-height: calc(100vh - 105px); }
- .has-module-menu-header .module-menu > .tree {padding-top: 8px; padding-bottom: 8px;}
- CSS;
- }
- /**
- * @var mixed[]
- */
- private $modules = array();
- /**
- * @param int|string $parentID
- */
- private function buildMenuTree($parentID = 0)
- {
- $children = zget($this->modules, $parentID, []);
- if(count($children) === 0) return [];
- global $app;
- $activeKey = $this->prop('activeKey');
- $treeItems = array();
- $tab = $this->prop('app') ? $this->prop('app') : $app->tab;
- $titleAttrs = array('data-app' => $tab);
- if(isInModal()) $titleAttrs['data-load'] = 'modal';
- foreach($children as $child)
- {
- $item = array(
- 'key' => $child->id,
- 'text' => $child->name,
- 'hint' => is_array($child->name) ? (isset($child->name['text']) ? $child->name['text'] : current($child->name)) : $child->name,
- 'url' => zget($child, 'url', ''),
- 'titleAttrs' => $titleAttrs,
- 'contentClass' => 'overflow-x-hidden'
- );
- if(!empty($child->actions)) $item['actions'] = $child->actions;
- $items = $this->buildMenuTree($child->id);
- if($items) $item['items'] = $items;
- if((string)$child->id === (string)$activeKey || $child->id === 'product-' . $activeKey)
- {
- $itemKey = $this->prop('checkbox') ? 'checked' : 'selected';
- $item[$itemKey] = true;
- }
- $treeItems[] = $item;
- }
- return $treeItems;
- }
- private function setMenuTreeProps()
- {
- $modules = $this->prop('modules');
- if($modules)
- {
- foreach($modules as $module) $this->modules[$module->parent][] = $module;
- }
- $this->setProp('items', $this->buildMenuTree());
- }
- private function getTitle()
- {
- if($this->prop('title')) return $this->prop('title');
- global $lang, $app;
- $activeKey = $this->prop('activeKey');
- if(empty($activeKey))
- {
- $allText = $this->prop('allText');
- if(empty($allText)) return $lang->all;
- return $allText;
- }
- $modules = $this->prop('modules');
- $moduleName = '';
- if($modules) array_map(function($module) use(&$moduleName, $activeKey) { if($module->id == $activeKey || $module->id == 'product-' . $activeKey) $moduleName = $module->name; }, $modules);
- if(!empty($modules) && empty($moduleName))
- {
- $module = $app->control->loadModel('tree')->getByID($activeKey);
- if($module) $moduleName = $module->name;
- }
- return $moduleName;
- }
- /**
- * @return \zin\node|mixed[]|null
- */
- private function buildActions()
- {
- $settingLink = $this->prop('settingLink');
- $showDisplay = $this->prop('showDisplay');
- $appendSettingItems = $this->prop('appendSettingItems');
- $isInModal = $this->prop('isInModal');
- if(!$settingLink && !$showDisplay && !$appendSettingItems) return null;
- global $app;
- $lang = $app->loadLang('datatable')->datatable;
- $items = array();
- if($settingLink && common::hasPriv('tree', 'browse'))
- {
- $tab = $this->prop('settingApp', $app->tab);
- $settingText = $this->prop('settingText', $lang->moduleSetting);
- if(empty($this->prop('items')))
- {
- $items[] = btn
- (
- setClass('m-4 mt-0'),
- set::text($settingText),
- set::url($settingLink),
- set::type('primary-pale'),
- setData('app', $tab),
- $isInModal ? setData(array('toggle' => 'modal', 'size' => 'md')) : null
- );
- }
- else
- {
- $items[] = array
- (
- 'text' => $settingText,
- 'url' => $settingLink,
- 'data-app' => $tab,
- 'data-toggle' => $isInModal ? 'modal' : '',
- 'data-size' => $isInModal ? 'md' : ''
- );
- }
- }
- if($showDisplay)
- {
- $datatableId = $app->moduleName . ucfirst($app->methodName);
- $currentModule = $app->rawModule;
- $currentMethod = $app->rawMethod;
- if(empty($this->prop('items')))
- {
- $items[] = btn
- (
- setClass('m-4 mt-0'),
- set::text($lang->displaySetting),
- set::url(createLink('datatable', 'ajaxDisplay', "datatableId=$datatableId&moduleName=$app->moduleName&methodName=$app->methodName¤tModule=$currentModule¤tMethod=$currentMethod")),
- set::type('primary-pale'),
- setData(array('toggle' => 'modal', 'size' => 'md'))
- );
- }
- else
- {
- $items[] = array
- (
- 'text' => $lang->displaySetting,
- 'url' => createLink('datatable', 'ajaxDisplay', "datatableId=$datatableId&moduleName=$app->moduleName&methodName=$app->methodName¤tModule=$currentModule¤tMethod=$currentMethod"),
- 'data-toggle' => 'modal',
- 'data-size' => 'md'
- );
- }
- }
- if($appendSettingItems)
- {
- if(empty($this->prop('items')))
- {
- foreach($appendSettingItems as $item)
- {
- $items[] = btn(setClass('m-4 mt-0'), set::type('primary-pale'), set($item));
- }
- }
- else
- {
- $items = array_merge($items, $appendSettingItems);
- }
- }
- if(empty($items)) return null;
- if(empty($this->prop('items'))) return $items;
- return new dropdown
- (
- new btn
- (
- set::type('ghost'),
- set::icon('cog-outline'),
- set::size('sm'),
- set::caret(false)
- ),
- set::items($items),
- set::placement('top-end')
- );
- }
- private function buildCloseBtn()
- {
- $closeLink = $this->prop('closeLink');
- $tab = $this->prop('app');
- $titleAttrs = array();
- if($tab) $titleAttrs['app'] = $tab;
- if(isInModal()) $titleAttrs['load'] = 'modal';
- if(!$closeLink) return null;
- $activeKey = $this->prop('activeKey');
- if(empty($activeKey)) return null;
- return btn
- (
- setClass('btn-close rounded-full'),
- set::icon('close'),
- set::url($closeLink),
- set::size('sm'),
- set::type('ghost'),
- $titleAttrs ? setData($titleAttrs) : null
- );
- }
- protected function build()
- {
- global $app;
- $this->setMenuTreeProps();
- $title = $this->getTitle();
- $userTreeProps = $this->prop('tree');
- $treeProps = $this->props->pick(array('items', 'activeClass', 'activeIcon', 'activeKey', 'onClickItem', 'defaultNestedShow', 'changeActiveKey', 'isDropdownMenu', 'checkbox', 'checkOnClick', 'onCheck'));
- $preserve = $this->prop('preserve', $app->rawModule . '-' . $app->rawMethod);
- $isInSidebar = $this->parent instanceof sidebar;
- $titleShow = $this->prop('titleShow');
- if(!is_null($this->prop('filterMap'))) static::$filterMap = $this->prop('filterMap');
- $header = $titleShow ? h::header
- (
- setClass('module-menu-header h-10 flex items-center pl-4 flex-none gap-3', $isInSidebar ? 'is-fixed rounded rounded-r-none canvas' : ''),
- span
- (
- setClass('module-title text-lg font-semibold clip'),
- $title
- ),
- $this->buildCloseBtn()
- ) : null;
- $actions = $this->buildActions();
- $hasActionDropdown = $actions && $actions instanceof dropdown;
- $hasToggleBtn = $this->prop('toggleSidebar');
- return array
- (
- $isInSidebar ? $header : null,
- div
- (
- setID('moduleMenu'),
- setClass('module-menu shadow ring rounded bg-canvas col relative'),
- $this->block('header'),
- $isInSidebar ? null : $header,
- zui::tree
- (
- set::_tag('menu'),
- set::_class('tree tree-lines col flex-auto scrollbar-hover overflow-y-auto overflow-x-hidden pr-2 pl-4'),
- set::defaultNestedShow(true),
- set::hover(true),
- set::lines(true),
- set::preserve($preserve),
- set::itemActions($this->prop('moduleActions')),
- set($treeProps),
- set($userTreeProps)
- ),
- $hasActionDropdown ? null : $actions,
- $this->block('footer'),
- ($hasActionDropdown || $hasToggleBtn) ? row
- (
- setClass('justify-end p-1 flex-none'),
- $this->prop('createModuleLink') ? btn
- (
- set::type('ghost'),
- set::icon('plus'),
- set::size('sm'),
- set::caret(false),
- set::url($this->prop('createModuleLink')),
- set::hint($this->prop('createModuleHint')),
- setData(array('toggle' => 'modal', 'size' => 'sm'))
- ) : null,
- $hasActionDropdown ? $actions : div(),
- $hasToggleBtn ? btn
- (
- set::type('ghost'),
- set::size('sm'),
- set::icon('menu-arrow-left text-gray'),
- set::hint($app->lang->collapse),
- on::click()->do('$this.closest(".sidebar").sidebar("toggle");')
- ) : null
- ) : null,
- $isInSidebar && !empty($header) ? on::init()->do('$("#mainContainer").addClass("has-module-menu-header")') : null
- ),
- );
- }
- }
|