mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
- Handle expansion/truncation of objects lists as part of the browser navigation history... implemented only for "simple lists" (Trac #73)
SVN:trunk[771]
This commit is contained in:
@@ -240,7 +240,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
'object_id' => $this->GetKey(),
|
||||
'target_attr' => $oAttDef->GetExtKeyToRemote(),
|
||||
'view_link' => false,
|
||||
'menu' => false,
|
||||
'menu' => true,
|
||||
'display_limit' => true, // By default limit the list to speed up the initial load & display
|
||||
);
|
||||
}
|
||||
@@ -393,6 +393,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
}
|
||||
}
|
||||
$bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true;
|
||||
$bTruncated = isset($aExtraParams['truncated']) ? $aExtraParams['truncated'] == true : true;
|
||||
$bSelectMode = isset($aExtraParams['selection_mode']) ? $aExtraParams['selection_mode'] == true : false;
|
||||
$bSingleSelectMode = isset($aExtraParams['selection_type']) ? ($aExtraParams['selection_type'] == 'single') : false;
|
||||
$aExtraFields = isset($aExtraParams['extra_fields']) ? explode(',', trim($aExtraParams['extra_fields'])) : array();
|
||||
@@ -460,7 +461,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
$aValues = array();
|
||||
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
|
||||
$iMaxObjects = -1;
|
||||
if ($bDisplayLimit)
|
||||
if ($bDisplayLimit && $bTruncated)
|
||||
{
|
||||
if ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit())
|
||||
{
|
||||
@@ -501,26 +502,67 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
}
|
||||
$sHtml .= '<table class="listContainer">';
|
||||
$sColspan = '';
|
||||
if ($bDisplayLimit && ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit()))
|
||||
$divId = $aExtraParams['block_id'];
|
||||
$sFilter = $oSet->GetFilter()->serialize();
|
||||
$iMinDisplayLimit = utils::GetConfig()->GetMinDisplayLimit();
|
||||
$sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oSet->Count());
|
||||
$sLinkLabel = Dict::S('UI:DisplayAll');
|
||||
foreach($oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
$aExtraParams['query_params'][$sName] = $sValue;
|
||||
}
|
||||
if ($bDisplayLimit && $bTruncated && ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit()))
|
||||
{
|
||||
// list truncated
|
||||
$divId = $aExtraParams['block_id'];
|
||||
$sFilter = $oSet->GetFilter()->serialize();
|
||||
$aExtraParams['display_limit'] = false; // To expand the full list
|
||||
foreach($oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
$aExtraParams['query_params'][$sName] = $sValue;
|
||||
}
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
$sHtml .= '<tr class="containerHeader"><td>'.Dict::Format('UI:TruncatedResults', utils::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).' <a href="#open_'.$divId.'" onClick="Javascript:ReloadTruncatedList(\''.$divId.'\', \''.$sFilter.'\', \''.$sExtraParams.'\');">'.Dict::S('UI:DisplayAll').'</a></td><td>';
|
||||
$oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');");
|
||||
$oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');");
|
||||
$aExtraParams['display_limit'] = true;
|
||||
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$divId.'">'.$sCollapsedLabel.'</span> <a class="truncated" id="trc_'.$divId.'">'.$sLinkLabel.'</a></td><td>';
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$divId table.listResults').addClass('truncated');
|
||||
$('#$divId table.listResults tr:last td').addClass('truncated');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else if ($bDisplayLimit && !$bTruncated && ($oSet->Count() > utils::GetConfig()->GetMaxDisplayLimit()))
|
||||
{
|
||||
// Collapsible list
|
||||
$aExtraParams['display_limit'] = true;
|
||||
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$divId.'">'.Dict::Format('UI:CountOfResults', $oSet->Count()).'</span><a class="truncated" id="trc_'.$divId.'">'.Dict::S('UI:CollapseList').'</a></td><td>';
|
||||
}
|
||||
$aExtraParams['truncated'] = false; // To expand the full list when clicked
|
||||
$sExtraParamsExpand = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Handle truncated lists
|
||||
$('#trc_$divId').click(function()
|
||||
{
|
||||
var state = {};
|
||||
|
||||
var currentState = $.bbq.getState( this.id, true ) || 'close';
|
||||
// Toggle the state!
|
||||
if (currentState == 'close')
|
||||
{
|
||||
state[ this.id ] = 'open';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Full list
|
||||
$sHtml .= '<tr class="containerHeader"><td> '.Dict::Format('UI:CountOfResults', $oSet->Count()).'</td><td>';
|
||||
state[ this.id ] = 'close';
|
||||
}
|
||||
$.bbq.pushState( state );
|
||||
$(this).trigger(state[this.id]);
|
||||
});
|
||||
|
||||
$('#trc_$divId').bind('open', function()
|
||||
{
|
||||
ReloadTruncatedList('$divId', '$sFilter', '$sExtraParamsExpand');
|
||||
});
|
||||
|
||||
$('#trc_$divId').bind('close', function()
|
||||
{
|
||||
TruncateList('$divId', $iMinDisplayLimit, '$sCollapsedLabel', '$sLinkLabel');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
if ($bDisplayMenu)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($oSet->GetFilter());
|
||||
|
||||
@@ -53,7 +53,7 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
// $this->add_linked_stylesheet("../css/date.picker.css");
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.history.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
// $this->add_linked_script("../js/jquery.dimensions.js");
|
||||
$this->add_linked_script("../js/jquery.tablehover.js");
|
||||
$this->add_linked_script("../js/jquery.treeview.js");
|
||||
@@ -148,12 +148,73 @@ class iTopWebPage extends NiceWebPage
|
||||
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
|
||||
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// tabs
|
||||
$("div[id^=tabbedContent]").tabs( { show: function(event, ui) {
|
||||
window.location.href = ui.tab.href; // So that history can keep track of the tabs
|
||||
} });
|
||||
// Tabs, using JQuery BBQ to store the history
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change' });
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find( tab_a_selector ).click(function()
|
||||
{
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
|
||||
// Bind an event to window.onhashchange that, when the history state changes,
|
||||
// iterates over all tab widgets, changing the current tab as necessary.
|
||||
$(window).bind( 'hashchange', function(e)
|
||||
{
|
||||
// Iterate over all tab widgets.
|
||||
tabs.each(function()
|
||||
{
|
||||
// Get the index for this tab widget from the hash, based on the
|
||||
// appropriate id property. In jQuery 1.4, you should use e.getState()
|
||||
// instead of $.bbq.getState(). The second, 'true' argument coerces the
|
||||
// string value to a number.
|
||||
var idx = $.bbq.getState( this.id, true ) || 0;
|
||||
|
||||
// Select the appropriate tab for this tab widget by triggering the custom
|
||||
// event specified in the .tabs() init above (you could keep track of what
|
||||
// tab each widget is on using .data, and only select a tab if it has
|
||||
// changed).
|
||||
$(this).find( tab_a_selector ).eq( idx ).triggerHandler( 'change' );
|
||||
});
|
||||
|
||||
// Iterate over all truncated lists to find whether they are expanded or not
|
||||
$('a.truncated').each(function()
|
||||
{
|
||||
var state = $.bbq.getState( this.id, true ) || 'close';
|
||||
if (state == 'open')
|
||||
{
|
||||
$(this).trigger('open');
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).trigger('close');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// End of Tabs handling
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
$(".listResults").tablesorter( { headers: { 0:{sorter: false }}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$(".date-pick").datepicker({
|
||||
@@ -170,12 +231,12 @@ class iTopWebPage extends NiceWebPage
|
||||
$('#ModalDlg').dialog({ autoOpen: false, modal: true, width: 0.8*docWidth }); // JQuery UI dialogs
|
||||
ShowDebug();
|
||||
$('#logOffBtn>ul').popupmenu();
|
||||
$.history.init(history_callback);
|
||||
$("a[rel='history']").click(function()
|
||||
{
|
||||
$.history.load(this.href.replace(/^.*#/, ''));
|
||||
return false;
|
||||
});
|
||||
// $.history.init(history_callback);
|
||||
// $("a[rel='history']").click(function()
|
||||
// {
|
||||
// $.history.load(this.href.replace(/^.*#/, ''));
|
||||
// return false;
|
||||
// });
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
@@ -189,17 +250,17 @@ EOF
|
||||
$sUserPrefs = appUserPreferences::GetAsJSON();
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
// for JQuery history
|
||||
function history_callback(hash)
|
||||
{
|
||||
// do stuff that loads page content based on hash variable
|
||||
var aMatches = /^tab_(.*)$/.exec(hash);
|
||||
if (aMatches != null)
|
||||
{
|
||||
var tab = $('#'+hash);
|
||||
tab.parents('div[id^=tabbedContent]:first').tabs('select', aMatches[1]);
|
||||
}
|
||||
}
|
||||
// // for JQuery history
|
||||
// function history_callback(hash)
|
||||
// {
|
||||
// // do stuff that loads page content based on hash variable
|
||||
// var aMatches = /^tab_(.*)$/.exec(hash);
|
||||
// if (aMatches != null)
|
||||
// {
|
||||
// var tab = $('#'+hash);
|
||||
// tab.parents('div[id^=tabbedContent]:first').tabs('select', aMatches[1]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// For automplete
|
||||
function findValue(li) {
|
||||
@@ -358,6 +419,16 @@ EOF
|
||||
public function output()
|
||||
{
|
||||
$this->DisplayMenu(); // Compute the menu
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
EOF
|
||||
);
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
|
||||
@@ -412,6 +412,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:SelectAllToggle+' => 'Select / Deselect All',
|
||||
'UI:TruncatedResults' => '%1$d objects displayed out of %2$d',
|
||||
'UI:DisplayAll' => 'Display All',
|
||||
'UI:CollapseList' => 'Collapse',
|
||||
'UI:CountOfResults' => '%1$d object(s)',
|
||||
'UI:ChangesLogTitle' => 'Changes log (%1$d):',
|
||||
'UI:EmptyChangesLogTitle' => 'Changes log is empty',
|
||||
|
||||
@@ -412,6 +412,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:SelectAllToggle+' => 'Tout Sélectionner / Tout Désélectionner',
|
||||
'UI:TruncatedResults' => '%1$d objets affichés sur %2$d',
|
||||
'UI:DisplayAll' => 'Tout afficher',
|
||||
'UI:CollapseList' => 'Refermer',
|
||||
'UI:CountOfResults' => '%1$d objet(s)',
|
||||
'UI:ChangesLogTitle' => 'Liste de modifications (%1$d):',
|
||||
'UI:EmptyChangesLogTitle' => 'Aucune modification',
|
||||
|
||||
18
js/jquery.ba-bbq.min.js
vendored
Normal file
18
js/jquery.ba-bbq.min.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
||||
* http://benalman.com/projects/jquery-bbq-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M<N?O[P]||(R[M+1]&&isNaN(R[M+1])?{}:[]):J}}else{if($.isArray(H[P])){H[P].push(J)}else{if(H[P]!==i){H[P]=[H[P],J]}else{H[P]=J}}}}else{if(P){H[P]=F?i:""}}});return H};function z(H,F,G){if(F===i||typeof F==="boolean"){G=F;F=a[H?D:A]()}else{F=E(F)?F.replace(H?w:x,""):F}return l(F,G)}l[A]=B(z,0);l[D]=v=B(z,1);$[y]||($[y]=function(F){return $.extend(C,F)})({a:k,base:k,iframe:t,img:t,input:t,form:"action",link:k,script:t});j=$[y];function s(I,G,H,F){if(!E(H)&&typeof H!=="object"){F=H;H=G;G=i}return this.each(function(){var L=$(this),J=G||j()[(this.nodeName||"").toLowerCase()]||"",K=J&&L.attr(J)||"";L.attr(J,a[I](K,H,F))})}$.fn[A]=B(s,A);$.fn[D]=B(s,D);b.pushState=q=function(I,F){if(E(I)&&/^#/.test(I)&&F===i){F=2}var H=I!==i,G=c(p[g][k],H?I:{},H?F:2);p[g][k]=G+(/#/.test(G)?"":"#")};b.getState=u=function(F,G){return F===i||typeof F==="boolean"?v(F):v(G)[F]};b.removeState=function(F){var G={};if(F!==i){G=u();$.each($.isArray(F)?F:arguments,function(I,H){delete G[H]})}q(G,2)};e[d]=$.extend(e[d],{add:function(F){var H;function G(J){var I=J[D]=c();J.getState=function(K,L){return K===i||typeof K==="boolean"?l(I,K):l(I,L)[K]};H.apply(this,arguments)}if($.isFunction(F)){H=F;return G}else{H=F.handler;F.handler=G}}})})(jQuery,this);
|
||||
/*
|
||||
* jQuery hashchange event - v1.2 - 2/11/2010
|
||||
* http://benalman.com/projects/jquery-hashchange-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this);
|
||||
18
js/utils.js
18
js/utils.js
@@ -18,6 +18,24 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Truncate a previously expanded list !
|
||||
*/
|
||||
function TruncateList(divId, iLimit, sNewLabel, sLinkLabel)
|
||||
{
|
||||
var iCount = 0;
|
||||
$('#'+divId+' table.listResults tr').each( function(){
|
||||
if (iCount > iLimit)
|
||||
{
|
||||
$(this).remove();
|
||||
}
|
||||
iCount++;
|
||||
});
|
||||
$('#lbl_'+divId).html(sNewLabel);
|
||||
$('#'+divId+' table.listResults tr:last td').addClass('truncated');
|
||||
$('#'+divId+' table.listResults').addClass('truncated');
|
||||
$('#trc_'+divId).html(sLinkLabel);
|
||||
}
|
||||
/**
|
||||
* Reload any block -- used for periodic auto-reload
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user