N°2847 - Move dashboard title and menu to the top bar

This commit is contained in:
Eric
2020-10-28 15:43:42 +01:00
parent 776f32dbe1
commit bd606ca3f9
5 changed files with 250 additions and 80 deletions

View File

@@ -17,6 +17,9 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
@@ -529,34 +532,37 @@ EOF
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!array_key_exists('dashboard_div_id', $aExtraParams))
{
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
$oPage->add(<<<HTML
<div class="dashboard-title-line">
<div class="dashboard-title">{$sTitleForHTML}</div>
</div>
HTML
);
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\">{$sTitleForHTML}</div>";
if ($oPage instanceof iTopWebPage) {
$oTopBar = $oPage->GetTopBarLayout();
$oToolbar = new Toolbar();
$oTopBar->SetToolbar($oToolbar);
$oToolbar->AddHtml($sHtml);
} else {
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML");
JS
);
}
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
foreach($this->aCells as $iCellIdx => $aDashlets)
{
foreach($aDashlets as $oDashlet)
{
foreach ($this->aCells as $iCellIdx => $aDashlets) {
foreach ($aDashlets as $oDashlet) {
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
}
}
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
if (!$bEditMode) {
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
@@ -987,39 +993,38 @@ EOF
}
/**
* @param \iTopWebPage $oPage
* @param WebPage $oPage
* @param array $aAjaxParams
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function RenderSelector($oPage, $aAjaxParams = array())
protected function RenderSelector(WebPage $oPage, $aAjaxParams = array())
{
$sId = $this->GetId();
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
$sExtraParams = json_encode($aAjaxParams);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$sSelectorHtml = '<div class="ibo-top-bar--toolbar-dashboard-selector">';
if ($this->HasCustomDashboard()) {
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
if ($oPage instanceof iTopWebPage) {
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
$oPage->add_script(
<<<EOF
$oPage->add_script(
<<<EOF
function ToggleDashboardSelector$sDivId()
{
$('.ibo-dashboard#$sDivId').block();
@@ -1032,7 +1037,14 @@ EOF
);
}
EOF
);
);
} else {
$sSelectorHtml = addslashes($sSelectorHtml);
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-selector").replaceWith("$sSelectorHtml");
JS
);
}
}
/**
@@ -1064,43 +1076,67 @@ EOF
*/
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
if (!($oPage instanceof iTopWebPage)) {
return;
}
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
$sName = 'UI:Dashboard:Actions';
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oActionButton = ButtonFactory::MakeLinkNeutral('', '', 'fas fa-ellipsis-v', $sName, '', $sMenuTogglerId);
$oActionButton->AddCSSClasses("ibo-top-bar--toolbar-dashboard-menu-toggler");
$oToolbar->AddSubBlock($oActionButton);
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
if ($this->HasCustomDashboard()) {
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
if ($bCanEdit) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized)
{
if ($this->bCustomized) {
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
$oToolbar->AddSubBlock($oPage->GetPopoverMenu($sPopoverMenuId, $aActions));
$oActionButton->AddCSSClasses('ibo-action-button')
->SetJsCode(<<<JS
$("#{$sPopoverMenuId}").popover_menu({toggler: "#{$sMenuTogglerId}"});
$('#{$sMenuTogglerId}').on('click', function(oEvent) {
var oEventTarget = $('#{$sMenuTogglerId}');
var aEventTargetPos = oEventTarget.position();
var popover = $("#{$sPopoverMenuId}");
EOF
);
popover.css({
// 'top': (aEventTargetPos.top + parseInt(oEventTarget.css('marginTop'), 10) + oEventTarget.height()) + 'px',
// 'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width() - popover.width()) + 'px',
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
'z-index': 10060
});
popover.popover_menu("togglePopup");
});
JS
);
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
<<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
@@ -1584,12 +1620,10 @@ JS
{
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
$aClassAliases = array();
try{
try {
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
$aClassAliases = $oFilter->GetSelectedClasses();
}
catch (Exception $e)
{
} catch (Exception $e) {
//on error, return default value
return null;
}

View File

@@ -44,16 +44,106 @@ $ibo-top-bar--quick-actions--margin-right: $ibo-top-bar--elements-spacing !defau
background-color: var(--ibo-top-bar--background-color);
@extend %ibo-elevation-100;
.ibo-breadcrumbs{
.ibo-breadcrumbs {
flex-grow: 1; /* Occupy as much width as possible */
overflow-x: hidden; /* Avoid glitches when too many items */
}
}
.ibo-top-bar--quick-actions{
.ibo-top-bar--quick-actions {
@extend %ibo-full-height-content;
margin-right: var(--ibo-top-bar--quick-actions--margin-right);
.ibo-global-search{
.ibo-global-search {
}
}
}
.ibo-top-bar--toolbar {
@extend %ibo-full-height-content;
}
.ibo-top-bar--toolbar-dashboard-title {
@extend %ibo-full-height-content;
@extend %ibo-font-ral-med-250;
display: flex;
align-items: center;
}
.ibo-top-bar--toolbar-dashboard-menu-toggler {
@extend %ibo-full-height-content;
display: flex;
align-items: center;
}
.ibo-top-bar--toolbar-dashboard-selector {
@extend %ibo-full-height-content;
display: flex;
align-items: center;
.selector-label {
display: inline-block;
margin-left: 10px;
margin-right: 10px;
vertical-align: super;
}
}
// Round Toggle
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 36px;
height: 20px;
vertical-align: baseline;
}
/* Hide default HTML checkbox */
.switch input {
display: none;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: $ibo-color-secondary-600;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 15px;
width: 15px;
left: 3px;
bottom: 3px;
background-color: $ibo-color-secondary-300;
transition: .4s;
}
input:checked + .slider {
background-color: $ibo-color-primary-600;
}
input:focus + .slider {
box-shadow: 0 0 1px $ibo-color-primary-600;
}
input:checked + .slider:before {
transform: translateX(14.5px);
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 7px;
}

View File

@@ -23,6 +23,7 @@ namespace Combodo\iTop\Application\UI\Layout\TopBar;
use Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs;
use Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch;
use Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate;
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
use Combodo\iTop\Application\UI\UIBlock;
/**
@@ -45,6 +46,8 @@ class TopBar extends UIBlock
protected $oGlobalSearch;
/** @var Breadcrumbs|null $oBreadcrumbs */
protected $oBreadcrumbs;
/** @var Toolbar|null */
protected $oToolbar;
/**
* TopBar constructor.
@@ -163,6 +166,35 @@ class TopBar extends UIBlock
return ($this->oBreadcrumbs !== null);
}
/**
* @return Toolbar|null
*/
public function GetToolbar(): ?Toolbar
{
return $this->oToolbar;
}
/**
* @param Toolbar|null $oToolbar
*
* @return TopBar
*/
public function SetToolbar(?Toolbar $oToolbar): TopBar
{
$this->oToolbar = $oToolbar;
return $this;
}
/**
* Return true if the breadcrumb has been set
*
* @return bool
*/
public function HasToolbar()
{
return ($this->oToolbar !== null);
}
/**
* @inheritDoc
*/
@@ -170,12 +202,10 @@ class TopBar extends UIBlock
{
$aSubBlocks = [];
$aSubBlocksNames = ['QuickCreate', 'GlobalSearch', 'Breadcrumbs'];
foreach($aSubBlocksNames as $sSubBlockName)
{
$aSubBlocksNames = ['QuickCreate', 'GlobalSearch', 'Breadcrumbs', 'Toolbar'];
foreach ($aSubBlocksNames as $sSubBlockName) {
$sHasMethodName = 'Has'.$sSubBlockName;
if(true === call_user_func_array([$this, $sHasMethodName], []))
{
if (true === call_user_func_array([$this, $sHasMethodName], [])) {
$sPropertyName = 'o'.$sSubBlockName;
$aSubBlocks[$this->$sPropertyName->GetId()] = $this->$sPropertyName;
}

View File

@@ -19,12 +19,14 @@
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
use Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs;
use Combodo\iTop\Application\UI\Component\Panel\PanelFactory;
use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Application\UI\Layout\iUIContentBlock;
use Combodo\iTop\Application\UI\Layout\NavigationMenu\NavigationMenuFactory;
use Combodo\iTop\Application\UI\Layout\PageContent\PageContent;
use Combodo\iTop\Application\UI\Layout\PageContent\PageContentFactory;
use Combodo\iTop\Application\UI\Layout\TopBar\TopBar;
use Combodo\iTop\Application\UI\Layout\TopBar\TopBarFactory;
use Combodo\iTop\Application\UI\UIBlock;
use Combodo\iTop\Renderer\BlockRenderer;
@@ -49,6 +51,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
/** @var \TabManager */
protected $m_oTabs;
protected $oTopBarLayout;
protected $bBreadCrumbEnabled;
protected $sBreadCrumbEntryId;
protected $sBreadCrumbEntryLabel;
@@ -78,16 +81,15 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
if ((count($_POST) == 0) || (array_key_exists('loginop', $_POST)))
{
if ((count($_POST) == 0) || (array_key_exists('loginop', $_POST))) {
// Create a breadcrumb entry for the current page, but get its title as late as possible (page title could be changed later)
$this->bBreadCrumbEnabled = true;
}
else
{
} else {
$this->bBreadCrumbEnabled = false;
}
$this->SetTopBarLayout(TopBarFactory::MakeStandard($this->GetBreadCrumbsNewEntry()));
utils::InitArchiveMode();
$this->m_aMessages = array();
@@ -535,6 +537,8 @@ JS
$this->sBreadCrumbEntryUrl = $sUrl;
$this->sBreadCrumbEntryIcon = $sIcon;
$this->sBreadCrumbEntryIconType = $sIconType;
$this->GetTopBarLayout()->SetBreadcrumbs(new Breadcrumbs($this->GetBreadCrumbsNewEntry(), Breadcrumbs::BLOCK_CODE));
}
/**
@@ -632,20 +636,6 @@ JS
return NavigationMenuFactory::MakeStandard();
}
/**
* Return the top bar layout (global search, breadcrumbs, ...)
*
* @internal
* @return \Combodo\iTop\Application\UI\Layout\TopBar\TopBar
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @since 3.0.0
*/
protected function GetTopBarLayout()
{
return TopBarFactory::MakeStandard($this->GetBreadCrumbsNewEntry());
}
/**
* Set the content layout (main content, [side content,] manually added content, ...)
* This function is public as the developer needs to be able to set how the content will be displayed.
@@ -1393,4 +1383,25 @@ EOF
$this->m_aInitScript[] = $sScript;
}
}
/**
* @return TopBar
*/
public function GetTopBarLayout(): TopBar
{
return $this->oTopBarLayout;
}
/**
* @param TopBar $oTopBarLayout
*
* @return iTopWebPage
*/
public function SetTopBarLayout(TopBar $oTopBarLayout): iTopWebPage
{
$this->oTopBarLayout = $oTopBarLayout;
return $this;
}
}

View File

@@ -10,4 +10,9 @@
{% if oUIBlock.HasBreadcrumbs() %}
{{ render_block(oUIBlock.GetBreadcrumbs(), {aPage: aPage}) }}
{% endif %}
{% if oUIBlock.HasToolBar() %}
<div class="ibo-top-bar--toolbar">
{{ render_block(oUIBlock.GetToolBar(), {aPage: aPage}) }}
</div>
{% endif %}
</nav>