Browse Source

- Handle expansion/truncation of objects lists as part of the browser navigation history... implemented only for "simple lists" (Trac #73)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@771 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 14 năm trước cách đây
mục cha
commit
767a87554e

+ 58 - 16
application/cmdbabstract.class.inc.php

@@ -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()).'&nbsp;&nbsp;<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>&nbsp;&nbsp;<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>&nbsp;'.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());

+ 94 - 23
application/itopwebpage.class.inc.php

@@ -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, 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;
 		
-	// tabs
-	$("div[id^=tabbedContent]").tabs( { show: function(event, ui) {
-			window.location.href = ui.tab.href; // So that history can keep track of the tabs
-	} });
+		// 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);

+ 1 - 0
dictionaries/dictionary.itop.ui.php

@@ -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',

+ 1 - 0
dictionaries/fr.dictionary.itop.ui.php

@@ -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',

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 8 - 0
js/jquery.ba-bbq.min.js


+ 18 - 0
js/utils.js

@@ -19,6 +19,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
  */ 
 function ReloadBlock(divId, sStyle, sSerializedFilter, sExtraParams)

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác