|
@@ -0,0 +1,769 @@
|
|
|
+<?php
|
|
|
+// Copyright (C) 2012 Combodo SARL
|
|
|
+//
|
|
|
+// This program is free software; you can redistribute it and/or modify
|
|
|
+// it under the terms of the GNU General Public License as published by
|
|
|
+// the Free Software Foundation; version 3 of the License.
|
|
|
+//
|
|
|
+// This program is distributed in the hope that it will be useful,
|
|
|
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+// GNU General Public License for more details.
|
|
|
+//
|
|
|
+// You should have received a copy of the GNU General Public License
|
|
|
+// along with this program; if not, write to the Free Software
|
|
|
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
+/**
|
|
|
+ * Data Table to display a set of objects in a tabular manner in HTML
|
|
|
+ *
|
|
|
+ * @author Erwan Taloc <erwan.taloc@combodo.com>
|
|
|
+ * @author Romain Quetiez <romain.quetiez@combodo.com>
|
|
|
+ * @author Denis Flaven <denis.flaven@combodo.com>
|
|
|
+ * @license http://www.opensource.org/licenses/gpl-3.0.html GPL
|
|
|
+ */
|
|
|
+class DataTable
|
|
|
+{
|
|
|
+ protected $iListId; // Unique ID inside the web page
|
|
|
+ protected $sTableId; // identifier for sqve 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 = $iListId;
|
|
|
+ $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;
|
|
|
+ if ($this->sTableId != null)
|
|
|
+ {
|
|
|
+ // Identified tables can have their own specific settings
|
|
|
+ $oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oCustomSettings = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($oCustomSettings != null)
|
|
|
+ {
|
|
|
+ // Custom settings overload the default ones
|
|
|
+ $this->bUseCustomSettings = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oCustomSettings = $oSettings;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($oCustomSettings->iDefaultPageSize != -1)
|
|
|
+ {
|
|
|
+ $this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, true, $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);
|
|
|
+
|
|
|
+ $sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">\n";
|
|
|
+ $sHtml .= "<tr><td>$sObjectsCount</td><td class=\"menucontainer\">$sActionsMenu</td></tr>\n";
|
|
|
+ $sHtml .= "<tr><td>$sPager</td><td class=\"menucontainer\">$sToolkitMenu</td></tr>\n";
|
|
|
+ $sHtml .= "<tr><td class=\"datacontents\" colspan=\"2\">$sDataTable</td></tr>\n";
|
|
|
+ $sHtml .= "</table>\n";
|
|
|
+ $sHtml .= $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 <tbody> 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', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>');
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $sHtml = Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>');
|
|
|
+ }
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $sPagerStyle = '';
|
|
|
+ }
|
|
|
+
|
|
|
+ $sCombo = '<select class="pagesize">';
|
|
|
+ for($iPage = 1; $iPage < 5; $iPage++)
|
|
|
+ {
|
|
|
+ $sSelected = ($iPage == $iPageSize) ? 'selected="selected"' : '';
|
|
|
+ $iNbItems = $iPage * $iDefaultPageSize;
|
|
|
+ $sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
|
|
+ }
|
|
|
+ $sSelected = (-1 == $iPageSize) ? 'selected="selected"' : '';
|
|
|
+ $sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
|
|
+ $sCombo .= '</select>';
|
|
|
+
|
|
|
+ $sPages = Dict::S('UI:Pagination:PagesLabel');
|
|
|
+ $sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
|
|
|
+
|
|
|
+ $iNbPages = ($iPageSize == -1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
|
|
+ $aPagesToDisplay = array();
|
|
|
+ for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
|
|
|
+ {
|
|
|
+ if ($idx == 0)
|
|
|
+ {
|
|
|
+ $aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $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] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
|
|
|
+ }
|
|
|
+ $sPagesLinks = implode('', $aPagesToDisplay);
|
|
|
+ $sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
|
|
|
+
|
|
|
+ $sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
|
|
|
+ $sHtml =
|
|
|
+<<<EOF
|
|
|
+<div id="pager{$this->iListId}" class="pager" $sPagerStyle>
|
|
|
+ <p><table class="pagination"><tr><td>$sPages</td><td><img src="../images/first.png" class="first"/></td>
|
|
|
+ <td><img src="../images/prev.png" class="prev"/></td>
|
|
|
+ <td><span id="index">$sPagesLinks</span></td>
|
|
|
+ <td><img src="../images/next.png" class="next"/></td>
|
|
|
+ <td><img src="../images/last.png" class="last"/></td>
|
|
|
+ <td>$sPageSizeCombo</td>
|
|
|
+ <td><span id="loading"> </span></td>
|
|
|
+ </tr>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
|
|
|
+</div>
|
|
|
+EOF;
|
|
|
+ return $sHtml;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
|
|
+ {
|
|
|
+ $oMenuBlock = new MenuBlock($this->oSet->GetFilter());
|
|
|
+
|
|
|
+ $sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
|
|
+ return $sHtml;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
|
|
|
+ {
|
|
|
+ $sMenuTitle = Dict::S('UI:ConfigureThisList');
|
|
|
+ $sHtml = '<div class="itop_popup" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png"><ul><li><a onclick="$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'open\');">'.$sMenuTitle.'</a></li></li></ul></div>';
|
|
|
+ //$oPage->add_ready_script("$('#tk_{$this->iListId} > ul').popupmenu();");
|
|
|
+ return $sHtml;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink)
|
|
|
+ {
|
|
|
+ $sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
|
|
|
+ $sHtml .= "<form onsubmit=\"return false\">";
|
|
|
+ $sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
|
|
|
+ $sHtml .= "<p><input type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"> ".Dict::S('UI:UseDefaultSettings').'</p>';
|
|
|
+ $sHtml .= "<fieldset>";
|
|
|
+ $sChecked = ($this->bUseCustomSettings) ? 'checked': '';
|
|
|
+ $sHtml .= "<legend class=\"transparent\"><input type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"> ".Dict::S('UI:UseSpecificSettings')."</legend>";
|
|
|
+ $sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
|
|
|
+
|
|
|
+ $sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="10">').'</p>';
|
|
|
+ $sHtml .= "</fieldset>";
|
|
|
+ $sHtml .= "<fieldset>";
|
|
|
+ $sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
|
|
|
+ $sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
|
|
|
+ $sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
|
|
|
+ $sHtml .= "<legend class=\"transparent\"><input type=\"checkbox\" $sSaveChecked name=\"save_settings\"> ".Dict::S('UI:UseSavetheSettings')."</legend>";
|
|
|
+ $sHtml .= '<p><input type="radio" name="scope" '.$sCustomChecked.' value="this_list"> '.Dict::S('UI:OnlyForThisList').' ';
|
|
|
+ $sHtml .= '<input type="radio" name="scope" '.$sGenericChecked.' value="defaults"> '.Dict::S('UI:ForAllLists').'</p>';
|
|
|
+ $sHtml .= "</fieldset>";
|
|
|
+ $sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
|
|
|
+ $sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
|
|
|
+ $sHtml .= '</td><td style="text-align:center;">';
|
|
|
+ $sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
|
|
|
+ $sHtml .= '</td></tr></table>';
|
|
|
+ $sHtml .= "</form>";
|
|
|
+ $sHtml .= "</div>";
|
|
|
+
|
|
|
+ $sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
|
|
|
+ $oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
|
|
|
+
|
|
|
+ return $sHtml;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function GetAsHash($oSetting)
|
|
|
+ {
|
|
|
+ $aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
|
|
|
+ return $aSettings;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
|
|
|
+ {
|
|
|
+ $aAttribs = array();
|
|
|
+ if ($sSelectMode == 'multiple')
|
|
|
+ {
|
|
|
+ $aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
|
|
|
+ }
|
|
|
+ else if ($sSelectMode == 'single')
|
|
|
+ {
|
|
|
+ $aAttribs['form::select'] = array('label' => "", 'description' => '');
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
|
+ {
|
|
|
+ foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ if ($aData['checked'])
|
|
|
+ {
|
|
|
+ if ($sAttCode == '_key_')
|
|
|
+ {
|
|
|
+ $aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
|
|
|
+ $aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $aAttribs;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
|
|
+ {
|
|
|
+ $aValues = array();
|
|
|
+ $this->oSet->Seek(0);
|
|
|
+ $iMaxObjects = $iPageSize;
|
|
|
+ while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
|
|
+ {
|
|
|
+ $bFirstObject = true;
|
|
|
+ $aRow = array();
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
|
+ {
|
|
|
+ $sHilightClass = $aObjects[$sAlias]->GetHilightClass();
|
|
|
+ if ($sHilightClass != '')
|
|
|
+ {
|
|
|
+ $aRow['@class'] = $sHilightClass;
|
|
|
+ }
|
|
|
+ if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
|
|
|
+ {
|
|
|
+ if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
|
|
|
+ {
|
|
|
+ $sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $sDisabled = '';
|
|
|
+ }
|
|
|
+ if ($sSelectMode == 'single')
|
|
|
+ {
|
|
|
+ $aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ if ($aData['checked'])
|
|
|
+ {
|
|
|
+ if ($sAttCode == '_key_')
|
|
|
+ {
|
|
|
+ $aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $bFirstObject = false;
|
|
|
+ }
|
|
|
+ $aValues[] = $aRow;
|
|
|
+ $iMaxObjects--;
|
|
|
+ }
|
|
|
+ return $aValues;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
|
|
+ {
|
|
|
+ $iNbPages = ($iPageSize == -1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
|
|
+ $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
|
|
+
|
|
|
+ $aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
|
|
+
|
|
|
+ $sHtml = '<table class="listContainer">';
|
|
|
+
|
|
|
+ foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
|
|
+ {
|
|
|
+ $aExtraParams['query_params'][$sName] = $sValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $sHtml .= "<tr><td>";
|
|
|
+ $sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
|
|
+ $sHtml .= '</td></tr>';
|
|
|
+ $sHtml .= '</table>';
|
|
|
+ $iCount = $this->iNbObjects;
|
|
|
+
|
|
|
+ $aArgs = $this->oSet->GetArgs();
|
|
|
+ $sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
|
|
|
+ $sSelectModeJS = '';
|
|
|
+ $sHeaders = '';
|
|
|
+ if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
|
|
+ {
|
|
|
+ $sSelectModeJS = $sSelectMode;
|
|
|
+ $sHeaders = 'headers: { 0: {sorter: false}},';
|
|
|
+ }
|
|
|
+ $sDisplayKey = ($bViewLink) ? 'true' : 'false';
|
|
|
+ // Protect against duplicate elements in the Zlist
|
|
|
+ $aUniqueOrderedList = array();
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
|
+ {
|
|
|
+ foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ if ($aData['checked'])
|
|
|
+ {
|
|
|
+ $aUniqueOrderedList[$sAttCode] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $aUniqueOrderedList = array_keys($aUniqueOrderedList);
|
|
|
+ $sJSColumns = json_encode($aColumns);
|
|
|
+ $sJSClassAliases = json_encode($this->aClassAliases);
|
|
|
+ $sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
|
|
|
+ $this->oSet->ApplyParameters();
|
|
|
+ // Display the actual sort order of the table
|
|
|
+ $aRealSortOrder = $this->oSet->GetRealSortOrder();
|
|
|
+ $aDefaultSort = array();
|
|
|
+ $iColOffset = 0;
|
|
|
+ if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
|
|
+ {
|
|
|
+ $iColOffset += 1;
|
|
|
+ }
|
|
|
+ if ($bViewLink)
|
|
|
+ {
|
|
|
+ $iColOffset += 1;
|
|
|
+ }
|
|
|
+ foreach($aRealSortOrder as $sColCode => $bAscending)
|
|
|
+ {
|
|
|
+ $iPos = array_search($sColCode, $aUniqueOrderedList);
|
|
|
+ if ($iPos !== false)
|
|
|
+ {
|
|
|
+ $aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
|
|
+ }
|
|
|
+ else if($sColCode == 'friendlyname' && $bViewLink)
|
|
|
+ {
|
|
|
+ $aDefaultSort[] = "[".($iColOffset-1).",".($bAscending ? '0' : '1')."]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $sSortList = '';
|
|
|
+ if (count($aDefaultSort) > 0)
|
|
|
+ {
|
|
|
+ $sSortList = ', sortList: ['.implode(',', $aDefaultSort).']';
|
|
|
+ }
|
|
|
+ $sOQL = addslashes($this->oSet->GetFilter()->serialize());
|
|
|
+ $oPage->add_ready_script(
|
|
|
+<<<EOF
|
|
|
+var oTable = $('#{$this->iListId} table.listResults');
|
|
|
+oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList'] $sSortList} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
|
|
+EOF
|
|
|
+ );
|
|
|
+
|
|
|
+ //if ($iNbPages == 1)
|
|
|
+ if (false)
|
|
|
+ {
|
|
|
+ if (isset($aExtraParams['cssCount']))
|
|
|
+ {
|
|
|
+ $sCssCount = $aExtraParams['cssCount'];
|
|
|
+ if ($sSelectMode == 'single')
|
|
|
+ {
|
|
|
+ $sSelectSelector = ":radio[name^=selectObj]";
|
|
|
+ }
|
|
|
+ else if ($sSelectMode == 'multiple')
|
|
|
+ {
|
|
|
+ $sSelectSelector = ":checkbox[name^=selectObj]";
|
|
|
+ }
|
|
|
+ $oPage->add_ready_script(
|
|
|
+<<<EOF
|
|
|
+ $('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
|
|
|
+ var c = $('{$sCssCount}');
|
|
|
+ var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
|
|
|
+ c.val(v);
|
|
|
+ $('#{$this->iListId} .selectedCount').text(v);
|
|
|
+ c.trigger('change');
|
|
|
+ });
|
|
|
+EOF
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $sHtml;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
|
|
+ {
|
|
|
+ $iPageSize = $iDefaultPageSize;
|
|
|
+ $iPageIndex = 1 + floor($iStart / $iPageSize);
|
|
|
+ $sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
|
|
+ $oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class DataTableSettings implements Serializable
|
|
|
+{
|
|
|
+ public $aClassAliases;
|
|
|
+ public $sTableId;
|
|
|
+ public $iDefaultPageSize;
|
|
|
+ public $aColumns;
|
|
|
+
|
|
|
+ public function __construct($aClassAliases, $sTableId = null)
|
|
|
+ {
|
|
|
+ $this->aClassAliases = $aClassAliases;
|
|
|
+ $this->sTableId = $sTableId;
|
|
|
+ $this->iDefaultPageSize = 10;
|
|
|
+ $this->aColumns = array();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
|
|
|
+ {
|
|
|
+ $this->iDefaultPageSize = $iDefaultPageSize;
|
|
|
+ $this->aColumns = $aColumns;
|
|
|
+ $this->FixVisibleColumns();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function serialize()
|
|
|
+ {
|
|
|
+ // Save only the 'visible' columns
|
|
|
+ $aColumns = array();
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClass)
|
|
|
+ {
|
|
|
+ $aColumns[$sAlias] = array();
|
|
|
+ foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ unset($aData['label']); // Don't save the display name
|
|
|
+ unset($aData['alias']); // Don't save the alias (redundant)
|
|
|
+ unset($aData['code']); // Don't save the code (redundant)
|
|
|
+ if ($aData['checked'])
|
|
|
+ {
|
|
|
+ $aColumns[$sAlias][$sAttCode] = $aData;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return serialize(
|
|
|
+ array(
|
|
|
+ 'iDefaultPageSize' => $this->iDefaultPageSize,
|
|
|
+ 'aColumns' => $aColumns,
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ public function unserialize($sData)
|
|
|
+ {
|
|
|
+ $aData = unserialize($sData);
|
|
|
+ $this->iDefaultPageSize = $aData['iDefaultPageSize'];
|
|
|
+ $this->aColumns = $aData['aColumns'];
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClass)
|
|
|
+ {
|
|
|
+ foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ $aFieldData = false;
|
|
|
+ if ($sAttCode == '_key_')
|
|
|
+ {
|
|
|
+ $aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
|
|
|
+ }
|
|
|
+ else if (MetaModel::isValidAttCode($sClass, $sAttCode))
|
|
|
+ {
|
|
|
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
|
|
+ $aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($aFieldData)
|
|
|
+ {
|
|
|
+ $this->aColumns[$sAlias][$sAttCode] = $aFieldData;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ unset($this->aColumns[$sAlias][$sAttCode]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->FixVisibleColumns();
|
|
|
+ }
|
|
|
+
|
|
|
+ static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
|
|
|
+ {
|
|
|
+ $oSettings = new DataTableSettings($aClassAliases);
|
|
|
+ // Retrieve the class specific settings for each class/alias based on the 'list' ZList
|
|
|
+ //TODO let the caller pass some other default settings (another Zlist, extre fields...)
|
|
|
+ $aColumns = array();
|
|
|
+ foreach($aClassAliases as $sAlias => $sClass)
|
|
|
+ {
|
|
|
+ if ($aDefaultLists == null)
|
|
|
+ {
|
|
|
+ $aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $aList = $aDefaultLists[$sAlias];
|
|
|
+ }
|
|
|
+
|
|
|
+ $aSortOrder = MetaModel::GetOrderByDefault($sClass);
|
|
|
+ if ($bViewLink)
|
|
|
+ {
|
|
|
+ $sSort = 'none';
|
|
|
+ if(array_key_exists('friendlyname', $aSortOrder))
|
|
|
+ {
|
|
|
+ $sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
|
|
|
+ }
|
|
|
+ $aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
|
|
|
+ }
|
|
|
+ foreach($aList as $sAttCode)
|
|
|
+ {
|
|
|
+ $sSort = 'none';
|
|
|
+ if(array_key_exists($sAttCode, $aSortOrder))
|
|
|
+ {
|
|
|
+ $sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
|
|
|
+ }
|
|
|
+ $oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
|
|
|
+ $aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
|
|
|
+ if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // TODO retrieve the user default page size or the system wide setting
|
|
|
+ $iDefaultPageSize = MetaModel::GetConfig()->GetMinDisplayLimit();
|
|
|
+ $oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
|
|
|
+ return $oSettings;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function FixVisibleColumns()
|
|
|
+ {
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClass)
|
|
|
+ {
|
|
|
+ foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
|
|
+ {
|
|
|
+ // Remove non-existent columns
|
|
|
+ // TODO: check if the existing ones are still valid (in case their type changed)
|
|
|
+ if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
|
|
|
+ {
|
|
|
+ unset($this->aColumns[$sAlias][$sAttCode]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $aList = MetaModel::ListAttributeDefs($sClass);
|
|
|
+
|
|
|
+ // Add the other (non visible ones)
|
|
|
+ foreach($aList as $sAttCode => $oAttDef)
|
|
|
+ {
|
|
|
+ if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
|
|
|
+ {
|
|
|
+ $aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
|
|
|
+ if ($aFieldData) $this->aColumns[$sAlias][$sAttCode] = $aFieldData;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static public function GetTableSettings($aClassAliases, $sTableId = null)
|
|
|
+ {
|
|
|
+ $pref = null;
|
|
|
+ $oSettings = new DataTableSettings($aClassAliases, $sTableId);
|
|
|
+ if ($sTableId != null)
|
|
|
+ {
|
|
|
+ // An identified table, let's fetch its own settings (if any)
|
|
|
+ $pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($pref == null)
|
|
|
+ {
|
|
|
+ // Try the global preferred values for this class / set of classes
|
|
|
+ $pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
|
|
+ if ($pref == null)
|
|
|
+ {
|
|
|
+ // no such settings, use the default values provided by the data model
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $oSettings->unserialize($pref);
|
|
|
+ return $oSettings;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function Save()
|
|
|
+ {
|
|
|
+ if ($this->sTableId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
|
|
+
|
|
|
+ $sSettings = $this->serialize();
|
|
|
+ appUserPreferences::SetPref($this->GetPrefsKey($this->sTableId), $sSettings);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function SaveAsDefault()
|
|
|
+ {
|
|
|
+ $sSettings = $this->serialize();
|
|
|
+ appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Clear the preferences for this particular table
|
|
|
+ * @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
|
|
|
+ */
|
|
|
+ public function ResetToDefault($bResetAll)
|
|
|
+ {
|
|
|
+ if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
|
|
|
+ if ($bResetAll)
|
|
|
+ {
|
|
|
+ // Turn the key into a suitable PCRE pattern
|
|
|
+ $sKey = $this->GetPrefsKey(null);
|
|
|
+ $sPattern = '!^'.str_replace(array('*'), array('.*'), $sKey).'$!';
|
|
|
+ appUserPreferences::UnsetPref($sPattern, true);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetPrefsKey($sTableId = null)
|
|
|
+ {
|
|
|
+ if ($sTableId == null) $sTableId = '*';
|
|
|
+ $aKeys = array();
|
|
|
+ foreach($this->aClassAliases as $sAlias => $sClass)
|
|
|
+ {
|
|
|
+ $aKeys[] = $sAlias.'-'.$sClass;
|
|
|
+ }
|
|
|
+ return implode('/', $aKeys).'|'.$sTableId;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
|
|
|
+ {
|
|
|
+ $ret = false;
|
|
|
+ if ($sAttCode == '_key_')
|
|
|
+ {
|
|
|
+ $sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
|
|
|
+ $ret = array(
|
|
|
+ 'label' => $sLabel,
|
|
|
+ 'checked' => true,
|
|
|
+ 'disabled' => true,
|
|
|
+ 'alias' => $sAlias,
|
|
|
+ 'code' => $sAttCode,
|
|
|
+ 'sort' => $sSort,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else if (!$oAttDef->IsLinkSet())
|
|
|
+ {
|
|
|
+ $sLabel = $oAttDef->GetLabel();
|
|
|
+ if ($oAttDef->IsExternalKey())
|
|
|
+ {
|
|
|
+ $sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
|
|
|
+ }
|
|
|
+ else if ($oAttDef->IsExternalField())
|
|
|
+ {
|
|
|
+ $oExtAttDef = $oAttDef->GetExtAttDef();
|
|
|
+ $sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
|
|
|
+ }
|
|
|
+ elseif ($oAttDef instanceof AttributeFriendlyName)
|
|
|
+ {
|
|
|
+ $sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
|
|
+ }
|
|
|
+ $ret = array(
|
|
|
+ 'label' => $sLabel,
|
|
|
+ 'checked' => $bChecked,
|
|
|
+ 'disabled' => false,
|
|
|
+ 'alias' => $sAlias,
|
|
|
+ 'code' => $sAttCode,
|
|
|
+ 'sort' => $sSort,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return $ret;
|
|
|
+ }
|
|
|
+}
|