mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
#185 Navigation Breadcrumb - Beta version
- Any page has a breadcrumb (except if POST and a number of pages like "new object") - Added Home + Menu buttons showed when the left pane is closed - Configuration: breadcrumb.max_count (0 to disable) SVN:trunk[4022]
This commit is contained in:
@@ -37,6 +37,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
private $m_sMessage;
|
||||
private $m_sInitScript;
|
||||
protected $m_oTabs;
|
||||
protected $bBreadCrumbEnabled;
|
||||
protected $sBreadCrumbEntryId;
|
||||
protected $sBreadCrumbEntryLabel;
|
||||
protected $sBreadCrumbEntryDescription;
|
||||
@@ -50,11 +51,15 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
|
||||
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
|
||||
|
||||
$this->sBreadCrumbEntryId = null;
|
||||
$this->sBreadCrumbEntryLabel = null;
|
||||
$this->sBreadCrumbEntryDescription = null;
|
||||
$this->sBreadCrumbEntryUrl = null;
|
||||
$this->sBreadCrumbEntryIcon = '';
|
||||
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
|
||||
{
|
||||
$this->bBreadCrumbEnabled = false;
|
||||
}
|
||||
|
||||
$this->m_sMenu = "";
|
||||
$this->m_sMessage = '';
|
||||
@@ -107,45 +112,44 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
}
|
||||
}
|
||||
|
||||
protected function PrepareLayout()
|
||||
protected function IsMenuPaneVisible()
|
||||
{
|
||||
$bForceMenuPane = utils::ReadParam('force_menu_pane', null);
|
||||
$sInitClosed = '';
|
||||
if (($bForceMenuPane !== null) && ($bForceMenuPane == 0))
|
||||
{
|
||||
$sInitClosed = 'initClosed: true,';
|
||||
}
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function ShowAboutBox()
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'about_box'}, function(data){
|
||||
$('body').append(data);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
$bLeftPaneOpen = true;
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
// Leave the pane opened
|
||||
}
|
||||
else
|
||||
{
|
||||
if (utils::ReadParam('force_menu_pane', null) === 0)
|
||||
{
|
||||
$bLeftPaneOpen = false;
|
||||
}
|
||||
elseif (appUserPreferences::GetPref('menu_pane', 'open') == 'closed')
|
||||
{
|
||||
$bLeftPaneOpen = false;
|
||||
}
|
||||
}
|
||||
return $bLeftPaneOpen;
|
||||
}
|
||||
|
||||
protected function PrepareLayout()
|
||||
{
|
||||
$bLeftPaneOpen = true;
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
// No pin button
|
||||
$sConfigureWestPane = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sConfigureWestPane =
|
||||
<<<EOF
|
||||
if (GetUserPreference('menu_pane', 'open') == 'closed')
|
||||
{
|
||||
myLayout.close('west');
|
||||
}
|
||||
myLayout.addPinBtn( "#tPinMenu", "west" );
|
||||
EOF;
|
||||
}
|
||||
$sInitClosed = $this->IsMenuPaneVisible() ? '' : 'initClosed: true,';
|
||||
|
||||
|
||||
$sJSDisconnectedMessage = json_encode(Dict::S('UI:DisconnectedDlgMessage'));
|
||||
$sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle'));
|
||||
$sJSLoginAgain = json_encode(Dict::S('UI:LoginAgain'));
|
||||
@@ -172,11 +176,12 @@ EOF;
|
||||
paneSize = GetUserPreference('menu_size', 300)
|
||||
myLayout = $('body').layout({
|
||||
west : {
|
||||
$sInitClosed minSize: 200, size: paneSize, spacing_open: 16, spacing_close: 16, slideTrigger_open: "mouseover", hideTogglerOnSlide: true, enableCursorHotkey: false,
|
||||
$sInitClosed minSize: 200, size: paneSize, spacing_open: 16, spacing_close: 16, slideTrigger_open: "click", hideTogglerOnSlide: true, enableCursorHotkey: false,
|
||||
onclose_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
$('.menu-pane-exclusive').show();
|
||||
SetUserPreference('menu_pane', 'closed', true);
|
||||
}
|
||||
},
|
||||
@@ -192,6 +197,7 @@ EOF;
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
$('.menu-pane-exclusive').hide();
|
||||
SetUserPreference('menu_pane', 'open', true);
|
||||
}
|
||||
}
|
||||
@@ -570,6 +576,7 @@ EOF
|
||||
*/
|
||||
public function SetBreadCrumbEntry($sId, $sLabel, $sDescription, $sUrl = '', $sIcon = '')
|
||||
{
|
||||
$this->bBreadCrumbEnabled = true;
|
||||
$this->sBreadCrumbEntryId = $sId;
|
||||
$this->sBreadCrumbEntryLabel = $sLabel;
|
||||
$this->sBreadCrumbEntryDescription = $sDescription;
|
||||
@@ -577,6 +584,19 @@ EOF
|
||||
$this->sBreadCrumbEntryIcon = $sIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* State that there will be no breadcrumb item for the current page
|
||||
*/
|
||||
public function DisableBreadCrumb()
|
||||
{
|
||||
$this->bBreadCrumbEnabled = false;
|
||||
$this->sBreadCrumbEntryId = null;
|
||||
$this->sBreadCrumbEntryLabel = null;
|
||||
$this->sBreadCrumbEntryDescription = null;
|
||||
$this->sBreadCrumbEntryUrl = null;
|
||||
$this->sBreadCrumbEntryIcon = null;
|
||||
}
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
@@ -701,9 +721,6 @@ 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
|
||||
@@ -715,12 +732,38 @@ EOF
|
||||
|
||||
$('.multiselect').multiselect($sJSMultiselectOptions);
|
||||
|
||||
$('#itop-breadcrumb').breadcrumb({itop_instance_id: $siTopInstanceId, new_entry: $sNewEntry});
|
||||
|
||||
FixSearchFormsDisposition();
|
||||
|
||||
EOF
|
||||
);
|
||||
|
||||
$iBreadCrumbMaxCount = utils::GetConfig()->Get('breadcrumb.max_count');
|
||||
if ($iBreadCrumbMaxCount > 1)
|
||||
{
|
||||
$siTopInstanceId = json_encode(APPROOT);
|
||||
if ($this->bBreadCrumbEnabled)
|
||||
{
|
||||
if (is_null($this->sBreadCrumbEntryId))
|
||||
{
|
||||
$this->sBreadCrumbEntryId = $this->s_title;
|
||||
$this->sBreadCrumbEntryLabel = $this->s_title;
|
||||
$this->sBreadCrumbEntryDescription = $this->s_title;
|
||||
$this->sBreadCrumbEntryUrl = '';
|
||||
$this->sBreadCrumbEntryIcon = utils::GetAbsoluteUrlAppRoot().'images/wrench.png';
|
||||
}
|
||||
$sNewEntry = 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));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sNewEntry = 'null';
|
||||
}
|
||||
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
$('#itop-breadcrumb').breadcrumb({itop_instance_id: $siTopInstanceId, new_entry: $sNewEntry, max_count: $iBreadCrumbMaxCount});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
foreach($this->a_headers as $s_header)
|
||||
@@ -1009,8 +1052,18 @@ EOF
|
||||
$sHtml .= ' <div id="top-bar" class="ui-helper-clearfix" style="width:100%">';
|
||||
$sHtml .= self::FilterXSS($sApplicationBanner);
|
||||
|
||||
$GoHomeInitialStyle = $this->IsMenuPaneVisible() ? 'display: none;' : '';
|
||||
|
||||
$sHtml .= ' <table id="top-bar-table">';
|
||||
$sHtml .= ' <tr>';
|
||||
$sHtml .= ' <td id="open-left-pane" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'" onclick="$(\'body\').layout().open(\'west\');">';
|
||||
$sHtml .= ' <img src="../images/menu.png">';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td id="go-home" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
|
||||
$sHtml .= ' <a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><img src="../images/home.png"></a>';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td class="top-bar-spacer menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td id="top-bar-table-breadcrumb">';
|
||||
$sHtml .= ' <div id="itop-breadcrumb"></div>';
|
||||
$sHtml .= ' </td>';
|
||||
|
||||
@@ -906,6 +906,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'breadcrumb.max_count' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items kept in the history breadcrumb. Set it to 0 to entirely disable the breadcrumb.',
|
||||
'default' => 8,
|
||||
'value' => 8,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
|
||||
@@ -2202,6 +2202,32 @@ span.refresh-button {
|
||||
|
||||
#top-bar-table {
|
||||
width: 100%;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
#top-bar-table #open-left-pane {
|
||||
text-align: center;
|
||||
width: 40px !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#top-bar-table #go-home {
|
||||
text-align: center;
|
||||
width: 40px !important;
|
||||
}
|
||||
#top-bar-table #go-home a {
|
||||
text-decoration: none;
|
||||
color: #555555;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
background: none;
|
||||
display: inline-block;
|
||||
line-height: 55px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#top-bar-table .top-bar-spacer {
|
||||
width: 35px !important;
|
||||
}
|
||||
|
||||
#top-bar-table #top-bar-table-search {
|
||||
@@ -2213,13 +2239,16 @@ span.refresh-button {
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background: #f1f1f1;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#itop-breadcrumb ul {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#itop-breadcrumb li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
margin: 0 22px 6px 0;
|
||||
margin: 0 22px 0px 0;
|
||||
}
|
||||
#itop-breadcrumb li .icon img {
|
||||
height: 15px;
|
||||
@@ -2231,11 +2260,6 @@ span.refresh-button {
|
||||
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;
|
||||
@@ -2243,6 +2267,11 @@ span.refresh-button {
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
#itop-breadcrumb li a:hover .icon img {
|
||||
-webkit-filter: none;
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
#itop-breadcrumb li a span.truncate {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
@@ -2266,6 +2295,20 @@ span.refresh-button {
|
||||
#itop-breadcrumb li:last-child a::after {
|
||||
display: none;
|
||||
}
|
||||
#itop-breadcrumb li .itop-breadcrumb-current {
|
||||
text-decoration: none;
|
||||
color: #555555;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
#itop-breadcrumb li .itop-breadcrumb-current span.truncate {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.ui-datepicker-buttonpane, .ui-timepicker-div {
|
||||
|
||||
@@ -1622,6 +1622,37 @@ span.refresh-button {
|
||||
|
||||
#top-bar-table {
|
||||
width: 100%;
|
||||
padding-left: 5px;
|
||||
|
||||
$top-button-width: 40px;
|
||||
$top-button-heigth: 55px;
|
||||
$top-button-spacer: 35px;
|
||||
|
||||
#open-left-pane {
|
||||
text-align: center;
|
||||
width: $top-button-width !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
#go-home {
|
||||
text-align: center;
|
||||
width: $top-button-width !important;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #555;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
background: none;
|
||||
|
||||
// Make the whole cell clickable
|
||||
display: inline-block;
|
||||
line-height: $top-button-heigth;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.top-bar-spacer{
|
||||
width: $top-button-spacer !important;
|
||||
}
|
||||
#top-bar-table-search{
|
||||
width: 347px;
|
||||
}
|
||||
@@ -1631,12 +1662,15 @@ span.refresh-button {
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background: $frame-background-color;
|
||||
margin-left: -20px;
|
||||
|
||||
ul {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
li{
|
||||
list-style: none;
|
||||
float: left;
|
||||
margin: 0 22px 6px 0;
|
||||
margin: 0 22px 0px 0;
|
||||
|
||||
.icon img{
|
||||
height: 15px;
|
||||
@@ -1652,18 +1686,19 @@ span.refresh-button {
|
||||
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;
|
||||
|
||||
&:hover .icon img{
|
||||
-webkit-filter: none;
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
span.truncate
|
||||
{
|
||||
// Ellipsis
|
||||
@@ -1693,6 +1728,24 @@ span.refresh-button {
|
||||
&:last-child a::after{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.itop-breadcrumb-current{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui-datepicker-buttonpane, .ui-timepicker-div {
|
||||
|
||||
BIN
images/home.png
Normal file
BIN
images/home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 219 B |
BIN
images/menu.png
Normal file
BIN
images/menu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
BIN
images/wrench.png
Normal file
BIN
images/wrench.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 328 B |
@@ -11,6 +11,7 @@ $(function()
|
||||
{
|
||||
itop_instance_id: '',
|
||||
new_entry: null,
|
||||
max_count: 8
|
||||
},
|
||||
|
||||
// the constructor
|
||||
@@ -23,14 +24,12 @@ $(function()
|
||||
|
||||
if(typeof(Storage) !== "undefined")
|
||||
{
|
||||
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
|
||||
var aBreadCrumb = [];
|
||||
var sBreadCrumbData = sessionStorage.getItem(sBreadCrumbStorageKey);
|
||||
if (sBreadCrumbData !== null)
|
||||
$(window).bind( 'hashchange', function(e)
|
||||
{
|
||||
aBreadCrumb = JSON.parse(sBreadCrumbData);
|
||||
}
|
||||
var iDisplayableItems = aBreadCrumb.length;
|
||||
me._RefreshLatestEntry();
|
||||
});
|
||||
|
||||
aBreadCrumb = this._Read();
|
||||
|
||||
if (this.options.new_entry !== null) {
|
||||
var sUrl = this.options.new_entry.url;
|
||||
@@ -49,13 +48,10 @@ $(function()
|
||||
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;
|
||||
// Keep only the last <max_count> items
|
||||
aBreadCrumb = aBreadCrumb.slice(-(this.options.max_count));
|
||||
}
|
||||
sBreadCrumbData = JSON.stringify(aBreadCrumb);
|
||||
sessionStorage.setItem(sBreadCrumbStorageKey, sBreadCrumbData);
|
||||
this._Write(aBreadCrumb);
|
||||
var sBreadCrumbHtml = '<ul>';
|
||||
for (iEntry in aBreadCrumb)
|
||||
{
|
||||
@@ -72,7 +68,15 @@ $(function()
|
||||
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>';
|
||||
if ((this.options.new_entry !== null) && (iEntry == aBreadCrumb.length - 1))
|
||||
{
|
||||
// Last entry is the current page
|
||||
sBreadCrumbHtml += '<li><div class="itop-breadcrumb-current" breadcrumb-entry="'+iEntry+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+oEntry['label']+'</span></div></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
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>';
|
||||
@@ -106,6 +110,36 @@ $(function()
|
||||
_setOption: function( key, value )
|
||||
{
|
||||
this._super( key, value );
|
||||
},
|
||||
_Read: function()
|
||||
{
|
||||
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
|
||||
var aBreadCrumb = [];
|
||||
var sBreadCrumbData = sessionStorage.getItem(sBreadCrumbStorageKey);
|
||||
if (sBreadCrumbData !== null)
|
||||
{
|
||||
aBreadCrumb = JSON.parse(sBreadCrumbData);
|
||||
}
|
||||
return aBreadCrumb;
|
||||
},
|
||||
_Write: function(aBreadCrumb)
|
||||
{
|
||||
var sBreadCrumbStorageKey = this.options.itop_instance_id + 'breadcrumb-v1';
|
||||
sBreadCrumbData = JSON.stringify(aBreadCrumb);
|
||||
sessionStorage.setItem(sBreadCrumbStorageKey, sBreadCrumbData);
|
||||
},
|
||||
// Refresh the latest entry (navigating to a tab)
|
||||
_RefreshLatestEntry: function()
|
||||
{
|
||||
aBreadCrumb = this._Read();
|
||||
var iDisplayableItems = aBreadCrumb.length;
|
||||
|
||||
if (this.options.new_entry !== null) {
|
||||
// The current page is the last entry in the breadcrumb, let's refresh it
|
||||
aBreadCrumb[aBreadCrumb.length - 1].url = window.location.href;
|
||||
$('#itop-breadcrumb li:last-of-type a').attr('href', window.location.href);
|
||||
}
|
||||
this._Write(aBreadCrumb);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
41
pages/UI.php
41
pages/UI.php
@@ -319,7 +319,7 @@ try
|
||||
$oP->add_linked_script("../js/linksdirectwidget.js");
|
||||
$oP->add_linked_script("../js/extkeywidget.js");
|
||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
switch($operation)
|
||||
@@ -363,13 +363,19 @@ 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));
|
||||
$sIcon = MetaModel::GetClassIcon($sClass, false);
|
||||
if ($sIcon == '')
|
||||
{
|
||||
$sIcon = utils::GetAbsoluteUrlAppRoot().'images/breadcrumb_object.png';
|
||||
}
|
||||
$oP->SetBreadCrumbEntry("ui-details-$sClass-$id", $oObj->Get('friendlyname'), MetaModel::GetName($sClass).': '.$oObj->Get('friendlyname'), '', $sIcon);
|
||||
DisplayDetails($oP, $sClass, $oObj, $id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'release_lock_and_details':
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '');
|
||||
$id = utils::ReadParam('id', '');
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
@@ -561,6 +567,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'modify': // Form to modify an object
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$id = utils::ReadParam('id', '');
|
||||
if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
|
||||
@@ -590,6 +597,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
|
||||
$oP->DisableBreadCrumb();
|
||||
$oP->set_title(Dict::S('UI:ModifyAllPageTitle'));
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
if (empty($sFilter))
|
||||
@@ -607,6 +615,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$oFullSetFilter = DBObjectSearch::unserialize($sFilter);
|
||||
@@ -619,6 +628,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'preview_or_modify_all': // Preview or apply bulk modify
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
// TO DO: limit the search filter by the user context
|
||||
$oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
|
||||
@@ -643,6 +653,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'new': // Form to create a new object
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sStateCode = utils::ReadParam('state', '');
|
||||
$bCheckSubClass = utils::ReadParam('checkSubclass', true);
|
||||
@@ -757,6 +768,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'apply_modify': // Applying the modifications to an existing object
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadPostedParam('class', '');
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
$id = utils::ReadPostedParam('id', '');
|
||||
@@ -860,6 +872,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_for_deletion': // Select multiple objects for deletion
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
if (empty($sFilter))
|
||||
{
|
||||
@@ -876,6 +889,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'bulk_delete_confirmed': // Confirm bulk deletion of objects
|
||||
$oP->DisableBreadCrumb();
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
@@ -887,6 +901,7 @@ EOF
|
||||
|
||||
case 'delete':
|
||||
case 'bulk_delete': // Actual bulk deletion (if confirmed)
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
$aObjects = array();
|
||||
@@ -938,6 +953,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'apply_new': // Creation of a new object
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadPostedParam('class', '', 'class');
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
@@ -1008,6 +1024,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_bulk_stimulus': // Form displayed when applying a stimulus to many objects
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$sStimulus = utils::ReadParam('stimulus', '');
|
||||
$sState = utils::ReadParam('state', '');
|
||||
@@ -1031,6 +1048,7 @@ EOF
|
||||
break;
|
||||
|
||||
case 'bulk_stimulus':
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$sStimulus = utils::ReadParam('stimulus', '');
|
||||
$sState = utils::ReadParam('state', '');
|
||||
@@ -1196,6 +1214,7 @@ EOF
|
||||
break;
|
||||
|
||||
case 'bulk_apply_stimulus':
|
||||
$oP->DisableBreadCrumb();
|
||||
$bPreviewMode = utils::ReadPostedParam('preview_mode', false);
|
||||
$sFilter = utils::ReadPostedParam('filter', '', false, 'raw_data');
|
||||
$sStimulus = utils::ReadPostedParam('stimulus', '');
|
||||
@@ -1329,6 +1348,7 @@ EOF
|
||||
break;
|
||||
|
||||
case 'stimulus': // Form displayed when applying a stimulus (state change)
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$id = utils::ReadParam('id', '');
|
||||
$sStimulus = utils::ReadParam('stimulus', '');
|
||||
@@ -1351,6 +1371,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'apply_stimulus': // Actual state change
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadPostedParam('class', '');
|
||||
$id = utils::ReadPostedParam('id', '');
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
@@ -1489,14 +1510,19 @@ EOF
|
||||
$sRelation = utils::ReadParam('relation', 'impact');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$aSourceObjects = array($oObj);
|
||||
|
||||
|
||||
$oP->set_title(MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName());
|
||||
|
||||
if ($sRelation == 'depends on')
|
||||
|
||||
$sPageId = "ui-relation-graph-".$sClass.'::'.$id;
|
||||
$sLabel = $oObj->GetName().' '.MetaModel::GetRelationLabel($sRelation);
|
||||
$sDescription = MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName();
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription);
|
||||
|
||||
if ($sRelation == 'depends on')
|
||||
{
|
||||
$sRelation = 'impacts';
|
||||
$sDirection = 'up';
|
||||
@@ -1561,6 +1587,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'kill_lock':
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '');
|
||||
$id = utils::ReadParam('id', '');
|
||||
iTopOwnershipLock::KillLock($sClass, $id);
|
||||
@@ -1571,6 +1598,7 @@ EOF
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'cancel': // An action was cancelled
|
||||
$oP->DisableBreadCrumb();
|
||||
$oP->set_title(Dict::S('UI:OperationCancelled'));
|
||||
$oP->add('<h1>'.Dict::S('UI:OperationCancelled').'</h1>');
|
||||
break;
|
||||
@@ -1582,7 +1610,6 @@ EOF
|
||||
$oMenuNode = ApplicationMenu::GetMenuNode(ApplicationMenu::GetMenuIndexById(ApplicationMenu::GetActiveNodeId()));
|
||||
if (is_object($oMenuNode))
|
||||
{
|
||||
|
||||
$oMenuNode->RenderContent($oP, $oAppContext->GetAsHash());
|
||||
$oP->set_title($oMenuNode->GetLabel());
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ $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');
|
||||
|
||||
// First part: select the class to search for
|
||||
$oP->add("<form>");
|
||||
$oP->add(Dict::S('UI:UniversalSearch:LabelSelectTheClass')."<select style=\"width: 150px;\" id=\"select_class\" name=\"baseClass\" onChange=\"this.form.submit();\">");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Execute and shows the data quality audit
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
/**
|
||||
@@ -156,10 +156,11 @@ try
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
|
||||
$oP = new iTopWebPage(Dict::S('UI:Audit:Title'));
|
||||
|
||||
|
||||
switch($operation)
|
||||
{
|
||||
case 'csv':
|
||||
$oP->DisableBreadCrumb();
|
||||
// Big result sets cause long OQL that cannot be passed (serialized) as a GET parameter
|
||||
// Therefore we don't use the standard "search_oql" operation of UI.php to display the CSV
|
||||
$iCategory = utils::ReadParam('category', '');
|
||||
@@ -221,6 +222,8 @@ try
|
||||
break;
|
||||
|
||||
case 'errors':
|
||||
$sTitle = 'Audit Errors';
|
||||
$oP->SetBreadCrumbEntry('ui-tool-auditerrors', $sTitle, '', '', utils::GetAbsoluteUrlAppRoot().'images/wrench.png');
|
||||
$iCategory = utils::ReadParam('category', '');
|
||||
$iRuleIndex = utils::ReadParam('rule', 0);
|
||||
|
||||
@@ -244,6 +247,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->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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
* CSV Import Page
|
||||
* Wizard to import CSV (or TSV) data into the database
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
try
|
||||
@@ -39,7 +39,8 @@ 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');
|
||||
|
||||
/**
|
||||
* Helper function to build a select from the list of valid classes for a given action
|
||||
* @param string $sName The name of the select in the HTML form
|
||||
|
||||
@@ -99,6 +99,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');
|
||||
|
||||
// Main program
|
||||
$sExpression = utils::ReadParam('expression', '', false, 'raw_data');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Presentation of the data model
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -570,6 +570,8 @@ $operation = utils::ReadParam('operation', '');
|
||||
$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');
|
||||
|
||||
$operation = utils::ReadParam('operation', '');
|
||||
|
||||
switch($operation)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2015 Combodo SARL
|
||||
// Copyright (C) 2015-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Export data specified by an OQL or a query phrasebook entry
|
||||
*
|
||||
* @copyright Copyright (C) 2015 Combodo SARL
|
||||
* @copyright Copyright (C) 2015-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -336,6 +336,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');
|
||||
}
|
||||
|
||||
if ($sExpression === null)
|
||||
|
||||
Reference in New Issue
Block a user