/** * Data Table to display a set of objects in a tabular manner in HTML * * @copyright Copyright (C) 2010-2015 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ class DataTable { protected $iListId; // Unique ID inside the web page protected $sTableId; // identifier for saving the settings (combined with the class aliases) protected $oSet; // The set of objects to display protected $aClassAliases; // The aliases (alias => class) inside the set protected $iNbObjects; // Total number of objects inthe set protected $bUseCustomSettings; // Whether or not the current display uses custom settings protected $oDefaultSettings; // the default settings for displaying such a list /** * @param $iListId mixed Unique ID for this div/table in the page * @param $oSet DBObjectSet The set of data to display * @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName * @param $sTableId mixed A string (or null) identifying this table in order to persist its settings */ public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null) { $this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery $this->oSet = $oSet; $this->aClassAliases = $aClassAliases; $this->sTableId = $sTableId; $this->iNbObjects = $oSet->Count(); $this->bUseCustomSettings = false; $this->oDefaultSettings = null; } public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams) { $this->oDefaultSettings = $oSettings; // Identified tables can have their own specific settings $oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId); if ($oCustomSettings != null) { // Custom settings overload the default ones $this->bUseCustomSettings = true; if ($this->oDefaultSettings->iDefaultPageSize == 0) { $oCustomSettings->iDefaultPageSize = 0; } } else { $oCustomSettings = $oSettings; } if ($oCustomSettings->iDefaultPageSize > 0) { $this->oSet->SetLimit($oCustomSettings->iDefaultPageSize); } $this->oSet->SetOrderBy($oCustomSettings->GetSortOrder()); // Load only the requested columns $aColumnsToLoad = array(); foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo) { foreach($aColumnsInfo as $sAttCode => $aData) { if ($sAttCode != '_key_') { if ($aData['checked']) { $aColumnsToLoad[$sAlias][] = $sAttCode; } else { // See if this column is a must to load $sClass = $this->aClassAliases[$sAlias]; $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); if ($oAttDef->alwaysLoadInTables()) { $aColumnsToLoad[$sAlias][] = $sAttCode; } } } } } $this->oSet->OptimizeColumnLoad($aColumnsToLoad); $bToolkitMenu = true; if (isset($aExtraParams['toolkit_menu'])) { $bToolkitMenu = (bool) $aExtraParams['toolkit_menu']; } if (UserRights::IsPortalUser()) { // Portal users have a limited access to data, for now they can only see what's configured for them $bToolkitMenu = false; } return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams); } public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams) { $sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode); $sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex); $sActionsMenu = ''; $sToolkitMenu = ''; if ($bActionsMenu) { $sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams); } if ($bToolkitMenu) { $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams); } $sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize); $sHtml = "iListId}\" class=\"datatable\">"; $sHtml .= ""; $sHtml .= ""; $sHtml .= "
"; $sHtml .= ""; $sHtml .= ""; $sHtml .= "$sPager"; $sHtml .= "
$sObjectsCount$sToolkitMenu $sActionsMenu
"; $sHtml .= "
$sDataTable
\n"; $oPage->add_at_the_end($sConfigDlg); $aOptions = array( 'sPersistentId' => '', 'sFilter' => $this->oSet->GetFilter()->serialize(), 'oColumns' => $aColumns, 'sSelectMode' => $sSelectMode, 'sViewLink' => ($bViewLink ? 'true' : 'false'), 'iNbObjects' => $this->iNbObjects, 'iDefaultPageSize' => $iDefaultPageSize, 'iPageSize' => $iPageSize, 'iPageIndex' => $iPageIndex, 'oClassAliases' => $this->aClassAliases, 'sTableId' => $this->sTableId, 'oExtraParams' => $aExtraParams, 'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', 'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object... 'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object... 'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')), ); if($this->oDefaultSettings != null) { $aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings); } $sJSOptions = json_encode($aOptions); $oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);"); return $sHtml; } /** * When refreshing the body of a paginated table, get the rows of the table (inside the TBODY) * return string The HTML rows to insert inside the node */ public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams) { $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink); $aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $sHtml = ''; foreach($aValues as $aRow) { $sHtml .= $oPage->GetTableRow($aRow, $aAttribs); } return $sHtml; } protected function GetObjectCount(WebPage $oPage, $sSelectMode) { if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) { $sHtml = '
'.Dict::Format('UI:Pagination:HeaderSelection', ''.$this->iNbObjects.'', '0').'
'; } else { $sHtml = '
'.Dict::Format('UI:Pagination:HeaderNoSelection', ''.$this->iNbObjects.'').'
'; } return $sHtml; } protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex) { $sHtml = ''; if ($iPageSize < 1) // Display all { $sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI // WARNING: mPDF does not take the "display" style into account // when applied to a or a tag, so make sure you apply this to a div } else { $sPagerStyle = ''; } $sCombo = ''; $sPages = Dict::S('UI:Pagination:PagesLabel'); $sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo); $iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize); if ($iNbPages == 1) { // No need to display the pager $sPagerStyle = 'style="display:none"'; } $aPagesToDisplay = array(); for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++) { if ($idx == 0) { $aPagesToDisplay[$idx] = '1'; } else { $aPagesToDisplay[$idx] = "".(1+$idx).""; } } $iLastPageIdx = $iNbPages - 1; if (!isset($aPagesToDisplay[$iLastPageIdx])) { unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page $aPagesToDisplay[$iLastPageIdx] = "... $iNbPages"; } $sPagesLinks = implode('', $aPagesToDisplay); $sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']'; $sSelectionMode = ($iNbPages == 1) ? '' : 'positive'; $sHtml = <<
$sPages $sPagesLinks $sPageSizeCombo  
EOF; return $sHtml; } protected function GetActionsMenu(WebPage $oPage, $aExtraParams) { $oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list'); $sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId); return $sHtml; } protected function GetToolkitMenu(WebPage $oPage, $aExtraParams) { if (!$oPage->IsPrintableVersion()) { $sMenuTitle = Dict::S('UI:ConfigureThisList'); $sHtml = '