mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-22 10:08:45 +02:00
#185 Navigation Breadcrumb - A beta version, based on the navigation history. Comments welcome!
SVN:trunk[4000]
This commit is contained in:
@@ -1203,6 +1203,15 @@ EOF
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
return $oNewCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the result to be meaningful, this function must be called AFTER GetRenderContent() (or Display())
|
||||
* @return int
|
||||
*/
|
||||
public function GetDisplayedCount()
|
||||
{
|
||||
return $this->m_oSet->Count();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,11 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
private $m_sMessage;
|
||||
private $m_sInitScript;
|
||||
protected $m_oTabs;
|
||||
protected $sBreadCrumbEntryId;
|
||||
protected $sBreadCrumbEntryLabel;
|
||||
protected $sBreadCrumbEntryDescription;
|
||||
protected $sBreadCrumbEntryUrl;
|
||||
protected $sBreadCrumbEntryIcon;
|
||||
|
||||
public function __construct($sTitle, $bPrintable = false)
|
||||
{
|
||||
@@ -45,6 +50,12 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
|
||||
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
|
||||
|
||||
$this->sBreadCrumbEntryId = null;
|
||||
$this->sBreadCrumbEntryLabel = null;
|
||||
$this->sBreadCrumbEntryDescription = null;
|
||||
$this->sBreadCrumbEntryUrl = null;
|
||||
$this->sBreadCrumbEntryIcon = '';
|
||||
|
||||
$this->m_sMenu = "";
|
||||
$this->m_sMessage = '';
|
||||
$this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
|
||||
@@ -55,7 +66,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->add_linked_stylesheet("../css/fg.menu.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.multiselect.css");
|
||||
$this->add_linked_stylesheet("../css/magnific-popup.css");
|
||||
|
||||
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
$this->add_linked_script("../js/jquery.treeview.js");
|
||||
@@ -79,7 +90,8 @@ 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');
|
||||
|
||||
|
||||
$sSearchAny = addslashes(Dict::S('UI:SearchValue:Any'));
|
||||
$sSearchNbSelected = addslashes(Dict::S('UI:SearchValue:NbSelected'));
|
||||
@@ -244,7 +256,7 @@ EOF;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('.resizable').filter(':visible').resizable();
|
||||
}
|
||||
catch(err)
|
||||
@@ -517,7 +529,23 @@ EOF
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sId Identifies the item, to search after it in the current breadcrumb
|
||||
* @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
|
||||
*/
|
||||
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '')
|
||||
{
|
||||
$this->sBreadCrumbEntryId = $sId;
|
||||
$this->sBreadCrumbEntryLabel = $sLabel;
|
||||
$this->sBreadCrumbEntryDescription = $sDescription;
|
||||
$this->sBreadCrumbEntryUrl = $sUrl;
|
||||
$this->sBreadCrumbEntryIcon = $sIcon;
|
||||
}
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
@@ -643,7 +671,9 @@ EOF
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSMultiselectOptions = json_encode($aMultiselectOptions);
|
||||
|
||||
|
||||
$siTopInstanceId = json_encode(APPROOT);
|
||||
$sNewEntry = is_null($this->sBreadCrumbEntryId) ? 'null' : json_encode(array('id' => $this->sBreadCrumbEntryId, 'url' => $this->sBreadCrumbEntryUrl, 'label' => htmlentities($this->sBreadCrumbEntryLabel, ENT_QUOTES, 'UTF-8'), 'description' => htmlentities($this->sBreadCrumbEntryDescription, ENT_QUOTES, 'UTF-8'), 'icon' => $this->sBreadCrumbEntryIcon));
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
@@ -655,6 +685,8 @@ EOF
|
||||
|
||||
$('.multiselect').multiselect($sJSMultiselectOptions);
|
||||
|
||||
$('#itop-breadcrumb').breadcrumb({itop_instance_id: $siTopInstanceId, new_entry: $sNewEntry});
|
||||
|
||||
FixSearchFormsDisposition();
|
||||
|
||||
EOF
|
||||
@@ -897,7 +929,7 @@ EOF
|
||||
|
||||
if (!empty($sNorthPane))
|
||||
{
|
||||
$sNorthPane = '<div id="bottom-pane" class="ui-layout-north">'.$sNorthPane.'</div>';
|
||||
$sNorthPane = '<div id="top-pane" class="ui-layout-north">'.$sNorthPane.'</div>';
|
||||
}
|
||||
|
||||
if (!empty($sSouthPane))
|
||||
@@ -944,13 +976,27 @@ EOF
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sHtml .= '<div class="ui-layout-center">';
|
||||
$sHtml .= ' <div id="top-bar" style="width:100%">';
|
||||
$sHtml .= ' <div id="top-bar" class="ui-helper-clearfix" style="width:100%">';
|
||||
$sHtml .= self::FilterXSS($sApplicationBanner);
|
||||
|
||||
$sHtml .= ' <table id="top-bar-table">';
|
||||
$sHtml .= ' <tr>';
|
||||
$sHtml .= ' <td id="top-bar-table-breadcrumb">';
|
||||
$sHtml .= ' <div id="itop-breadcrumb"></div>';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td id="top-bar-table-search">';
|
||||
$sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"></div></div></td>';
|
||||
//$sHtml .= '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
$sHtml .= '<td><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank"><img title="'.Dict::S('UI:Help').'" src="../images/help.png?itopversion='.ITOP_VERSION.'"/></td>';
|
||||
$sHtml .= '<td>'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
$sHtml .= ' <td><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank"><img title="'.Dict::S('UI:Help').'" src="../images/help.png?itopversion='.ITOP_VERSION.'"/></td>';
|
||||
$sHtml .= ' <td>'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' </tr>';
|
||||
$sHtml .= ' </table>';
|
||||
|
||||
// $sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"></div></div></td>';
|
||||
// $sHtml .= '<td><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank"><img title="'.Dict::S('UI:Help').'" src="../images/help.png?itopversion='.ITOP_VERSION.'"/></td>';
|
||||
// $sHtml .= '<td>'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
// $sHtml .= ' <div id="itop-breadcrumb"></div>';
|
||||
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="ui-layout-content" style="overflow:auto;">';
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Construction and display of the application's main menu
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -296,6 +296,16 @@ class ApplicationMenu
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
if ($sMenuId === null)
|
||||
{
|
||||
$sMenuId == self::GetDefaultMenuId();
|
||||
}
|
||||
return $sMenuId;
|
||||
}
|
||||
|
||||
static public function GetDefaultMenuId()
|
||||
{
|
||||
static $sDefaultMenuId = null;
|
||||
if (is_null($sDefaultMenuId))
|
||||
{
|
||||
// Make sure the root menu is sorted on 'rank'
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
@@ -303,10 +313,10 @@ class ApplicationMenu
|
||||
$aChildren = self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'];
|
||||
usort($aChildren, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$oMenuNode = self::GetMenuNode($aChildren[0]['index']);
|
||||
$sMenuId = $oMenuNode->GetMenuId();
|
||||
$sDefaultMenuId = $oMenuNode->GetMenuId();
|
||||
}
|
||||
return $sMenuId;
|
||||
}
|
||||
return $sDefaultMenuId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +349,7 @@ abstract class MenuNode
|
||||
{
|
||||
protected $sMenuId;
|
||||
protected $index;
|
||||
protected $iParentIndex;
|
||||
|
||||
/**
|
||||
* Properties reflecting how the node has been declared
|
||||
@@ -379,6 +390,7 @@ abstract class MenuNode
|
||||
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
$this->sMenuId = $sMenuId;
|
||||
$this->iParentIndex = $iParentIndex;
|
||||
$this->aReflectionProperties = array();
|
||||
if (strlen($sEnableClass) > 0)
|
||||
{
|
||||
@@ -411,7 +423,21 @@ abstract class MenuNode
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId+", "");
|
||||
$sRet = Dict::S("Menu:$this->sMenuId+", "");
|
||||
if ($sRet === '')
|
||||
{
|
||||
if ($this->iParentIndex != -1)
|
||||
{
|
||||
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
|
||||
$sRet = $oParentMenu->GetTitle().' / '.$this->GetTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = $this->GetTitle();
|
||||
}
|
||||
//$sRet = $this->GetTitle();
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetIndex()
|
||||
@@ -647,11 +673,12 @@ class OQLMenuNode extends MenuNode
|
||||
$this->bSearch, // Search pane
|
||||
true, // Search open
|
||||
$oPage,
|
||||
array_merge($this->m_aParams, $aExtraParams)
|
||||
array_merge($this->m_aParams, $aExtraParams),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public static function RenderOQLSearch($sOql, $sTitle, $sUsageId, $bSearchPane, $bSearchOpen, WebPage $oPage, $aExtraParams = array())
|
||||
public static function RenderOQLSearch($sOql, $sTitle, $sUsageId, $bSearchPane, $bSearchOpen, WebPage $oPage, $aExtraParams = array(), $bEnableBreadcrumb = false)
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
@@ -669,6 +696,15 @@ class OQLMenuNode extends MenuNode
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, $sUsageId);
|
||||
|
||||
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
|
||||
{
|
||||
// Breadcrumb
|
||||
//$iCount = $oBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oSearch->GetClass();
|
||||
$sLabel = MetaModel::GetName($oSearch->GetClass());
|
||||
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,6 +956,29 @@ EOF
|
||||
$sId = addslashes($this->sMenuId);
|
||||
$oPage->add_ready_script("EditDashboard('$sId');");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
|
||||
$sParentTitle = $oParentMenu->GetTitle();
|
||||
$sThisTitle = $this->GetTitle();
|
||||
if ($sParentTitle != $sThisTitle)
|
||||
{
|
||||
$sDescription = $sParentTitle.' / '.$sThisTitle;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDescription = $sThisTitle;
|
||||
}
|
||||
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
|
||||
{
|
||||
$sIcon = '../images/breadcrumb_home.png';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sIcon = '../images/breadcrumb-dashboard.png';
|
||||
}
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -950,7 +1009,7 @@ EOF
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -21,7 +21,7 @@
|
||||
* Persistent class Shortcut and derived
|
||||
* Shortcuts of any kind
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -200,7 +200,7 @@ class ShortcutOQL extends Shortcut
|
||||
$bSearchOpen = false;
|
||||
try
|
||||
{
|
||||
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams);
|
||||
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
|
||||
@@ -1151,7 +1151,6 @@ div#logo div {
|
||||
|
||||
|
||||
#top-bar {
|
||||
height: 55px;
|
||||
background: #f1f1f1;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -2201,3 +2200,71 @@ span.refresh-button {
|
||||
}
|
||||
|
||||
|
||||
#top-bar-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#top-bar-table #top-bar-table-search {
|
||||
width: 347px;
|
||||
}
|
||||
|
||||
|
||||
#itop-breadcrumb {
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background: #f1f1f1;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#itop-breadcrumb li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
margin: 0 22px 6px 0;
|
||||
}
|
||||
#itop-breadcrumb li .icon img {
|
||||
height: 15px;
|
||||
width: auto;
|
||||
margin-right: 5px;
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
filter: gray;
|
||||
filter: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' height='0'><filter id='greyscale'><feColorMatrix type='matrix' values='0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0' /></filter></svg>#greyscale");
|
||||
opacity: 0.5;
|
||||
}
|
||||
#itop-breadcrumb li:hover .icon img {
|
||||
-webkit-filter: none;
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
#itop-breadcrumb li a {
|
||||
text-decoration: none;
|
||||
color: #555555;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
#itop-breadcrumb li a span.truncate {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
#itop-breadcrumb li a:hover {
|
||||
text-decoration: none;
|
||||
color: #e87c1e;
|
||||
}
|
||||
#itop-breadcrumb li a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-image: url(../images/breadcrumb-separator.png?v=v2.2.0);
|
||||
background-repeat: no-repeat;
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#itop-breadcrumb li:last-child a::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ $popup-menu-highlight-color = $highlight-color;
|
||||
$popup-menu-text-color: #000;
|
||||
$popup-menu-background-color: #fff;
|
||||
$popup-menu-text-higlight-color: #fff;
|
||||
$breadcrumb-color: #555;
|
||||
$breadcrumb-text-color: #fff;
|
||||
$breadcrumb-highlight-color: $highlight-color;
|
||||
$breadcrumb-text-highlight-color: #fff;
|
||||
|
||||
/* CSS Document */
|
||||
body {
|
||||
@@ -868,7 +872,6 @@ div#logo div {
|
||||
overflow: hidden;
|
||||
}
|
||||
#top-bar {
|
||||
height: 55px;
|
||||
background: $frame-background-color;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -1615,4 +1618,80 @@ span.refresh-button {
|
||||
}
|
||||
.history_entry_truncated .history_truncated_toggler {
|
||||
background-position: 0 -192px;
|
||||
}
|
||||
}
|
||||
|
||||
#top-bar-table {
|
||||
width: 100%;
|
||||
#top-bar-table-search{
|
||||
width: 347px;
|
||||
}
|
||||
}
|
||||
|
||||
#itop-breadcrumb{
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background: $frame-background-color;
|
||||
margin-left: -20px;
|
||||
|
||||
li{
|
||||
list-style: none;
|
||||
float: left;
|
||||
margin: 0 22px 6px 0;
|
||||
|
||||
.icon img{
|
||||
height: 15px;
|
||||
width: auto;
|
||||
margin-right: 5px;
|
||||
|
||||
-webkit-filter: unquote("grayscale(100%)");
|
||||
filter: unquote("grayscale(100%)");
|
||||
filter: unquote("gray");
|
||||
filter: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' height='0'><filter id='greyscale'><feColorMatrix type='matrix' values='0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0' /></filter></svg>#greyscale");
|
||||
|
||||
// IE has no filter option: at least, have some effect when hovering...
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover .icon img{
|
||||
-webkit-filter: none;
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
a{
|
||||
text-decoration: none;
|
||||
color: #555;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
background: none;
|
||||
span.truncate
|
||||
{
|
||||
// Ellipsis
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
text-decoration: none;
|
||||
color: $highlight-color;
|
||||
}
|
||||
|
||||
&::after{
|
||||
content:'';
|
||||
position: absolute;
|
||||
background-image: url(../images/breadcrumb-separator.png?v=#{$version});
|
||||
background-repeat: no-repeat;
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child a::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
images/breadcrumb-dashboard.png
Normal file
BIN
images/breadcrumb-dashboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 477 B |
BIN
images/breadcrumb-search.png
Normal file
BIN
images/breadcrumb-search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 B |
BIN
images/breadcrumb-separator.png
Normal file
BIN
images/breadcrumb-separator.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 324 B |
BIN
images/breadcrumb_home.png
Normal file
BIN
images/breadcrumb_home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 175 B |
111
js/breadcrumb.js
Normal file
111
js/breadcrumb.js
Normal file
@@ -0,0 +1,111 @@
|
||||
//iTop Form field
|
||||
;
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where 'itop' is the namespace,
|
||||
// 'breadcrumb' the widget name
|
||||
$.widget( 'itop.breadcrumb',
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
itop_instance_id: '',
|
||||
new_entry: null,
|
||||
},
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
var me = this;
|
||||
|
||||
this.element
|
||||
.addClass('breadcrumb');
|
||||
|
||||
if(typeof(Storage) !== "undefined")
|
||||
{
|
||||
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
|
||||
var aBreadCrumb = [];
|
||||
var sBreadCrumbData = sessionStorage.getItem(sBreadCrumbStorageKey);
|
||||
if (sBreadCrumbData !== null)
|
||||
{
|
||||
aBreadCrumb = JSON.parse(sBreadCrumbData);
|
||||
}
|
||||
var iDisplayableItems = aBreadCrumb.length;
|
||||
|
||||
if (this.options.new_entry !== null) {
|
||||
var sUrl = this.options.new_entry.url;
|
||||
if (sUrl.length == 0) {
|
||||
sUrl = window.location.href;
|
||||
}
|
||||
// Eliminate items having the same id, before appending the new item
|
||||
var aBreadCrumb = $.grep(aBreadCrumb, function(item, ipos){
|
||||
if (item.id == me.options.new_entry.id) return false;
|
||||
else return true;
|
||||
});
|
||||
aBreadCrumb.push({
|
||||
id: this.options.new_entry.id,
|
||||
label: this.options.new_entry.label,
|
||||
description: this.options.new_entry.description,
|
||||
icon: this.options.new_entry.icon,
|
||||
url: sUrl
|
||||
});
|
||||
// Keep only the last N items
|
||||
aBreadCrumb = aBreadCrumb.slice(-8);
|
||||
// Do not show the last = current item
|
||||
iDisplayableItems = aBreadCrumb.length - 1;
|
||||
}
|
||||
sBreadCrumbData = JSON.stringify(aBreadCrumb);
|
||||
sessionStorage.setItem(sBreadCrumbStorageKey, sBreadCrumbData);
|
||||
var sBreadCrumbHtml = '<ul>';
|
||||
for (iEntry in aBreadCrumb)
|
||||
{
|
||||
//if (iEntry >= iDisplayableItems) break; // skip the current page
|
||||
var oEntry = aBreadCrumb[iEntry];
|
||||
if (oEntry['label'].length > 0)
|
||||
{
|
||||
var sIconSpec = '';
|
||||
if (oEntry['icon'].length > 0)
|
||||
{
|
||||
sIconSpec = '<span class="icon"><img src="'+oEntry['icon']+'"/></span>';
|
||||
}
|
||||
var sTitle = oEntry['description'];
|
||||
if (sTitle.length == 0) {
|
||||
sTitle = oEntry['label'];
|
||||
}
|
||||
sBreadCrumbHtml += '<li><a class="itop-breadcrumb-link" breadcrumb-entry="'+iEntry+'" href="'+oEntry['url']+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+oEntry['label']+'</span></a></li>';
|
||||
}
|
||||
}
|
||||
sBreadCrumbHtml += '</ul>';
|
||||
$('#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');
|
||||
},
|
||||
// _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 );
|
||||
}
|
||||
});
|
||||
});
|
||||
40
pages/UI.php
40
pages/UI.php
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Main page of iTop
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -174,6 +174,12 @@ function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '',
|
||||
{
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, 1);
|
||||
|
||||
// Breadcrumb
|
||||
//$iCount = $oBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oFilter->GetClass();
|
||||
$sLabel = MetaModel::GetName($oFilter->GetClass());
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,11 +362,13 @@ try
|
||||
}
|
||||
if (!is_null($oObj))
|
||||
{
|
||||
$sClass = get_class($oObj); // get the leaf class
|
||||
$oP->SetBreadCrumbEntry("ui-details-$sClass-$id", $oObj->Get('friendlyname'), $sClass.': '.$oObj->Get('friendlyname'), '', MetaModel::GetClassIcon($sClass, false));
|
||||
DisplayDetails($oP, $sClass, $oObj, $id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'release_lock_and_details':
|
||||
$sClass = utils::ReadParam('class', '');
|
||||
$id = utils::ReadParam('id', '');
|
||||
@@ -414,19 +422,19 @@ try
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'search_form': // Search form
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sFormat = utils::ReadParam('format', 'html');
|
||||
$bSearchForm = utils::ReadParam('search_form', true);
|
||||
$bDoSearch = utils::ReadParam('do_search', true);
|
||||
if (empty($sClass))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
|
||||
}
|
||||
$oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat, $bDoSearch);
|
||||
break;
|
||||
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sFormat = utils::ReadParam('format', 'html');
|
||||
$bSearchForm = utils::ReadParam('search_form', true);
|
||||
$bDoSearch = utils::ReadParam('do_search', true);
|
||||
if (empty($sClass))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
|
||||
}
|
||||
$oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
DisplaySearchSet($oP, $oFilter, $bSearchForm, '' /* sBaseClass */, $sFormat, $bDoSearch);
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'search': // Serialized DBSearch
|
||||
@@ -1633,7 +1641,7 @@ catch(Exception $e)
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
|
||||
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
|
||||
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
|
||||
$oP->output();
|
||||
|
||||
if (MetaModel::IsLogEnabledIssue())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Analytical search
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -113,7 +113,13 @@ if ($oFilter != null)
|
||||
// Search results
|
||||
$oResultBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oResultBlock->Display($oP, 1);
|
||||
|
||||
|
||||
// Breadcrumb
|
||||
//$iCount = $oBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oFilter->GetClass();
|
||||
$sLabel = MetaModel::GetName($oFilter->GetClass());
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
|
||||
|
||||
// Menu node
|
||||
$sFilter = $oFilter->ToOQL();
|
||||
$oP->add("\n<!-- $sFilter -->\n");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2013 Combodo SARL
|
||||
// Copyright (C) 2013-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Page to configuration the notifications (triggers and actions)
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2013-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,8 @@ $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->StartCollapsibleSection(Dict::S('UI:NotificationsMenu:Help'), true);
|
||||
$oP->add('<div style="padding: 1em; font-size:10pt;background:#E8F3CF;margin-top: 0.25em;">');
|
||||
$oP->add('<img src="../images/bell.png" style="margin-top: -60px; margin-right: 10px; float: right;">');
|
||||
|
||||
@@ -192,6 +192,29 @@ try
|
||||
$oResultBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oResultBlock->Display($oP, 'runquery');
|
||||
|
||||
// Breadcrumb
|
||||
//$iCount = $oResultBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oFilter->GetClass();
|
||||
$sLabel = MetaModel::GetName($oFilter->GetClass());
|
||||
$aArgs = array();
|
||||
foreach (array_merge($_POST, $_GET) as $sKey => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
$aItems = array();
|
||||
foreach($value as $sItemKey => $sItemValue)
|
||||
{
|
||||
$aArgs[] = $sKey.'['.$sItemKey.']='.urlencode($sItemValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArgs[] = $sKey.'='.urlencode($value);
|
||||
}
|
||||
}
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?'.implode('&', $aArgs);
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, '../images/breadcrumb-search.png');
|
||||
|
||||
$oP->p('');
|
||||
$oP->StartCollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), false);
|
||||
$oP->p(Dict::S('UI:RunQuery:DevelopedQuery').htmlentities($oFilter->ToOQL(), ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
Reference in New Issue
Block a user