N°2847 - Rework of the global iTopWebPage layout (Part II)

- Optimize TWIG templates includes (don't pass context to autonomous components)
- Preliminary work of the top bar and breadcrumbs features
- Removal of images dedicated to the breadcrumbs feature
This commit is contained in:
Molkobain
2020-07-17 17:01:29 +02:00
parent 6f9565d979
commit 8efd8008fc
34 changed files with 8309 additions and 201 deletions

View File

@@ -696,7 +696,8 @@ class DisplayBlock
'breadcrumb_label' => MetaModel::GetName($this->m_oSet->GetClass()),
'breadcrumb_max_count' => utils::GetConfig()->Get('breadcrumb.max_count'),
'breadcrumb_instance_id' => MetaModel::GetConfig()->GetItopInstanceid(),
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png',
'breadcrumb_icon' => 'fas fa-search',
'breadcrumb_icon_type' => iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES,
));
$oPage->add_ready_script("$('body').trigger('update_history.itop', [$seventAttachedData])");

View File

@@ -35,6 +35,13 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
/** @var string DEFAULT_APP_ICON_SHAPE */
const DEFAULT_APP_ICON_SHAPE = self::ENUM_APP_ICON_SHAPE_FULL;
/** @var string ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE */
const ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE = 'image';
/** @var string ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES */
const ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES = 'css_classes';
/** @var string DEFAULT_BREADCRUMB_ENTRY_ICON_TYPE */
const DEFAULT_BREADCRUMB_ENTRY_ICON_TYPE = self::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE;
/** @var array Default and branding filenames for the app. icon in the backoffice */
protected static $aAppIconFilenames = [
self::ENUM_APP_ICON_SHAPE_SQUARE => [
@@ -58,6 +65,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
protected $sBreadCrumbEntryDescription;
protected $sBreadCrumbEntryUrl;
protected $sBreadCrumbEntryIcon;
protected $sBreadCrumbEntryIconType;
protected $oCtx;
/**
@@ -126,7 +134,6 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
$this->add_linked_script('js/ajaxfileupload.js');
$this->add_linked_script('js/jquery.mousewheel.js');
$this->add_linked_script('js/jquery.magnific-popup.min.js');
$this->add_linked_script('js/breadcrumb.js');
$this->add_linked_script('js/moment-with-locales.min.js');
$this->add_linked_script('js/showdown.min.js');
$this->add_linked_script('js/newsroom_menu.js');
@@ -715,9 +722,12 @@ JS
* @param string $sLabel Label of the breadcrumb item
* @param string $sDescription More information, displayed as a tooltip
* @param string $sUrl Specify a URL if the current URL as perceived on the browser side is not relevant
* @param string $sIcon Icon (relative or absolute) path that will be displayed next to the label
* @param string $sIcon Image URL (relative or absolute) or CSS classes (eg. "fas fa-wrench") of the icon that will be displayed next to the label
* @param string $sIconType Type of the icon, must be set according to the $sIcon value. See class constants ENUM_BREADCRUMB_ENTRY_ICON_TYPE_XXX
*
* @see static::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE, static::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES
*/
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '')
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '', $sIconType = self::DEFAULT_BREADCRUMB_ENTRY_ICON_TYPE)
{
$this->bBreadCrumbEnabled = true;
$this->sBreadCrumbEntryId = $sId;
@@ -725,6 +735,7 @@ JS
$this->sBreadCrumbEntryDescription = $sDescription;
$this->sBreadCrumbEntryUrl = $sUrl;
$this->sBreadCrumbEntryIcon = $sIcon;
$this->sBreadCrumbEntryIconType = $sIconType;
}
/**
@@ -822,7 +833,7 @@ JS
* @return string
* @since 2.8.0
*/
public function GetApplicationRevisionNumber()
protected function GetApplicationRevisionNumber()
{
if (ITOP_REVISION == 'svn')
{
@@ -849,7 +860,7 @@ JS
* @throws \Exception
* @since 2.8.0
*/
public function GetApplicationIconUrl($sShape = self::DEFAULT_APP_ICON_SHAPE)
protected function GetApplicationIconUrl($sShape = self::DEFAULT_APP_ICON_SHAPE)
{
$sIconDefaultFilename = static::$aAppIconFilenames[$sShape]['default'];
$sIconBrandingFilename = static::$aAppIconFilenames[$sShape]['branding'];
@@ -874,7 +885,7 @@ JS
* @throws \DictExceptionMissingString
* @since 2.8.0
*/
public function GetNavigationMenuData()
protected function GetNavigationMenuData()
{
$oAppContext = new ApplicationContext();
@@ -888,6 +899,83 @@ JS
];
}
/**
* Return the top bar data (global search, breadcrumbs, ...)
*
* @return array
* @throws \ConfigException
* @throws \CoreException
* @since 2.8.0
*/
protected function GetTopBarData()
{
$aData = [
'sId' => 'ibo-top-bar',
'aComponents' => [
'aBreadCrumbs' => $this->GetBreadCrumbsData(),
],
];
return $aData;
}
/**
* Return the breadcrumbs data (iTop instance ID, new entry, ...)
*
* @return array
* @throws \ConfigException
* @throws \CoreException
* @since 2.8.0
*/
protected function GetBreadCrumbsData()
{
$aData = [
'sId' => 'ibo-breadcrumbs',
];
$iBreadCrumbMaxCount = utils::GetConfig()->Get('breadcrumb.max_count');
if ($iBreadCrumbMaxCount > 1)
{
$oConfig = MetaModel::GetConfig();
$siTopInstanceId = $oConfig->GetItopInstanceid();
if ($this->bBreadCrumbEnabled)
{
// Default entry values
if (is_null($this->sBreadCrumbEntryId))
{
$this->sBreadCrumbEntryId = $this->s_title;
$this->sBreadCrumbEntryLabel = $this->s_title;
$this->sBreadCrumbEntryDescription = $this->s_title;
$this->sBreadCrumbEntryUrl = '';
$this->sBreadCrumbEntryIcon = 'fas fa-wrench';
$this->sBreadCrumbEntryIconType = static::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES;
}
$aNewEntry = array(
'id' => $this->sBreadCrumbEntryId,
'url' => $this->sBreadCrumbEntryUrl,
'label' => utils::HtmlEntities($this->sBreadCrumbEntryLabel),
'description' => utils::HtmlEntities($this->sBreadCrumbEntryDescription),
'icon' => $this->sBreadCrumbEntryIcon,
'icon_type' => $this->sBreadCrumbEntryIconType,
);
}
else
{
$aNewEntry = null;
}
$aData['aWidgetOptions'] = [
'itop_instance_id' => $siTopInstanceId,
'max_count' => $iBreadCrumbMaxCount,
'new_entry' => $aNewEntry,
];
}
return $aData;
}
/**
* Handles the "newsroom" menu at the top-right of the screen
*/
@@ -1060,6 +1148,9 @@ EOF
// - Navigation menu
$aData['aLayouts']['aNavigationMenu'] = $this->GetNavigationMenuData();
// - Top bar
$aData['aLayouts']['aTopBar'] = $this->GetTopBarData();
$oTwigEnv = TwigHelper::GetTwigEnvironment(APPROOT.'templates/');
$sTemplateRelPath = 'pages/backoffice/layout';

View File

@@ -1031,7 +1031,7 @@ class OQLMenuNode extends MenuNode
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oSearch->GetClass();
$sLabel = MetaModel::GetName($oSearch->GetClass());
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
}
}
@@ -1078,7 +1078,7 @@ class SearchMenuNode extends MenuNode
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oSearch = new DBObjectSearch($this->sClass);
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
@@ -1315,13 +1315,13 @@ class DashboardMenuNode extends MenuNode
}
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
{
$sIcon = '../images/breadcrumb_home.png';
$sIcon = 'fas fa-home';
}
else
{
$sIcon = '../images/breadcrumb-dashboard.png';
$sIcon = 'fas fa-chart-pie';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
}
else

View File

@@ -16,3 +16,4 @@
* You should have received a copy of the GNU Affero General Public License
*/
@import "breadcrumbs";

View File

@@ -0,0 +1,74 @@
/*!
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
$ibo-breadcrumbs--item--text-color: $ibo-color-grey-800 !default;
$ibo-breadcrumbs--item-icon--margin-x: 8px !default;
$ibo-breadcrumbs--item-icon--max-width: 16px !default;
$ibo-breadcrumbs--item-icon--text-color: $ibo-color-grey-600 !default;
$ibo-breadcrumbs--item-separator--margin-x: 12px !default;
$ibo-breadcrumbs--item-separator--text-color: $ibo-color-grey-500 !default;
.ibo-breadcrumbs{
display: flex;
align-items: center;
* {
display: flex;
align-items: center;
}
}
.ibo-breadcrumbs--item{
color: $ibo-breadcrumbs--item--text-color;
@extend %ibo-font-ral-nor-100;
&:not(:last-child){
&::after{
content: '\f054';
margin: 0 $ibo-breadcrumbs--item-separator--margin-x;
color: $ibo-breadcrumbs--item-separator--text-color;
@extend %fa-solid-base;
}
&:hover{
.ibo-breadcrumbs--item-icon{
> *{
opacity: 1;
filter: none;
}
}
}
}
}
.ibo-breadcrumbs--item-icon{
margin-right: $ibo-breadcrumbs--item-icon--margin-x;
@extend %ibo-font-ral-nor-150;
transition: all 0.1s linear;
> span{
color: $ibo-breadcrumbs--item-icon--text-color;
opacity: 0.6;
}
> img{
height: auto;
max-width: $ibo-breadcrumbs--item-icon--max-width;
opacity: 0.3;
filter: grayscale(100%);
}
}

View File

@@ -17,13 +17,15 @@
*/
/* SCSS variables (can be overloaded) */
$ibo-top-bar-height: 54px !default;
$ibo-top-bar-padding-left: 16px !default; /* Should be align with the page content padding-left */
$ibo-top-bar-padding-right: 16px !default;
$ibo-top-bar-padding-y: 16px !default;
$ibo-top-bar-padding-y: 0px !default;
$ibo-top-bar-background-color: $ibo-color-white-100 !default;
/* CSS variables (can be changed directly from the browser) */
:root{
--ibo-top-bar-height: #{$ibo-top-bar-height};
--ibo-top-bar-padding-left: #{$ibo-top-bar-padding-left};
--ibo-top-bar-padding-right: #{$ibo-top-bar-padding-right};
--ibo-top-bar-padding-y: #{$ibo-top-bar-padding-y};
@@ -32,6 +34,11 @@ $ibo-top-bar-background-color: $ibo-color-white-100 !default;
.ibo-top-bar{
display: flex;
align-items: center;
height: var(--ibo-top-bar-height);
padding: var(--ibo-top-bar-padding-y) var(--ibo-top-bar-padding-right) var(--ibo-top-bar-padding-y) var(--ibo-top-bar-padding-left);
background-color: var(--ibo-top-bar-background-color);
.ibo-breadcrumbs{
flex-grow: 1; /* Occupy as much width as possible */
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,4 +18,5 @@
@import "typography";
@import "elevation";
@import "misc";
@import "misc";
@import "font-icon";

View File

@@ -0,0 +1,56 @@
/*!
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
/******************************************************************************************************************************/
/* NOTE: Those helpers allow to easily use an icon from libs. like FontAwesome or FontCombodo within a CSS rule (eg. ::after) */
/* To use it, simply "@extend %fa-regular-base" in a rule and put the desired icon "content: '\f054'" */
/******************************************************************************************************************************/
%fa-regular-base{
font-family: "Font Awesome 5 Free";
font-weight: 400;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
line-height: 1;
}
%fa-solid-base{
font-family: "Font Awesome 5 Free";
font-weight: 900;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
line-height: 1;
}
%fc-regular-base{
display: inline-block;
font-family: CombodoRegular;
font-style: normal;
font-variant: normal;
font-weight: normal;
text-rendering: auto;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@@ -30,7 +30,7 @@ LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be
$oAppContext = new ApplicationContext();
$oPage = new iTopWebPage(Dict::S('iTopHub:InstalledExtensions'));
$oPage->SetBreadCrumbEntry('ui-hub-myextensions', Dict::S('Menu:iTopHub:MyExtensions'), Dict::S('Menu:iTopHub:MyExtensions+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oPage->SetBreadCrumbEntry('ui-hub-myextensions', Dict::S('Menu:iTopHub:MyExtensions'), Dict::S('Menu:iTopHub:MyExtensions+'), '', 'fas fa-puzzle-piece', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
function DisplayExtensionInfo(Webpage $oPage, iTopExtension $oExtension)
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

View File

@@ -1,10 +1,27 @@
//iTop Form field
/*
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
;
$(function()
{
// the widget definition, where 'itop' is the namespace,
// 'breadcrumb' the widget name
$.widget( 'itop.breadcrumb',
// 'breadcrumbs' the widget name
$.widget( 'itop.breadcrumbs',
{
// default options
options:
@@ -19,17 +36,17 @@ $(function()
{
var me = this;
this.element
.addClass('breadcrumb');
this.element.addClass('ibo-breadcrumbs');
if(typeof(Storage) !== "undefined")
// Check that storage API is available
if(typeof(Storage) !== 'undefined')
{
$(window).bind( 'hashchange', function(e)
$(window).bind('hashchange', function(e)
{
me.RefreshLatestEntry();
});
aBreadCrumb = this._Read();
aBreadCrumb = this._readDataFromStorage();
if (this.options.new_entry !== null) {
var sUrl = this.options.new_entry.url;
@@ -46,72 +63,57 @@ $(function()
label: this.options.new_entry.label,
description: this.options.new_entry.description,
icon: this.options.new_entry.icon,
icon_type: this.options.new_entry.icon_type,
url: sUrl
});
// Keep only the last <max_count> items
aBreadCrumb = aBreadCrumb.slice(-(this.options.max_count));
}
this._Write(aBreadCrumb);
var sBreadCrumbHtml = '';
this._writeDataToStorage(aBreadCrumb);
for (iEntry in aBreadCrumb)
{
//if (iEntry >= iDisplayableItems) break; // skip the current page
var sBreadcrumbsItemHtml = '';
var oEntry = aBreadCrumb[iEntry];
if (oEntry['label'].length > 0)
{
var sIconSpec = '';
if (oEntry['icon'].length > 0)
if (oEntry['icon_type'] === 'css_classes')
{
sIconSpec = '<span class="icon"><img src="'+oEntry['icon']+'"/></span>';
sIconSpec = '<span class="ibo-breadcrumbs--item-icon"><span class="'+oEntry['icon']+'"/></span></span>';
}
else if (oEntry['icon'].length > 0)
{
sIconSpec = '<span class="ibo-breadcrumbs--item-icon"><img src="'+oEntry['icon']+'"/></span>';
}
var sTitle = oEntry['description'];
if (sTitle.length == 0) {
sTitle = oEntry['label'];
}
if ((this.options.new_entry !== null) && (iEntry == aBreadCrumb.length - 1))
{
// Last entry is the current page
sBreadCrumbHtml += '<div class="breadcrumb-item breadcrumb-current" breadcrumb-entry="'+iEntry+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+oEntry['label']+'</span></div>';
sBreadcrumbsItemHtml += '<span class="ibo-breadcrumbs--item--is-current" data-breadcrumb-entry-number="'+iEntry+'" title="'+sTitle+'">'+sIconSpec+'<span class="ibo-breadcrumbs--item-label">'+oEntry['label']+'</span></span>';
}
else
{
var sSanitizedUrl = StripArchiveArgument(oEntry['url']);
sBreadCrumbHtml += '<div class="breadcrumb-item"><a class="breadcrumb-link" breadcrumb-entry="'+iEntry+'" href="'+sSanitizedUrl+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+oEntry['label']+'</span></a></div>';
sBreadcrumbsItemHtml += '<a class="ibo-breadcrumbs--item" data-breadcrumb-entry-number="'+iEntry+'" href="'+sSanitizedUrl+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+oEntry['label']+'</span></a>';
}
}
this.element.append(sBreadcrumbsItemHtml);
}
$('#itop-breadcrumb').html(sBreadCrumbHtml);
}
else
{
// Sorry! No Web Storage support..
//$('#itop-breadcrumb').html('<span style="display:none;">Session storage not available for the current browser</span>');
}
},
// called when created, and later when changing options
_refresh: function()
{
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element
.removeClass('breadcrumb');
this.element.removeClass('ibo-breadcrumbs');
},
// _setOptions is called with a hash of all options that are changing
// always refresh when changing options
_setOptions: function()
{
this._superApply(arguments);
},
// _setOption is called for each individual option that is changing
_setOption: function( key, value )
{
this._super( key, value );
},
_Read: function()
_readDataFromStorage: function()
{
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
var aBreadCrumb = [];
@@ -122,7 +124,7 @@ $(function()
}
return aBreadCrumb;
},
_Write: function(aBreadCrumb)
_writeDataToStorage: function(aBreadCrumb)
{
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
sBreadCrumbData = JSON.stringify(aBreadCrumb);
@@ -131,11 +133,11 @@ $(function()
// Refresh the latest entry (navigating to a tab)
RefreshLatestEntry: function(sRefreshHrefTo)
{
aBreadCrumb = this._Read();
var aBreadCrumb = this._readDataFromStorage();
var iDisplayableItems = aBreadCrumb.length;
if (this.options.new_entry !== null) {
if (sRefreshHrefTo == undefined)
if (sRefreshHrefTo === undefined)
{
sRefreshHrefTo = window.location.href;
}
@@ -144,8 +146,7 @@ $(function()
aBreadCrumb[aBreadCrumb.length - 1].url = sRefreshHrefTo;
$('#itop-breadcrumb .breadcrumb-current:last-of-type a').attr('href', sRefreshHrefTo);
}
this._Write(aBreadCrumb);
this._writeDataToStorage(aBreadCrumb);
},
});
});

View File

@@ -202,7 +202,7 @@ $(function()
}
$('#itop-breadcrumb')
$('#ibo-breadcrumbs')
.breadcrumb('destroy')
.breadcrumb({
itop_instance_id: oData['breadcrumb_instance_id'],
@@ -212,6 +212,7 @@ $(function()
"label": oData['breadcrumb_label'],
"url": sNewUrl,
'icon': oData['breadcrumb_icon'],
'icon_type': oData['breadcrumb_icon_type'],
'description': ''
}
});

View File

@@ -190,11 +190,13 @@ function SetObjectBreadCrumbEntry(DBObject $oObj, WebPage $oPage)
{
$sClass = get_class($oObj); // get the leaf class
$sIcon = MetaModel::GetClassIcon($sClass, false);
$sIconType = iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE;
if ($sIcon == '')
{
$sIcon = utils::GetAbsoluteUrlAppRoot().'images/breadcrumb_object.png';
$sIcon = 'fas fa-cube';
$sIconType = iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES;
}
$oPage->SetBreadCrumbEntry("ui-details-$sClass-".$oObj->GetKey(), $oObj->Get('friendlyname'), MetaModel::GetName($sClass).': '.$oObj->Get('friendlyname'), '', $sIcon);
$oPage->SetBreadCrumbEntry("ui-details-$sClass-".$oObj->GetKey(), $oObj->Get('friendlyname'), MetaModel::GetName($sClass).': '.$oObj->Get('friendlyname'), '', $sIcon, $sIconType);
}
/**
@@ -239,7 +241,7 @@ function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '',
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oFilter->GetClass();
$sLabel = MetaModel::GetName($oFilter->GetClass());
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
}
}
@@ -631,7 +633,7 @@ try
$sPageId = "ui-global-search";
$sLabel = Dict::S('UI:SearchResultsTitle');
$sDescription = Dict::S('UI:SearchResultsTitle+');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription, '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription, '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oP->add("<div style=\"padding: 10px;\">\n");
$oP->add("<div class=\"header_message\" id=\"full_text_progress\" style=\"position: fixed; background-color: #cccccc; opacity: 0.7; padding: 1.5em;\">\n");
$oP->add('<img id="full_text_indicator" src="../images/indicator.gif">&nbsp;<span style="padding: 1.5em;">'.Dict::Format('UI:Search:Ongoing', htmlentities($sFullText, ENT_QUOTES, 'UTF-8')).'</span>');

View File

@@ -48,7 +48,7 @@ $sOQLClause = utils::ReadParam('oql_clause', '', false, 'raw_data');
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
$sOperation = utils::ReadParam('operation', '');
$oP->SetBreadCrumbEntry('ui-tool-universalsearch', Dict::S('Menu:UniversalSearchMenu'), Dict::S('Menu:UniversalSearchMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-universalsearch', Dict::S('Menu:UniversalSearchMenu'), Dict::S('Menu:UniversalSearchMenu+'), '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
@@ -117,7 +117,7 @@ if ($oFilter != null)
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oFilter->GetClass();
$sLabel = MetaModel::GetName($oFilter->GetClass());
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
// Menu node
$sFilter = $oFilter->ToOQL();

View File

@@ -243,7 +243,7 @@ try
case 'errors':
$sTitle = 'Audit Errors';
$oP->SetBreadCrumbEntry('ui-tool-auditerrors', $sTitle, '', '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-auditerrors', $sTitle, '', '', 'fas fa-stethoscope', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$iCategory = utils::ReadParam('category', '');
$iRuleIndex = utils::ReadParam('rule', 0);
@@ -268,7 +268,7 @@ try
case 'audit':
default:
$oP->SetBreadCrumbEntry('ui-tool-audit', Dict::S('Menu:Audit'), Dict::S('UI:Audit:InteractiveAudit'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-audit', Dict::S('Menu:Audit'), Dict::S('UI:Audit:InteractiveAudit'), '', 'fas fa-stethoscope', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oP->add('<div class="page_header"><h1>'.Dict::S('UI:Audit:InteractiveAudit').'</h1><img style="margin-top: -20px; margin-right: 10px; float: right;" src="../images/clean.png"/></div>');
$oAuditFilter = new DBObjectSearch('AuditCategory');
$oCategoriesSet = new DBObjectSet($oAuditFilter);

View File

@@ -33,7 +33,7 @@ try
$iStep = utils::ReadParam('step', 1);
$oPage = new iTopWebPage(Dict::S('UI:Title:BulkImport'));
$oPage->SetBreadCrumbEntry('ui-tool-bulkimport', Dict::S('Menu:CSVImportMenu'), Dict::S('UI:Title:BulkImport+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oPage->SetBreadCrumbEntry('ui-tool-bulkimport', Dict::S('Menu:CSVImportMenu'), Dict::S('UI:Title:BulkImport+'), '', 'fas fa-file-import', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
/**
* Helper function to build a select from the list of valid classes for a given action

View File

@@ -35,7 +35,7 @@ $oP->add('<div class="page_header" style="padding:0.5em;">');
$oP->add('<h1>'.dict::S('UI:NotificationsMenu:Title').'</h1>');
$oP->add('</div>');
$oP->SetBreadCrumbEntry('ui-tool-notifications', Dict::S('Menu:NotificationsMenu'), Dict::S('Menu:NotificationsMenu+'), '', '../images/bell.png');
$oP->SetBreadCrumbEntry('ui-tool-notifications', Dict::S('Menu:NotificationsMenu'), Dict::S('Menu:NotificationsMenu+'), '', 'fas fa-bell', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oP->StartCollapsibleSection(Dict::S('UI:NotificationsMenu:Help'), true, 'notifications-home');
$oP->add('<div style="padding: 1em; font-size:10pt;background:#E8F3CF;margin-top: 0.25em;">');

View File

@@ -507,7 +507,7 @@ try
case 'display':
default:
$oPage->SetBreadCrumbEntry('ui-tool-preferences', Dict::S('UI:Preferences'), Dict::S('UI:Preferences'), '',
utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
'fas fa-user-cog', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
DisplayPreferences($oPage);
}
}

View File

@@ -92,7 +92,7 @@ $sOperation = utils::ReadParam('operation', 'menu');
$oAppContext = new ApplicationContext();
$oP = new iTopWebPage(Dict::S('UI:RunQuery:Title'));
$oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
// Main program
$sExpression = utils::ReadParam('expression', '', false, 'raw_data');
@@ -208,7 +208,7 @@ EOF
}
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?'.implode('&', $aArgs);
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, '../images/breadcrumb-search.png');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oP->p('');
$oP->StartCollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), false, 'runQuery');

View File

@@ -1134,7 +1134,7 @@ $oPage = new iTopWebPage(Dict::S('UI:Schema:Title'));
$oPage->no_cache();
$oPage->SetBreadCrumbEntry('ui-tool-datamodel', Dict::S('Menu:DataModelMenu'), Dict::S('Menu:DataModelMenu+'), '',
utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
'fas fa-book', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oPage->add_script(
<<<EOF
var autocompleteClassLabelAndCode = [];

View File

@@ -52,7 +52,7 @@ try
$oP->add('<h1>'.dict::S('UI:TagAdminMenu:Title').'</h1>');
$oP->add('</div>');
$oP->SetBreadCrumbEntry('ui-tool-tag-admin', Dict::S('Menu:TagAdminMenu'), Dict::S('Menu:TagAdminMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-tag-admin', Dict::S('Menu:TagAdminMenu'), Dict::S('Menu:TagAdminMenu+'), '', 'fas fa-tags', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$sSearchHeaderForceDropdown = '<select id="select_class" name="class" onChange="this.form.submit();">';
$aClassLabels = array();

View File

@@ -0,0 +1,11 @@
<div id="{{ aBreadCrumbs.sId }}" class="ibo-breadcrumbs"></div>
{# TODO: Move this to a dedicated script file #}
{% if aBreadCrumbs.aWidgetOptions is defined %}
<script type="text/javascript" src="js/components/breadcrumbs.js"></script>
<script type="text/javascript">
setTimeout(function(){
$('#{{ aBreadCrumbs.sId }}').breadcrumbs({{ aBreadCrumbs.aWidgetOptions|json_encode|raw }});
}, 500);
</script>
{% endif %}

View File

@@ -1,8 +1,8 @@
<nav {% if sId is defined %}id="{{ sId }}"{% endif%} class="ibo-navigation-menu">
<nav id="{{ aNavigationMenu.sId }}" class="ibo-navigation-menu">
<div class="ibo-navigation-menu--body">
<div class="ibo-navigation-menu--top-part">
<a class="ibo-navigation-menu--square-company-logo" title="{{ sAppRevisionNumber }}" href="{{ sAppIconLink }}">
<img src="{{ sAppSquareIconUrl }}" alt="{{ 'UI:Layout:NavigationMenu:CompanyLogo:AltText'|dict_s }}" />
<a class="ibo-navigation-menu--square-company-logo" title="{{ aNavigationMenu.sAppRevisionNumber }}" href="{{ aNavigationMenu.sAppIconLink }}">
<img src="{{ aNavigationMenu.sAppSquareIconUrl }}" alt="{{ 'UI:Layout:NavigationMenu:CompanyLogo:AltText'|dict_s }}" />
</a>
<a class="ibo-navigation-menu--toggler" data-role="ibo-navigation-menu--toggler" title="{{ 'UI:Layout:NavigationMenu:Toggler:Tooltip'|dict_s }}" href="#">
<span class="ibo-navigation-menu--toggler-icon">
@@ -13,8 +13,8 @@
</a>
</div>
<div class="ibo-navigation-menu--middle-part">
{% for aMenuGroup in aMenuGroups %}
{% include 'layouts/navigation-menu/menu-group.html.twig' with aMenuGroup %}
{% for aMenuGroup in aNavigationMenu.aMenuGroups %}
{{ include('layouts/navigation-menu/menu-group.html.twig', { aMenuGroup: aMenuGroup }, false) }}
{% endfor %}
</div>
<div class="ibo-navigation-menu--bottom-part">
@@ -29,8 +29,8 @@
<span class="ibo-navigation-menu--menu-filter-hotkey">{{ 'UI:Layout:NavigationMenu:MenuFilter:Input:Hotkey'|dict_s }}</span>
</div>
<div class="ibo-navigation-menu--menu-groups">
{% for aMenuGroup in aMenuGroups %}
{% include 'layouts/navigation-menu/menu-nodes.html.twig' with aMenuGroup %}
{% for aMenuGroup in aNavigationMenu.aMenuGroups %}
{{ include('layouts/navigation-menu/menu-nodes.html.twig', { aMenuGroup: aMenuGroup }, false) }}
{% endfor %}
</div>
</div>
@@ -40,6 +40,6 @@
<script type="text/javascript" src="js/layouts/navigation-menu.js"></script>
<script type="text/javascript">
setTimeout(function(){
$('#{{ sId }}').navigation_menu();
$('#{{ aNavigationMenu.sId }}').navigation_menu();
}, 500);
</script>

View File

@@ -5,10 +5,10 @@
{% else %}
<span class="ibo-navigation-menu--menu-node-title">{{ aMenuNode.sTitle }}</span>
{% endif %}
{% if aMenuNode.aChildNodes is defined and aMenuNode.aChildNodes|length > 0 %}
{% if aMenuNode.aSubMenuNodes is defined and aMenuNode.aSubMenuNodes|length > 0 %}
<ul>
{% for aSubMenuNode in aMenuGroup.aSubMenuNodes %}
{% include 'layouts/navigation-menu/menu-node.html.twig' with aSubMenuNode %}
{% for aSubMenuNode in aMenuNode.aSubMenuNodes %}
{{ include('layouts/navigation-menu/menu-node.html.twig', { aMenuNode: aSubMenuNode }, false) }}
{% endfor %}
</ul>
{% endif %}

View File

@@ -2,7 +2,7 @@
<h2 class="ibo-navigation-menu--menu-nodes-title">{{ aMenuGroup.sTitle }}</h2>
<ul>
{% for aMenuNode in aMenuGroup.aSubMenuNodes %}
{% include 'layouts/navigation-menu/menu-node.html.twig' with aMenuNode %}
{{ include('layouts/navigation-menu/menu-node.html.twig', { aMenuNode: aMenuNode }, false) }}
{% endfor %}
</ul>
</div>

View File

@@ -0,0 +1,3 @@
<nav id="{{ aTopBar.sId }}" class="ibo-top-bar">
{{ include('components/breadcrumbs/layout.html.twig', { aBreadCrumbs: aTopBar.aComponents.aBreadCrumbs }, false) }}
</nav>

View File

@@ -36,11 +36,9 @@
{% endblock %}
</head>
<body data-gui-type="backoffice">
{% include 'layouts/navigation-menu/layout.html.twig' with aLayouts.aNavigationMenu %}
{{ include('layouts/navigation-menu/layout.html.twig', { aNavigationMenu: aLayouts.aNavigationMenu }, false) }}
<div id="ibo-page-container">
<nav id="ibo-top-bar" class="ibo-top-bar">
<span>item</span><span>item</span><span>item</span><span>item</span><span>item</span><span>item</span><span>item</span><span>item</span>
</nav>
{{ include('layouts/top-bar/layout.html.twig', { aTopBar: aLayouts.aTopBar }, false) }}
<main id="ibo-page-content">
<div>item</div>
<div>

View File

@@ -98,7 +98,7 @@ $sOperation = utils::ReadParam('operation', 'menu');
$oAppContext = new ApplicationContext();
$oP = new iTopWebPage(Dict::S('UI:RunQuery:Title'));
$oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
// Main program
$sExpression = utils::ReadParam('expression', '', false, 'raw_data');
@@ -213,7 +213,7 @@ EOF
}
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?'.implode('&', $aArgs);
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, '../images/breadcrumb-search.png');
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oP->p('');
$oP->StartCollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), false, 'runQuery');

View File

@@ -375,7 +375,7 @@ EOF
else
{
$oP = new iTopWebPage('iTop Export');
$oP->SetBreadCrumbEntry('ui-tool-export', Dict::S('Menu:ExportMenu'), Dict::S('Menu:ExportMenu+'), '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
$oP->SetBreadCrumbEntry('ui-tool-export', Dict::S('Menu:ExportMenu'), Dict::S('Menu:ExportMenu+'), '', 'fas fa-file-export', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
if ($sExpression === null)