diff --git a/module/doc/css/common.css b/module/doc/css/common.css index 3db09226aa..71c1b7ffd8 100644 --- a/module/doc/css/common.css +++ b/module/doc/css/common.css @@ -11,6 +11,50 @@ .w-lib-p33{width:31%;} #titlebar > .heading > strong > i{display:inline;} -#modulemenu .nav > li > .dropdown > a#libType{display:inline-block;} -#modulemenu .nav > li > .dropdown.open > a#libType{background:#e5e5e5;} #groups_chosen .chosen-choices {border-right:0px;} + +#dropMenu.loading > #libMenu, +#dropMenu > .icon {display: none} +#dropMenu.loading > .icon {display: block} +#dropMenu {min-width: 600px; transition: min-width .2s;} + +#libMenu {display: block; margin: -10px -15px; position: relative;} +#libMenuHeading {padding: 10px;} +#libMenuGroups {display: table; width: 100%; margin-bottom: 10px;} +.lib-menu-group {display: table-cell; width: 33.333333%; padding: 0 10px} +.lib-menu-group + .lib-menu-group {border-left: 1px dotted #ddd;} +.lib-menu-list-heading {background-color: #fafafa; color: #808080; padding: 0 10px; text-align: center; display: inline-block; margin-bottom: 10px; border: 1px solid #ddd; line-height: 20px; border-radius: 10px;} +.lib-menu-list-heading:hover {border-color: #114f8e; cursor: pointer; color: #114f8e;} +.lib-menu-list-heading > .icon {display: none} +.lib-menu-list {max-height: 500px; overflow-y: auto; min-height: 100px;} +.list-menu-item-heading {padding: 0 10px 0 0; font-weight: bold; color: #a1a1a1; background-color: #fff; border-bottom: 1px dotted #ddd; float: left; width: 100%;} +.list-menu-item-heading > .icon {display: inline-block; width: 20px;} +.list-menu-item + .list-menu-item-heading {border-top: 1px solid #ddd;} +.list-menu-item {padding: 0 10px 0 20px; display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; width: 100%; float: left;} +.list-menu-item.current {background-color: #EBF2F9;} +.list-menu-item.active, +.list-menu-item:hover {background-color: #e5e5e5; color: #1a53ff} +#searchLib {padding: 2px 8px; height: 28px; max-width: 190px;} + +#dropMenu.lib-menu-lg {min-width: 1200px;} +#dropMenu.lib-menu-lg .list-menu-item {width: 50%; float: left;} + +#dropMenu[data-filter="project"] #libMenuProjectGroup, +#dropMenu[data-filter="custom"] #libMenuCustomGroup, +#dropMenu[data-filter="product"] #libMenuProductGroup {display: block; width: 100%} +#dropMenu[data-filter="project"] #libMenuProjectGroup .lib-menu-list-heading, +#dropMenu[data-filter="custom"] #libMenuCustomGroup .lib-menu-list-heading, +#dropMenu[data-filter="product"] #libMenuProductGroup .lib-menu-list-heading {position: absolute; top: 13px; left: 215px; padding-right: 25px; background-color: #114f8e; color: #fff; border-color: #114f8e;} +#dropMenu[data-filter="project"] #libMenuProjectGroup .lib-menu-list-heading > .icon, +#dropMenu[data-filter="custom"] #libMenuCustomGroup .lib-menu-list-heading > .icon, +#dropMenu[data-filter="product"] #libMenuProductGroup .lib-menu-list-heading > .icon {position: absolute; right: 3px; top: 2px; display: block;} +#dropMenu[data-filter="project"] #libMenuProjectGroup .list-menu-item, +#dropMenu[data-filter="custom"] #libMenuCustomGroup .list-menu-item, +#dropMenu[data-filter="product"] #libMenuProductGroup .list-menu-item {width: 33.33333%;} +#dropMenu.lib-menu-lg[data-filter="product"] #libMenuProductGroup .list-menu-item {width: 16.666667%;} +#dropMenu[data-filter="project"] #libMenuProductGroup, +#dropMenu[data-filter="project"] #libMenuCustomGroup, +#dropMenu[data-filter="custom"] #libMenuProjectGroup, +#dropMenu[data-filter="custom"] #libMenuProductGroup, +#dropMenu[data-filter="product"] #libMenuProjectGroup, +#dropMenu[data-filter="product"] #libMenuCustomGroup {display: none;} diff --git a/module/doc/js/common.js b/module/doc/js/common.js index 029c23ea5c..b4b7da4468 100644 --- a/module/doc/js/common.js +++ b/module/doc/js/common.js @@ -1,3 +1,175 @@ +function showLibMenu() +{ + var $item = $('#currentItem'); + var $li = $item.closest('li'); + var $menu = $('#dropMenu'); + + if($li.hasClass('show')) {$li.removeClass('show'); return;} + var isBigMode = false; + if(!$li.data('showagain')) + { + $menu.addClass('loading'); + var $search = $('#searchLib'); + var items = {}; + var itemIdSeed = $.zui.uuid(); + var orderSeed = 1; + $.getJSON(createLink('doc', 'ajaxGetAllLibs'), function(data) + { + $menu.removeClass('loading'); + + var $list = $('#libMenuProductGroup > .lib-menu-list'); + var productCount = 0, projectCount = 0, customCount = 0; + $.each(data.product, function(idx, product) + { + $list.append('
' + product.name + '
'); + $.each(product.libs, function(libId, libName) + { + var url = libId === 'files' ? createLink('doc', 'showFiles', 'type=product&objectID=' + product.id) : createLink('doc', 'browse', 'libID=' + libId); + var itemId = 'lib-' + itemIdSeed++; + $list.append('' + libName + ''); + items[itemId] = {type: 'product', id: libId, name: libName, objectId: product.id, product: product.name, search: (libName + ' ' + product.name).toLowerCase()}; + productCount++; + }); + }); + + $list = $('#libMenuProjectGroup > .lib-menu-list'); + $.each(data.project, function(idx, project) + { + $list.append('
' + project.name + '
'); + $.each(project.libs, function(libId, libName) + { + var url = libId === 'files' ? createLink('doc', 'showFiles', 'type=project&objectID=' + project.id) : createLink('doc', 'browse', 'libID=' + libId); + var itemId = 'lib-' + itemIdSeed++; + $list.append('' + libName + ''); + items[itemId] = {type: 'project', id: libId, name: libName, objectId: project.id, project: project.name, search: (libName + ' ' + project.name).toLowerCase()}; + projectCount++; + }); + }); + + $list = $('#libMenuCustomGroup > .lib-menu-list'); + $.each(data.custom, function(libId, libName) + { + var url = createLink('doc', 'browse', 'libID=' + libId); + var itemId = 'lib-' + itemIdSeed++; + $list.append('' + libName + ''); + items[itemId] = {type: 'custom', id: libId, name: libName, search: libName.toLowerCase()}; + customCount++; + }); + var $items = $menu.find('.list-menu-item'); + $items.filter('[data-id="' + $item.data('libId') + '"]').addClass('current'); + $items.first().addClass('active'); + + isBigMode = productCount > 8 && projectCount > 8 && customCount > 8; + $menu.toggleClass('lib-menu-lg', isBigMode && $(window).width() > 1200); + + var lastSearchKey = $search.val(); + $search.on('change keyup paste input propertychange', function() + { + var searchKey = $search.val(); + if(searchKey == lastSearchKey) return; + lastSearchKey = searchKey; + $menu.find('.list-menu-item.active').removeClass('active'); + if(searchKey) + { + var $menuHeadings = $menu.find('.list-menu-item-heading').addClass('hidden'); + searchKey = searchKey.toLowerCase(); + $.each(items, function(itemId, item) + { + var isMatch = item.search.indexOf(searchKey) > -1 || '@' + item.type === searchKey || item.id === searchKey; + $('#' + itemId).toggleClass('hidden', !isMatch); + if(isMatch && item.type !== 'custom' && item.objectId) + { + $menuHeadings.filter('[data-' + item.type + '="' + item.objectId + '"]').removeClass('hidden'); + } + }); + } + else + { + $menu.find('.list-menu-item.hidden,.list-menu-item-heading.hidden').removeClass('hidden'); + } + $menu.find('.list-menu-item:not(.hidden)').first().addClass('active'); + }).on('keydown', function(e) + { + $items = $menu.find('.list-menu-item'); + + var code = e.which; + var $this = $items.filter('.list-menu-item.active'); + if(code === 38) // up + { + $this.removeClass('active'); + if($this.length) + { + var order = $this.data('order') - 1; + if(order > 0) + { + var $prev = $items.filter('.list-menu-item[data-order="' + order + '"]'); + while($prev.hasClass('hidden') && order > 1) + { + order -= 1; + $prev = $items.filter('.list-menu-item[data-order="' + order + '"]'); + } + if($prev.length) + { + $prev.addClass('active'); + return; + } + } + } + $items.last(':not(.hidden)').addClass('active'); + } + else if(code === 40) // down + { + $this.removeClass('active'); + if($this.length) + { + var order = $this.data('order') + 1; + if(order <= $items.length) + { + var $next = $items.filter('.list-menu-item[data-order="' + order + '"]'); + while($next.hasClass('hidden') && order <= $items.length) + { + order += 1; + $next = $items.filter('.list-menu-item[data-order="' + order + '"]'); + } + if($next.length) + { + $next.addClass('active'); + return; + } + } + } + $items.first(':not(.hidden)').addClass('active'); + } + else if(code === 13) // enter + { + if($this.length) window.location.href = $this.attr('href'); + } + }); + + $menu.on('mouseenter', '.list-menu-item', function() + { + $menu.find('.list-menu-item.active').removeClass('active'); + $(this).addClass('active'); + }); + + $menu.on('click', '.lib-menu-list-heading', function() + { + var libType = $(this).data('type'); + var showFilter = $menu.attr('data-filter') != libType; + $menu.attr('data-filter', showFilter ? libType : ''); + }); + }); + $li.data('showagain', true); + $li.on('click', function(e){e.stopPropagation();}); + $(document).click(function(){$li.removeClass('show');}); + } + $menu.toggleClass('lib-menu-lg', isBigMode && $(window).width() > 1200); + $menu.find('.lib-menu-list').css('max-height', $(window).height() - 210); + $li.addClass('show') +} + +showLibMenu(); + function loadModules(libID) { link = createLink('doc', 'ajaxGetModules', 'libID=' + libID); diff --git a/module/doc/model.php b/module/doc/model.php index 1401b5162f..5f3e9975ac 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -36,17 +36,9 @@ class docModel extends model } } - $selectHtml = "{$libs[$libID]}
"; + $selectHtml = "{$libs[$libID]}
{$this->lang->doc->libTypeList['product']}
{$this->lang->doc->libTypeList['project']}
{$this->lang->doc->libTypeList['custom']}
"; common::setMenuVars($this->lang->doc->menu, 'list', $selectHtml); - - $libTypeSelect = ""; - common::setMenuVars($this->lang->doc->menu, 'type', $libTypeSelect); + common::setMenuVars($this->lang->doc->menu, 'type', ''); } /** @@ -695,11 +687,19 @@ class docModel extends model { if($lib->product) { - $productLibs[$lib->product][$lib->id] = $lib->name; + if(empty($productLibs[$lib->product])) + { + $productLibs[$lib->product] = array('id' => $lib->product, 'libs' => array()); + } + $productLibs[$lib->product]['libs'][$lib->id] = $lib->name; } elseif($lib->project) { - $projectLibs[$lib->project][$lib->id] = $lib->name; + if(empty($projectLibs[$lib->project])) + { + $projectLibs[$lib->project] = array('id' => $lib->project, 'libs' => array()); + } + $projectLibs[$lib->project]['libs'][$lib->id] = $lib->name; } else { @@ -716,20 +716,20 @@ class docModel extends model $hasLibsPriv = common::hasPriv('doc', 'allLibs'); $hasFilesPriv = common::hasPriv('doc', 'showFiles'); - foreach($products as $productID => $productName) + foreach ($productLibs as $productID => $productLib) { - foreach($productLibs[$productID] as $libID => $libName) $productLibs[$productID][$libID] = $productName . ' / ' . $libName; - if(isset($hasProject[$productID]) and $hasLibsPriv) $productLibs[$productID]['project'] = $productName . ' / ' . $this->lang->doc->systemLibs['project']; - if($hasFilesPriv) $productLibs[$productID]['files'] = $productName . ' / ' . $this->lang->doclib->files; + $productLibs[$productID]['name'] = $products[$productID]; + if(isset($hasProject[$productID]) and $hasLibsPriv) $productLibs[$productID]['libs']['project'] = $this->lang->doc->systemLibs['project']; + if($hasFilesPriv) $productLibs[$productID]['libs']['files'] = $this->lang->doclib->files; } $projects = $this->dao->select('id,name')->from(TABLE_PROJECT)->where('id')->in(array_keys($projectLibs))->andWhere('deleted')->eq('0')->orderBy('`order`_desc')->fetchPairs('id', 'name'); - foreach($projects as $projectID => $projectName) + foreach($projectLibs as $projectID => $projectName) { - foreach($projectLibs[$projectID] as $libID => $libName) $projectLibs[$projectID][$libID] = $projectName . ' / ' . $libName; - if($hasFilesPriv) $projectLibs[$projectID]['files'] = $projectName . ' / ' . $this->lang->doclib->files; + $projectLibs[$projectID]['name'] = $projects[$projectID]; + if($hasFilesPriv) $projectLibs[$projectID]['libs']['files'] = $this->lang->doclib->files; } - return array('product' => $productLibs, 'project' => $projectLibs, 'custom' => $customLibs); + return array('product' => array_values($productLibs), 'project' => array_values($projectLibs), 'custom' => $customLibs); } /**