N°2847 - Tranform old itop datatable to jquery DataTable

This commit is contained in:
acognet
2020-11-04 13:36:20 +01:00
parent 7cfd888516
commit f718b26b7b
67 changed files with 2506 additions and 732 deletions

View File

@@ -20,6 +20,7 @@
use Combodo\iTop\Application\UI\Component\Alert\AlertFactory;
use Combodo\iTop\Application\UI\Component\Button\Button;
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\DataContainer\DataContainerFactory;
use Combodo\iTop\Application\UI\Component\Field\Field;
use Combodo\iTop\Application\UI\Component\FieldSet\FieldSet;
use Combodo\iTop\Application\UI\Component\Form\Form;
@@ -57,6 +58,7 @@ require_once(APPROOT.'sources/application/search/criterionconversionabstract.cla
require_once(APPROOT.'sources/application/search/criterionconversion/criteriontooql.class.inc.php');
require_once(APPROOT.'sources/application/search/criterionconversion/criteriontosearchform.class.inc.php');
use Combodo\iTop\Application\UI\Component\DataTable\DataTableFactory;
/**
* Class cmdbAbstractObject
*/
@@ -1042,7 +1044,7 @@ HTML
*/
public static function DisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oPage->add(self::GetDisplaySet($oPage, $oSet, $aExtraParams));
$oPage->AddUiBlock(self::GetDisplaySetBlock($oPage, $oSet, $aExtraParams));
}
/**
@@ -1100,14 +1102,16 @@ HTML
*
* @throws \CoreException*@throws \Exception
* @throws \ApplicationException
* @deprecated 3.0.0 use GetDisplaySetBlock
*/
public static function GetDisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
if ($oPage->IsPrintableVersion() || $oPage->is_pdf())
{
return self::GetDisplaySetForPrinting($oPage, $oSet, $aExtraParams);
$oPage->AddUiBlock(GetDisplaySetBlock( $oPage, $oSet, $aExtraParams ));
return "";
}
public static function GetDisplaySetBlock(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
if (empty($aExtraParams['currentId']))
{
$iListId = $oPage->GetUniqueId(); // Works only if not in an Ajax page !!
@@ -1117,136 +1121,10 @@ HTML
$iListId = $aExtraParams['currentId'];
}
// Initialize and check the parameters
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
$sLinkageAttribute = isset($aExtraParams['link_attr']) ? $aExtraParams['link_attr'] : '';
$iLinkedObjectId = isset($aExtraParams['object_id']) ? $aExtraParams['object_id'] : 0;
$sTargetAttr = isset($aExtraParams['target_attr']) ? $aExtraParams['target_attr'] : '';
if (!empty($sLinkageAttribute))
{
if ($iLinkedObjectId == 0)
{
// if 'links' mode is requested the id of the object to link to must be specified
throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_object_id'));
}
if ($sTargetAttr == '')
{
// if 'links' mode is requested the d of the object to link to must be specified
throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_target_attr'));
}
}
$bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true;
$bSelectMode = isset($aExtraParams['selection_mode']) ? $aExtraParams['selection_mode'] == true : false;
$bSingleSelectMode = isset($aExtraParams['selection_type']) ? ($aExtraParams['selection_type'] == 'single') : false;
$oDataTable = DataTableFactory::MakeForResult($oPage, $iListId, $oSet, $aExtraParams);
$aExtraFieldsRaw = isset($aExtraParams['extra_fields']) ? explode(',',
trim($aExtraParams['extra_fields'])) : array();
$aExtraFields = array();
foreach($aExtraFieldsRaw as $sFieldName)
{
// Ignore attributes not of the main queried class
if (preg_match('/^(.*)\.(.*)$/', $sFieldName, $aMatches))
{
$sClassAlias = $aMatches[1];
$sAttCode = $aMatches[2];
if ($sClassAlias == $oSet->GetFilter()->GetClassAlias())
{
$aExtraFields[] = $sAttCode;
}
}
else
{
$aExtraFields[] = $sFieldName;
}
}
$sClassName = $oSet->GetFilter()->GetClass();
$sZListName = isset($aExtraParams['zlist']) ? ($aExtraParams['zlist']) : 'list';
if ($sZListName !== false)
{
$aList = self::FlattenZList(MetaModel::GetZListItems($sClassName, $sZListName));
$aList = array_merge($aList, $aExtraFields);
}
else
{
$aList = $aExtraFields;
}
// Filter the list to removed linked set since we are not able to display them here
foreach($aList as $index => $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet)
{
// Removed from the display list
unset($aList[$index]);
}
}
if (!empty($sLinkageAttribute))
{
// The set to display is in fact a set of links between the object specified in the $sLinkageAttribute
// and other objects...
// The display will then group all the attributes related to the link itself:
// | Link_attr1 | link_attr2 | ... || Object_attr1 | Object_attr2 | Object_attr3 | .. | Object_attr_n |
$aDisplayList = array();
$aAttDefs = MetaModel::ListAttributeDefs($sClassName);
assert(isset($aAttDefs[$sLinkageAttribute]));
$oAttDef = $aAttDefs[$sLinkageAttribute];
assert($oAttDef->IsExternalKey());
// First display all the attributes specific to the link record
foreach($aList as $sLinkAttCode)
{
$oLinkAttDef = $aAttDefs[$sLinkAttCode];
if ((!$oLinkAttDef->IsExternalKey()) && (!$oLinkAttDef->IsExternalField()))
{
$aDisplayList[] = $sLinkAttCode;
}
}
// Then display all the attributes neither specific to the link record nor to the 'linkage' object (because the latter are constant)
foreach($aList as $sLinkAttCode)
{
$oLinkAttDef = $aAttDefs[$sLinkAttCode];
if (($oLinkAttDef->IsExternalKey() && ($sLinkAttCode != $sLinkageAttribute))
|| ($oLinkAttDef->IsExternalField() && ($oLinkAttDef->GetKeyAttCode() != $sLinkageAttribute)))
{
$aDisplayList[] = $sLinkAttCode;
}
}
// First display all the attributes specific to the link
// Then display all the attributes linked to the other end of the relationship
$aList = $aDisplayList;
}
$sSelectMode = 'none';
if ($bSelectMode)
{
$sSelectMode = $bSingleSelectMode ? 'single' : 'multiple';
}
$sClassAlias = $oSet->GetClassAlias();
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
$sTableId = isset($aExtraParams['table_id']) ? $aExtraParams['table_id'] : null;
$aClassAliases = array($sClassAlias => $sClassName);
$oDataTable = new DataTable($iListId, $oSet, $aClassAliases, $sTableId);
$oSettings = DataTableSettings::GetDataModelSettings($aClassAliases, $bViewLink, array($sClassAlias => $aList));
if ($bDisplayLimit)
{
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size',
MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->iDefaultPageSize = $iDefaultPageSize;
}
else
{
$oSettings->iDefaultPageSize = 0;
}
$oSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
return $oDataTable->Display($oPage, $oSettings, $bDisplayMenu, $sSelectMode, $bViewLink, $aExtraParams);
return $oDataTable;
}
/**
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
@@ -1265,6 +1143,7 @@ HTML
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @deprecated since 3.0.0
*/
public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{

View File

@@ -20,6 +20,8 @@
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');

View File

@@ -28,7 +28,7 @@ class DataTable
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 $iNbObjects; // Total number of objects in the set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
@@ -211,7 +211,7 @@ class DataTable
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
@@ -525,6 +525,7 @@ EOF;
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
@@ -872,396 +873,3 @@ class PrintableDataTable extends DataTable
return $sHtml;
}
}
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
/**
* DataTableSettings constructor.
*
* @param $aClassAliases
* @param null $sTableId
*/
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
/**
* @param $iDefaultPageSize
* @param $aSortOrder
* @param $aColumns
*/
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
/**
* @return string
*/
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,
)
);
}
/**
* @param string $sData
*
* @throws \Exception
*/
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();
}
/**
* @param $aClassAliases
* @param $bViewLink
* @param $aDefaultLists
*
* @return \DataTableSettings
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public static 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';
}
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
if(array_key_exists($sNormalizedFName, $aSortOrder))
{
$sSort = $aSortOrder[$sNormalizedFName] ? '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;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
/**
* @throws \CoreException
*/
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
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), sorted in alphabetical order
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach($aTempData as $sLabel => $aFieldData)
{
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
/**
* @param $aClassAliases
* @param null $sTableId
* @param bool $bOnlyOnTable
*
* @return \DataTableSettings|null
* @throws \Exception
*/
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
{
$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)
{
if (!$bOnlyOnTable)
{
// 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;
}
/**
* @return array
*/
public function GetSortOrder()
{
$aSortOrder = array();
foreach($this->aColumns as $sAlias => $aColumns)
{
foreach($aColumns as $aColumn)
{
if ($aColumn['sort'] != 'none')
{
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
/**
* @param null $sTargetTableId
*
* @return bool
*/
public function Save($sTargetTableId = null)
{
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
return true;
}
/**
* @return bool
*/
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); // escape the | character
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
}
else
{
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
/**
* @param null $sTableId
*
* @return string
*/
protected function GetPrefsKey($sTableId = null)
{
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
}
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
{
if ($sTableId === null)
{
$sTableId = '*';
}
$aKeys = array();
foreach($aClassAliases as $sAlias => $sClass)
{
$aKeys[] = $sAlias.'-'.$sClass;
}
return implode('/', $aKeys).'|'.$sTableId;
}
/**
* @param $sAlias
* @param $sAttCode
* @param $oAttDef
* @param $bChecked
* @param $sSort
*
* @return array|bool
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
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())
{
if ($oAttDef->IsFriendlyName())
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
else
{
$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;
}
}

View File

@@ -20,6 +20,7 @@
use Combodo\iTop\Application\UI\Component\Badge\BadgeFactory;
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\Dashlet\DashletFactory;
use Combodo\iTop\Application\UI\Component\DataTable\DataTableFactory;
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
use Combodo\iTop\Application\UI\iUIBlock;
@@ -238,18 +239,15 @@ class DisplayBlock
$sFilter = addslashes($this->m_oFilter->serialize(false, $aQueryParams)); // Used either for asynchronous or auto_reload
if (!$this->m_bAsynchronous) {
// render now
$oHtml->AddHtml("<div id=\"$sId\" class=\"display_block\" >\n");
try {
$oHtml->AddSubBlock($this->GetRenderContent($oPage, $aExtraParams, $sId));
} catch (Exception $e) {
IssueLog::Error('Exception during GetDisplay: '.$e->getMessage());
}
$oHtml->AddHtml("</div>\n");
} else {
// render it as an Ajax (asynchronous) call
$oHtml->AddHtml("<div id=\"$sId\" class=\"display_block loading\">\n");
$oHtml->AddCSSClasses("display_block loading");
$oHtml->AddHtml($oPage->GetP("<img src=\"../images/indicator_arrows.gif\"> ".Dict::S('UI:Loading')));
$oHtml->AddHtml("</div>\n");
$oPage->add_script('
$.post("ajax.render.php?style='.$this->m_sStyle.'",
{ operation: "ajax", filter: "'.$sFilter.'", extra_params: "'.$sExtraParams.'" },
@@ -573,7 +571,16 @@ class DisplayBlock
$index++;
}
$oSet = new CMDBObjectSet($oBlockFilter, array(), $aArgs);
$sHtml .= "<tr><td>".cmdbAbstractObject::GetDisplayExtendedSet($oPage, $oSet, $aExtraParams)."</td></tr>\n";
if (empty($aExtraParams['currentId']))
{
$iListId = $oPage->GetUniqueId(); // Works only if not in an Ajax page !!
}
else
{
$iListId = $aExtraParams['currentId'];
}
$oBlock = DataTableFactory::MakeForRendering( $iListId, $this->m_oSet, $aExtraParams);
$sHtml .= "<tr><td>".render_block($oBlock)."</td></tr>\n";
}
}
$sHtml .= "</table>\n";
@@ -599,7 +606,15 @@ class DisplayBlock
{
if($this->m_oSet->CountWithLimit(1) > 0)
{
$sHtml .= cmdbAbstractObject::GetDisplayExtendedSet($oPage, $this->m_oSet, $aExtraParams);
if (empty($aExtraParams['currentId']))
{
$iListId = $oPage->GetUniqueId(); // Works only if not in an Ajax page !!
}
else
{
$iListId = $aExtraParams['currentId'];
}
$oBlock = DataTableFactory::MakeForObject($oPage, $iListId, $this->m_oSet, $aExtraParams);
}
else
{
@@ -618,7 +633,7 @@ class DisplayBlock
// The list is made of only 1 class of objects, actions on the list are possible
if ( ($this->m_oSet->CountWithLimit(1)> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
{
$sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams);
$oBlock = cmdbAbstractObject::GetDisplaySetBlock($oPage, $this->m_oSet, $aExtraParams);
}
else
{
@@ -784,10 +799,9 @@ class DisplayBlock
case 'search':
if (!$oPage->IsPrintableVersion())
{
$sHtml .= "<div id=\"ds_$sId\" class=\"search_box\">\n";
$aExtraParams['currentId'] = $sId;
$sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams);
$sHtml .= "</div>\n";
$oSearchForm = new \Combodo\iTop\Application\Search\SearchForm();
$oBlock = $oSearchForm->GetSearchFormUIBlock($oPage, $this->m_oSet, $aExtraParams);
}
break;
@@ -1800,7 +1814,7 @@ class MenuBlock extends DisplayBlock
}
if ($bToolkitMenu) {
$sLabel = Dict::S('UI:ConfigureThisList');
$aActions['iTop::ConfigureList'] = ['label' => $sLabel, 'url' => '#', 'onclick' => "$('#datatable_dlg_{$sId}').dialog('open');"];
$aActions['iTop::ConfigureList'] = ['label' => $sLabel, 'url' => '#', 'onclick' => "$('#datatable_dlg_datatable_{$sId}').dialog('open');"];
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $param, $aActions);
}
break;

View File

@@ -15,6 +15,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
/**

View File

@@ -184,7 +184,7 @@ class UILinksWidgetDirect
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$sRealClass = '';
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
@@ -294,7 +294,7 @@ class UILinksWidgetDirect
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
{
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
@@ -355,7 +355,6 @@ class UILinksWidgetDirect
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
<button type="button" class="cancel">{$sCancel}</button>&nbsp;&nbsp;<button type="button" class="ok" disabled="disabled">{$sAdd}</button>
</form>
</div>
HTML
);
}

View File

@@ -368,7 +368,8 @@ JS
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
{
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
$sHtml .= "<table class=\"listResults\">\n";
$sHtml .= "<table class=\"listResults\" id='dt_{$this->m_sAttCode}{$this->m_sNameSuffix}' width='100%'>\n";
$oP->add_ready_script("$('#dt_{$this->m_sAttCode}{$this->m_sNameSuffix}').DataTable({\"language\": {\"emptyTable\": \"".str_replace("\"","\\\"",Dict::S('UI:Message:EmptyList:UseAdd'))."\"},search:false});");
// Header
$sHtml .= "<thead>\n";
$sHtml .= "<tr>\n";
@@ -391,11 +392,11 @@ JS
{
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
//$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
$sHtml .= "</tbody>\n";
// Footer
$sHtml .= "</table>\n";
$sHtml .= "</table></br>\n";
return $sHtml;
}
@@ -463,6 +464,7 @@ JS
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
}
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
// To prevent adding forms inside the main form
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
@@ -513,7 +515,7 @@ JS
*/
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
{
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
@@ -555,14 +557,13 @@ JS
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_sAttCode}{$this->m_sNameSuffix}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');">&nbsp;&nbsp;<input id="btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}" disabled="disabled" type="button" onclick="return oWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');">&nbsp;&nbsp;
<input id="btn_ok_add_{$this->m_sAttCode}{$this->m_sNameSuffix}" disabled="disabled" type="button" onclick="return oWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
</div>
HTML
);
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."' , autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
}

View File

@@ -40,7 +40,6 @@ class UISearchFormForeignKeys
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
@@ -65,9 +64,9 @@ class UISearchFormForeignKeys
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">&nbsp;&nbsp;<input id="btn_ok_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">&nbsp;&nbsp;
<input id="btn_ok_add_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
</div>
HTML
);

View File

@@ -1273,6 +1273,15 @@ abstract class AttributeDefinition
{
return (string)$value;
}
/*
* return string
*/
public function GetRenderForDataTable(string $sClassAlias) :string
{
$sRenderFunction = "return data;";
return $sRenderFunction;
}
}
class AttributeDashboard extends AttributeDefinition
@@ -4906,6 +4915,11 @@ class AttributeEmailAddress extends AttributeString
return '<a class="mailto" href="mailto:'.$sValue.'"><span class="text_decoration '.$sUrlDecorationClass.'"></span>'.parent::GetAsHTML($sValue).'</a>';
}
public function GetRenderForDataTable(string $sClassAlias) :string
{
$sRenderFunction = "return '<a class=\'mailto\' href= \'mailto:'+data+'\'><span class=\'fas fa-envelope\'></span> '+data+'</a>' ;";
return $sRenderFunction;
}
}
/**
@@ -4992,6 +5006,12 @@ class AttributePhoneNumber extends AttributeString
return '<a class="tel" href="'.$sUrl.'"><span class="text_decoration '.$sUrlDecorationClass.'"></span>'.parent::GetAsHTML($sValue).'</a>';
}
public function GetRenderForDataTable(string $sClassAlias) :string
{
$sRenderFunction = "return '<a class=\'tel\' href= \'tel:'+data+'\'><span class=\'fas fa-phone\'></span> '+data+'</a>' ;";
return $sRenderFunction;
}
}
/**
@@ -6781,6 +6801,12 @@ class AttributeExternalKey extends AttributeDBFieldVoid
return DBObject::MakeHyperLink($this->GetTargetClass(), $sValue);
}
public function GetRenderForDataTable(string $sClassAlias) :string
{
$sRenderFunction = "return '<a class=\'object-ref-link\' href= \'UI.php?operation=details&class=".$this->m_aParams['targetclass']."&id='+data+'\'>'+row['".$sClassAlias."/".$this->m_sCode."_friendlyname']+'</a>' ;";
return $sRenderFunction;
}
}
/**

View File

@@ -18,6 +18,7 @@
@import "input/all";
@import "title";
@import "datatable";
@import "form";
@import "fieldset";
@import "field";

View File

@@ -0,0 +1,85 @@
.ibo-datatable {
padding-bottom: 2em;
padding-top: 2em;
thead tr th, tbody tr td {
line-height: 30px;
padding-right: 1em;
padding-left: 1em;
@extend %ibo-font-ral-nor-100;
a {
color: $ibo-color-primary-600;
}
}
tbody tr:nth-child(odd) {
background-color: $ibo-color-secondary-500;
}
}
.dataTables_length
{
position: relative;
float: right;
padding-top: 0.755em;
padding-right: 0.5em;
}
.dataTables_info
{
position: relative;
float: right;
padding-top: 0.755em;
padding-right: 2em;
padding-left: 0em;
}
.select-info{
padding-left: 2em;
}
.pagination
{
left: 1.21%;
right: 1.21%;
top: 91.58%;
bottom: 4.85%;
.paginate_button {
margin-left: 1em;
margin-right: 1em;
}
}
.dataTables_paginate
{
/* position: relative;*/
float: left;
padding-top: 0.755em;
padding-left: 2em;
}
.paginate_button {
box-sizing: border-box;
display: inline-block;
}
.paginate_button a{
color: $ibo-color-grey-800;
@extend %ibo-font-ral-nor-100;
}
.paginate_button a:hover {
color: $ibo-color-blue-grey-200;
}
.paginate_button.active a {
color: $ibo-color-grey-900;
border: 2px solid var(--ibo-color-grey-300);
background-color: $ibo-color-grey-200;
}
.ibo-datatable-toolbar {
/*position: relative;*/
height: 30px;
}
.ibo-criterion-area{
font-size: $ibo-font-size-50 ;
}
.ibo-search-form{
padding-top: $ibo-panel--spacing-top ;
}
.ibo-form-group{
position: fixed;
}

View File

@@ -79,4 +79,30 @@ $ibo-title--status-dot--border-radius: $ibo-border-radius-full !default;
color: map-get($aColors, 'secondary-color');
background-color: map-get($aColors, 'primary-color');
}
}
.ibo-title-for-dashlet {
padding-top: 2em;
}
.ibo-title-for-dashlet--title {
@extend %ibo-font-ral-nor-350;
}
.ibo-title-for-dashlet--content{
background-color: $ibo-color-white-100;
border-radius: 5px;
border: 1px solid ;
border-color:$ibo-color-grey-400;
padding-bottom:1em;
}
.ibo-title-separator{
border-radius: 5px 5px 0px 0px;
border-color:$ibo-color-blue-600;
color:$ibo-color-blue-600;
background-color:$ibo-color-blue-600;
border: 3px solid ;
margin:0;
padding:0;
}

View File

@@ -93,66 +93,66 @@
text-decoration: none;
}
table.datatable {
width: 100%;
border: 0;
padding: 0;
}
//table.datatable {
// width: 100%;
// border: 0;
// padding: 0;
//}
td.menucontainer {
text-align: right;
}
table.listResults {
padding: 0px;
border-top: 3px solid $frame-background-color;
border-left: 3px solid $frame-background-color;
border-bottom: 3px solid #e6e6e1;
border-right: 3px solid #e6e6e1;
width: 100%;
background-color: $white;
}
//table.listResults {
// padding: 0px;
// border-top: 3px solid $frame-background-color;
// border-left: 3px solid $frame-background-color;
// border-bottom: 3px solid #e6e6e1;
// border-right: 3px solid #e6e6e1;
// width: 100%;
// background-color: $white;
//}
table.listResults td {
padding: 2px;
}
//table.listResults td {
// padding: 2px;
//}
table.listResults td .view-image {
//table.listResults td .view-image {
// Counteract the forced dimensions (usefull for displaying in the details view)
width: inherit !important;
height: inherit !important;
// width: inherit !important;
// height: inherit !important;
img {
max-width: 48px !important;
max-height: 48px !important;
display: block;
margin-left: auto;
margin-right: auto;
}
}
// img {
// max-width: 48px !important;
// max-height: 48px !important;
// display: block;
// margin-left: auto;
// margin-right: auto;
// }
//}
table.listResults > tbody > tr.selected > * {
}
//table.listResults > tbody > tr.selected > * {
//}
table.listResults > tbody > tr > * {
transition: background-color 400ms linear;
}
//table.listResults > tbody > tr > * {
// transition: background-color 400ms linear;
//}
table.listResults > tbody > tr:hover > * {
cursor: pointer;
}
//table.listResults > tbody > tr:hover > * {
// cursor: pointer;
//}
table.listResults > tbody > tr.selected:hover > * {
//table.listResults > tbody > tr.selected:hover > * {
/* hover on lines is currently done toggling td.hover, and having a rule for links */
background-color: $brand-primary-lightest;
color: $text-color;
}
// background-color: $brand-primary-lightest;
// color: $text-color;
//}
table.listResults > tbody > tr:hover > * {
//table.listResults > tbody > tr:hover > * {
/* hover on lines is currently done toggling td.hover, and having a rule for links */
background-color: $table-hover-background;
color: $text-color;
}
// background-color: $table-hover-background;
// color: $text-color;
//}
.edit-image {
.view-image {
@@ -278,13 +278,13 @@
color: $text-color;
}
th {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 8pt;
color: $complement-color;
height: 20px;
background: $frame-background-color bottom repeat-x;
}
//th {
// font-family: Tahoma, Verdana, Arial, Helvetica;
// font-size: 8pt;
// color: $complement-color;
// height: 20px;
// background: $frame-background-color bottom repeat-x;
//}
th.header {
cursor: pointer;
@@ -986,14 +986,14 @@
}
.search_form_handler {
position: relative;
z-index: 10;
width: 100%;
margin-left: auto;
margin-right: auto;
font-size: 12px;
text-align: left; /* To compensate .search_box:text-align */
border: 1px solid $search-form-container-bg-color;
// position: relative;
// z-index: 10;
// width: 100%;
// margin-left: auto;
// margin-right: auto;
// font-size: 12px;
// text-align: left; /* To compensate .search_box:text-align */
// border: 1px solid $search-form-container-bg-color;
//transition: width 0.3s ease-in-out;
/* Sizing reset */
@@ -1137,7 +1137,6 @@
background-color: $white;
.sf_criterion_row {
position: relative;;
&:not(:first-child) {
margin-top: 20px;
@@ -1165,6 +1164,11 @@
.sf_criterion_group {
display: inline;
.sfc_fg_button,
.sfc_header {
border: 1px solid #E1E7EC; /* Must be equal to .search_form_criteria:margin-bottom + this:padding-bottom */
border-radius: 3px;
}
}
}
@@ -1197,7 +1201,6 @@
box-shadow: $box-shadow-regular;
}
.sfc_form_group,
.sfm_content {
position: absolute;
z-index: -1;

View File

@@ -31,12 +31,12 @@
{# - Bootstrap Datetime picker #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css'|add_itop_version }}" rel="stylesheet">
{# - Datatables #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/dataTables.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/fixedHeader.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/responsive.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/scroller.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/select.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/select.dataTables.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/dataTables.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/fixedHeader.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/responsive.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/scroller.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/select.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'lib/datatables/css/select.dataTables.min.css'|add_itop_version }}" rel="stylesheet">
{# - Font OpenSans #}
<link href="{{ app['combodo.absolute_url'] ~ 'css/font-open-sans/font-open-sans.css'|add_itop_version }}" rel="stylesheet">
{# - Font Combodo #}
@@ -112,13 +112,13 @@
{# Moment.js with locales#}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/moment-with-locales.min.js'|add_itop_version }}"></script>
{# Datatables #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/jquery.dataTables.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.bootstrap.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.fixedHeader.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.responsive.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.scroller.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.select.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/datetime-moment.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/jquery.dataTables.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/dataTables.bootstrap.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/dataTables.fixedHeader.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/dataTables.responsive.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/dataTables.scroller.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/dataTables.select.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'lib/datatables/js/datetime-moment.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/dataTables.accentNeutraliseForFilter.js'|add_itop_version }}"></script>
{# Export for Datatables #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/export.js'|add_itop_version }}"></script>

View File

@@ -1167,7 +1167,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'UI:ColumnsAndSortOrder' => 'Sloupce a jejich řazení:',
'UI:UseDefaultSettings' => 'Použít výchozí nastavení',
'UI:UseSpecificSettings' => 'Použít následující nastavení:',
'UI:Display_X_ItemsPerPage' => 'Zobrazit %1$s položek na stránku',
'UI:Display_X_ItemsPerPage_prefix' => 'Zobrazit',
'UI:Display_X_ItemsPerPage_suffix' => 'položek na stránku',
'UI:UseSavetheSettings' => 'Uložit nastavení',
'UI:OnlyForThisList' => 'Jen pro tento seznam',
'UI:ForAllLists' => 'Pro všechny seznamy',

View File

@@ -1156,7 +1156,8 @@ Ved tilknytningen til en trigger, bliver hver handling tildelt et "rækkefølge"
'UI:ColumnsAndSortOrder' => 'Kolonner og sortering:',
'UI:UseDefaultSettings' => 'Brug de anbefalede indstillinger',
'UI:UseSpecificSettings' => 'Brug følgende indstillinger:',
'UI:Display_X_ItemsPerPage' => 'Vis %1$s emner per side',
'UI:Display_X_ItemsPerPage_prefix' => 'Vis',
'UI:Display_X_ItemsPerPage_suffix' => 'emner per side',
'UI:UseSavetheSettings' => 'Gem indstillinger',
'UI:OnlyForThisList' => 'Kun for denne liste',
'UI:ForAllLists' => 'For alle lister',

View File

@@ -1154,7 +1154,8 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
'UI:ColumnsAndSortOrder' => 'Spalten und Sortierrheienfolge:',
'UI:UseDefaultSettings' => 'Verwende Default-Einstellungen',
'UI:UseSpecificSettings' => 'Verwende folgende Einstellungen:',
'UI:Display_X_ItemsPerPage' => '%1$s Elemente pro Seite anzeigen',
'UI:Display_X_ItemsPerPage_prefix' => '',
'UI:Display_X_ItemsPerPage_suffix' => 'Elemente pro Seite anzeigen',
'UI:UseSavetheSettings' => 'Einstellungen speichern',
'UI:OnlyForThisList' => 'Nur für diese Liste',
'UI:ForAllLists' => 'Standard für alle Listen',

View File

@@ -1173,7 +1173,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:ColumnsAndSortOrder' => 'Columns and sort order:',
'UI:UseDefaultSettings' => 'Use the Default Settings',
'UI:UseSpecificSettings' => 'Use the Following Settings:',
'UI:Display_X_ItemsPerPage' => 'Display %1$s items per page',
'UI:Display_X_ItemsPerPage_prefix' => 'Display',
'UI:Display_X_ItemsPerPage_suffix' => 'items per page',
'UI:UseSavetheSettings' => 'Save the Settings',
'UI:OnlyForThisList' => 'Only for this list',
'UI:ForAllLists' => 'Default for all lists',

View File

@@ -1169,7 +1169,8 @@ Cuando se asocien con un disparador, cada acción recibe un número de "orden",
'UI:ColumnsAndSortOrder' => 'Columnas y Ordenamiento:',
'UI:UseDefaultSettings' => 'Usar Configuración por Omisión',
'UI:UseSpecificSettings' => 'Usar la Siguiente Configuración:',
'UI:Display_X_ItemsPerPage' => 'Desplegar %1$s elementos por página',
'UI:Display_X_ItemsPerPage_prefix' => 'Desplegar',
'UI:Display_X_ItemsPerPage_suffix' => 'elementos por página',
'UI:UseSavetheSettings' => 'Guardar Configuraciones',
'UI:OnlyForThisList' => 'Sólo esta Lista',
'UI:ForAllLists' => 'Defecto en todas las listas',

View File

@@ -1153,7 +1153,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:ColumnsAndSortOrder' => 'Colonnes et ordre de tri:',
'UI:UseDefaultSettings' => 'Utiliser les réglages par défaut',
'UI:UseSpecificSettings' => 'Utiliser les réglages suivants:',
'UI:Display_X_ItemsPerPage' => 'Afficher %1$s éléments par page',
'UI:Display_X_ItemsPerPage_prefix' => 'Afficher',
'UI:Display_X_ItemsPerPage_suffix' => 'éléments par page',
'UI:UseSavetheSettings' => 'Enregistrer ces réglages',
'UI:OnlyForThisList' => 'Seulement pour cette liste',
'UI:ForAllLists' => 'Défaut pour toutes les listes',

View File

@@ -1154,7 +1154,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'UI:ColumnsAndSortOrder' => 'カラムと並び順:',
'UI:UseDefaultSettings' => '既定のセッティングを使用',
'UI:UseSpecificSettings' => '次のセッティングを使用:',
'UI:Display_X_ItemsPerPage' => '1ページに %1$s アイテムを表示',
'UI:Display_X_ItemsPerPage_prefix' => '1ページに',
'UI:Display_X_ItemsPerPage_suffix' => 'アイテムを表示',
'UI:UseSavetheSettings' => 'セッティングを保存',
'UI:OnlyForThisList' => 'このリストのみ',
'UI:ForAllLists' => 'すべてのリストのデフォルト',

View File

@@ -1177,7 +1177,8 @@ Bij die koppeling wordt aan elke actie een volgorde-nummer gegeven. Dit bepaalt
'UI:ColumnsAndSortOrder' => 'Kolommen en sorteervolgorde:',
'UI:UseDefaultSettings' => 'Gebruik de standaard instellingen',
'UI:UseSpecificSettings' => 'Gebruik de volgende instellingen:',
'UI:Display_X_ItemsPerPage' => 'Geef %1$s items per pagina weer',
'UI:Display_X_ItemsPerPage_prefix' => 'Geef',
'UI:Display_X_ItemsPerPage_suffix' => 'items per pagina weer',
'UI:UseSavetheSettings' => 'Sla de instellingen op',
'UI:OnlyForThisList' => 'Alleen voor deze lijst',
'UI:ForAllLists' => 'Standaard voor alle lijsten',

View File

@@ -1167,7 +1167,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:ColumnsAndSortOrder' => 'Colunas e ordem de classificação:',
'UI:UseDefaultSettings' => 'Use a configuração padrão',
'UI:UseSpecificSettings' => 'Use as seguintes configurações:',
'UI:Display_X_ItemsPerPage' => 'Mostrar %1$s itens por página',
'UI:Display_X_ItemsPerPage_prefix' => 'Mostrar',
'UI:Display_X_ItemsPerPage_suffix' => 'itens por página',
'UI:UseSavetheSettings' => 'Salvar configurações',
'UI:OnlyForThisList' => 'Somente para esta lista',
'UI:ForAllLists' => 'Para todas as listas',

View File

@@ -1145,7 +1145,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'UI:ColumnsAndSortOrder' => 'Колонки и порядок сортировки:',
'UI:UseDefaultSettings' => 'Использовать настройки по умолчанию',
'UI:UseSpecificSettings' => 'Использовать эти настройки:',
'UI:Display_X_ItemsPerPage' => 'Показывать %1$s элементов на странице',
'UI:Display_X_ItemsPerPage_prefix' => 'Показывать',
'UI:Display_X_ItemsPerPage_suffix' => 'элементов на странице',
'UI:UseSavetheSettings' => 'Сохранить настройки',
'UI:OnlyForThisList' => 'Только для текущего списка',
'UI:ForAllLists' => 'Для всех списков',

View File

@@ -1156,7 +1156,8 @@ Keď sú priradené spúštačom, každej akcii je dané číslo "príkazu", šp
'UI:ColumnsAndSortOrder' => 'Stĺpce a triediaci príkaz:',
'UI:UseDefaultSettings' => 'Použite štandardné nastavenia',
'UI:UseSpecificSettings' => 'Použite nasledovné nastavenia:',
'UI:Display_X_ItemsPerPage' => 'Zobraziť %1$s položiek na stránku',
'UI:Display_X_ItemsPerPage_prefix' => 'Zobraziť',
'UI:Display_X_ItemsPerPage_suffix' => 'položiek na stránku',
'UI:UseSavetheSettings' => 'Uložiť nastavenia',
'UI:OnlyForThisList' => 'Iba pre tento zoznam',
'UI:ForAllLists' => 'Pre všetky zoznamy',

View File

@@ -0,0 +1,33 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
// Global search
Dict::Add('EN US', 'English', 'English', array(
'UI:Datatables:Language:Processing' => 'Please wait...',
'UI:Datatables:Language:Search' => 'Filter:',
'UI:Datatables:Language:LengthMenu' => 'Showing _MENU_ out',
'UI:Datatables:Language:ZeroRecords' => 'No result',
'UI:Datatables:Language:Info' => 'of _TOTAL_ items',
'UI:Datatables:Language:InfoEmpty' => 'No information',
'UI:Datatables:Language:InfoFiltered' => 'filtered out of _MAX_ items',
'UI:Datatables:Language:EmptyTable' => 'No data available in this table',
'UI:Datatables:Language:DisplayLength:All' => 'All',
'UI:Datatables:Language:Sort:Ascending' => 'enable for an ascending sort',
'UI:Datatables:Language:Sort:Descending' => 'enable for a descending sort',
));

View File

@@ -1167,7 +1167,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'UI:ColumnsAndSortOrder' => '列和排序顺序:',
'UI:UseDefaultSettings' => '使用默认配置',
'UI:UseSpecificSettings' => '使用下面的配置:',
'UI:Display_X_ItemsPerPage' => '每页显示 %1$s 个项目',
'UI:Display_X_ItemsPerPage_prefix' => '每页显示',
'UI:Display_X_ItemsPerPage_suffix' => '个项目',
'UI:UseSavetheSettings' => '保存设置',
'UI:OnlyForThisList' => '仅这个列表',
'UI:ForAllLists' => '默认所有列表',

View File

@@ -1,4 +1,4 @@
# Deprecated in 2.8.0
# Deprecated in 3.0.0
* TabManager::GetCurrentTabLength()
* TabManager::TruncateTab()
@@ -6,8 +6,9 @@
* TabManager::RenderIntoContent()
* iTopWebPage::SelectTab()
*cmdbabstract->GetDisplaySet
*cmdbabstract->GetDisplayExtendedSet
# Modified in 2.8.0
# Modified in 3.0.0
* iTabbedPage::AddTabContainer -> one optional parameter added

125
js/dataTables.pipeline.js Normal file
View File

@@ -0,0 +1,125 @@
//
// Pipelining function for DataTables. To be used to the `ajax` option of DataTables
//
$.fn.dataTable.pipeline = function ( opts ) {
// Configuration options
var conf = $.extend( {
pages: 5, // number of pages to cache
url: '', // script url
data: null, // function or object with parameters to send to the server
// matching how `ajax.data` works in DataTables
method: 'GET' // Ajax HTTP method
}, opts );
// Private variables for storing the cache
var cacheLower = -1;
var cacheUpper = null;
var cacheLastRequest = null;
var cacheLastJson = null;
var draw_number = 1;
return function ( request, drawCallback, settings ) {
var ajax = false;
var requestStart = request.start;
var drawStart = request.start;
var requestLength = request.length;
if(request.start=undefined)
{
requestStart = settings._iDisplayStart;
drawStart = settings._iDisplayStart;
requestLength = settings._iDisplayLength;
}
var requestEnd = requestStart + requestLength;
if ( settings.clearCache ) {
// API requested that the cache be cleared
ajax = true;
settings.clearCache = false;
}
else if ( cacheLower < 0 || requestStart < cacheLower || requestEnd > cacheUpper ) {
// outside cached data - need to make a request
ajax = true;
}
else if ( JSON.stringify( request.order ) !== JSON.stringify( cacheLastRequest.order ) ||
JSON.stringify( request.columns ) !== JSON.stringify( cacheLastRequest.columns ) ||
JSON.stringify( request.search ) !== JSON.stringify( cacheLastRequest.search )
) {
// properties changed (ordering, columns, searching)
ajax = true;
}
else if(cacheLastJson == undefined || cacheLastJson.length==0)
{
ajax = true;
}
// Store the request for checking next time around
cacheLastRequest = $.extend( true, {}, request );
if ( ajax ) {
// Need data from the server
if ( requestStart < cacheLower ) {
requestStart = requestStart - (requestLength*(conf.pages-1));
if ( requestStart < 0 ) {
requestStart = 0;
}
}
cacheLower = requestStart;
cacheUpper = requestStart + (requestLength * conf.pages);
request.start = requestStart;
request.length = requestLength*conf.pages;
request.end = requestStart+ requestLength*conf.pages;
// Provide the same `data` options as DataTables.
if ( typeof conf.data === 'function' ) {
// As a function it is executed with the data object as an arg
// for manipulation. If an object is returned, it is used as the
// data object to submit
var d = conf.data( request );
if ( d ) {
$.extend( request, d );
}
}
else if ( $.isPlainObject( conf.data ) ) {
// As an object, the data given extends the default
$.extend( request, conf.data );
}
return $.ajax( {
"type": conf.method,
"url": conf.url,
"data": request,
"dataType": "json",
"cache": false,
"success": function ( json ) {
cacheLastJson = $.extend(true, {}, json);
if ( cacheLower != drawStart ) {
json.data.splice( 0, drawStart-cacheLower );
}
if ( requestLength >= -1 ) {
json.data.splice( requestLength, json.data.length );
}
drawCallback( json );
}
} );
}
else {
json = $.extend( true, {}, cacheLastJson );
json.draw = request.draw; // Update the echo for each response
json.data.splice( 0, requestStart-cacheLower );
json.data.splice( requestLength, json.data.length );
drawCallback(json);
}
}
};
// Register an API method that will empty the pipelined data, forcing an Ajax
// fetch on the next draw (i.e. `table.clearPipeline().draw()`)
$.fn.dataTable.Api.register( 'clearPipeline()', function () {
return this.iterator( 'table', function ( settings ) {
settings.clearCache = true;
} );
} );

359
js/dataTables.settings.js Normal file
View File

@@ -0,0 +1,359 @@
// jQuery UI style "widget" for selecting and sorting "fields"
$(function()
{
// the widget definition, where "itop" is the namespace,
// "datatable" the widget name
$.widget( "itop.DataTableSettings",
{
// default options
options:
{
sListId: '',
oColumns: {},
sSelectMode: '',
sViewLink: 'true',
iPageSize: -1,
oClassAliases: {},
sTableId : null,
oExtraParams: {},
sRenderUrl: 'index.php',
oRenderParameters: {},
oDefaultSettings: {},
oLabels: { moveup: 'Move Up', movedown: 'Move Down' }
},
// the constructor
_create: function(mydatatable, options)
{
this.aDlgStateParams = ['iDefaultPageSize', 'oColumns'];
console.warn('datatablesettings');
this.element.addClass('itop-datatable');
var me = this;
var bViewLink = (this.options.sViewLink == 'true');
$('#sfl_'+me.options.sListId).fieldsorter({hasKeyColumn: bViewLink, labels: this.options.oLabels, fields: this.options.oColumns, onChange: function() { me._onSpecificSettings(); } });
$('#datatable_dlg_'+me.options.sListId).find('input[name=page_size]').click(function() { me._onSpecificSettings(); });
$('#datatable_dlg_'+me.options.sListId).find('input[name=save_settings]').click(function() { me._updateSaveScope(); });
this.element.find('.itop_popup > ul li').popupmenu();
this._updateSaveScope();
this._saveDlgState();
},
// called when created, and later when changing options
_refresh: function()
{
oParams = this.options.oData;
oParams.operation = 'search_and_refresh';
oParams.start = 0;
oParams.end = this.options.iPageSize;
oParams.select_mode = this.options.sSelectMode;
oParams.display_key = this.options.sViewLink;
oParams.class_aliases = this.options.oClassAliases;
oParams.columns = this.options.oColumns;
var iSortCol = 0;
var aCurrentSort = [];
for(var k1 in oParams.columns) //Aliases
{
for(var k2 in oParams.columns[k1]) //Attribute codes
{
if (oParams.columns[k1][k2].sort != 'none')
{
oParams.sort_col = iSortCol;
oParams.sort_order = oParams.columns[k1][k2].sort;
aCurrentSort.push([iSortCol, (oParams.columns[k1][k2].sort == 'asc') ? 0 : 1]);
break; //TODO make this more generic, Sort on just one column for now
}
iSortCol++;
}
break; //TODO: DBObjectSet supports only sorting on the first alias of the set
}
oParams.list_id = this.options.sListId;
var me = this;
this.element.block();
$('#'+me.options.sListId).DataTable().ajax.reload();
$.post(this.options.sRenderUrl, oParams, function(data) {
// Nasty workaround to clear the pager's state for paginated lists !!!
// See jquery.tablesorter.pager.js / saveParams / restoreParams
if (window.pager_params)
{
window.pager_params['pager'+me.options.sListId] = undefined;
}
// End of workaround
console.warn("update:");
console.warn(data);
// try {
var toto = $('#'+me.options.sListId).parent().parent();
$('#'+me.options.sListId).DataTable().destroy(true);
var entete="";
var aOptions = JSON.parse(data);
$.each(aOptions[0]['allColumns'], function(i, item) {
$.each(item, function(j, champs) {
if(champs.checked == 'true') {
entete += "<th>"+champs.label+"</th>";
}
});
});
$.each(aOptions[0]['columns'], function(i, item) {
aOptions[0]["columns"][i]["render"]["display"] = new Function ( "data, type, row" , aOptions[0]["columns"][i]["render"]["display"]);
});
toto.append( "<table id=\""+me.options.sListId+"\" width=\"100%\" class=\"ibo-datatable\">" +
"<thead><tr>"+entete+"</tr></thead></table>" );
//$('#'+me.options.sListId).DataTable().clear();
//$('#'+me.options.sListId).empty();
aOptions[0]["lengthMenu"]= [[oParams.end, oParams.end*2, oParams.end*3, oParams.end*4, -1], [oParams.end, oParams.end*2, oParams.end*3, oParams.end*4, aOptions[0]["lengthMenu"]]];
aOptions[0]["ajax"]=eval(aOptions[0]["ajax"]);
$('#'+me.options.sListId).DataTable(aOptions[0]);
//me.element.find('.datacontents').html(data);
// restore the sort order on columns
//me.element.find('table.listResults').trigger('fakesorton', [aCurrentSort]);
/*} catch (e) {
// ugly hacks for IE 8/9 first...
if (!window.console) console.error = {};
if (!window.console.error) {
console.error = function () {
};
}
console.error("Can not inject data : "+data);
}*/
me.element.unblock();
}, 'html' );
},
_useDefaultSettings: function(bResetAll)
{
var oParams = this.options.oData;
oParams.operation = 'datatable_reset_settings';
oParams.table_id = this.options.sTableId;
oParams.defaults = bResetAll;
oParams.class_aliases = this.options.oClassAliases;
var me = this;
$.post(this.options.sRenderUrl, oParams, function(data) {
// Do nothing...
}, 'html' );
},
_saveSettings: function(bSaveAsDefaults)
{
var oParams = this.options.oData ;
oParams.operation = 'datatable_save_settings';
oParams.page_size = this.options.iPageSize;
oParams.table_id = this.options.sTableId;
oParams.defaults = bSaveAsDefaults;
oParams.columns = this.options.oColumns;
var iSortCol = 0;
var sSortOrder = '';
for(var i in this.options.oColumns)
{
if (this.options.oColumns[i].checked)
{
if (this.options.oColumns[i].sort != 'none')
{
sSortOrder = this.options.oColumns[i].sort;
}
else
{
iSortCol++;
}
}
}
/*A voir, je ne sais pas à quoi ça sert
if ((this.options.sSelectMode != '') && (this.options.sSelectMode != 'none'))
{
iSortCol++;
}*/
oParams.sort_col = iSortCol;
oParams.sort_order = sSortOrder;
var me = this;
$.post(this.options.sRenderUrl, oParams, function(data) {
// Do nothing...
}, 'html' );
},
onDlgOk: function()
{
var oOptions = {};
oSettings = $('#datatable_dlg_'+this.options.sListId).find('input[name=settings]:checked');
if (oSettings.val() == 'defaults')
{
oOptions = { iPageSize: this.options.oDefaultSettings.iDefaultPageSize,
oColumns: this.options.oDefaultSettings.oColumns
};
}
else
{
var oDisplayColumns = {};
var iColIdx = 0;
var iSortIdx = 0;
var sSortDirection = 'asc';
var oColumns = $('#datatable_dlg_'+this.options.sListId).find(':itop-fieldsorter').fieldsorter('get_params');
var iPageSize = parseInt($('#datatable_dlg_'+this.options.sListId+' input[name=page_size]').val(), 10);
oOptions = {oColumns: oColumns, iPageSize: iPageSize, iDefaultPageSize: iPageSize };
}
this._setOptions(oOptions);
// Check if we need to save the settings or not...
var oSaveCheck = $('#datatable_dlg_'+this.options.sListId).find('input[name=save_settings]');
var oSaveScope = $('#datatable_dlg_'+this.options.sListId).find('input[name=scope]:checked');
if (oSaveCheck.prop('checked'))
{
if (oSettings.val() == 'defaults')
{
this._useDefaultSettings((oSaveScope.val() == 'defaults'));
}
else
{
this._saveSettings((oSaveScope.val() == 'defaults'));
}
}
this._saveDlgState();
},
onDlgCancel: function()
{
this._restoreDlgState();
},
_onSpecificSettings: function()
{
$('#datatable_dlg_'+this.options.sListId).find('input.specific_settings').prop('checked', true);
},
_updateSaveScope: function()
{
var oSaveCheck = $('#datatable_dlg_'+this.options.sListId).find('input[name=save_settings]');
if (oSaveCheck.prop('checked'))
{
$('#datatable_dlg_'+this.options.sListId).find('input[name=scope]').each(function() {
if ($(this).attr('stay-disabled') != 'true')
{
$(this).prop('disabled', false);
}
});
}
else
{
$('#datatable_dlg_'+this.options.sListId).find('input[name=scope]').prop('disabled', true);
}
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element.removeClass('itop-datatable');
$('#sfl_'+this.options.sListId).remove();
$('#datatable_dlg_'+this.options.sListId).remove();
},
// _setOptions is called with a hash of all options that are changing
_setOptions: function()
{
// in 1.9 would use _superApply
this._superApply(arguments);
this._refresh();
},
// _setOption is called for each individual option that is changing
_setOption: function( key, value )
{
// in 1.9 would use _super
this._superApply(arguments);
},
UpdateState: function( config )
{
console.warn('datatablesettings:UpdateState');
var iPageSize = config.page_size;
if (iPageSize == -1)
{
iPageSize = 0;
}
this.options.iPageSize = iPageSize;
var iPos = 0;
for (alias in this.options.oColumns)
{
for (attcode in this.options.oColumns[alias])
{
this.options.oColumns[alias][attcode]['sort'] = 'none';
if (this.options.oColumns[alias][attcode]['checked'])
{
if (iPos == config.sort_index)
{
this.options.oColumns[alias][attcode]['sort'] = config.sort_order;
}
iPos++;
}
}
}
var dlgElement = $('#datatable_dlg_'+this.options.sListId);
dlgElement.find('input[name=page_size]').val(iPageSize);
dlgElement.find(':itop-fieldsorter').fieldsorter('option', { fields: this.options.oColumns });
},
_saveDlgState: function()
{
this.originalState = {};
for(k in this.aDlgStateParams)
{
this.originalState[this.aDlgStateParams[k]] = this.options[this.aDlgStateParams[k]];
}
this.originalState.oFields = $('#datatable_dlg_'+this.options.sListId).find(':itop-fieldsorter').fieldsorter('get_params');
},
_restoreDlgState: function()
{
var dlgElement = $('#datatable_dlg_'+this.options.sListId);
for(k in this.aDlgStateParams)
{
this._setOption(this.aDlgStateParams[k], this.originalState[this.aDlgStateParams[k]]);
}
dlgElement.find('input[name=page_size]').val(this.originalState.iDefaultPageSize);
dlgElement.find(':itop-fieldsorter').fieldsorter('option', { fields: this.originalState.oFields });
$('#datatable_dlg_'+this.options.sListId).unblock();
},
IsDialogOpen: function()
{
var oDlgOpen = $('#datatable_dlg_'+this.options.sListId+' :visible');
return (oDlgOpen.length > 0);
},
DoRefresh: function()
{
this._refresh();
},
GetMultipleSelectionParams: function()
{
var oRes = {};
oRes.selectionMode = '';
if (this.element.find(':input[name=selectionMode]').length > 0)
{
oRes.selectionMode = this.element.find(':input[name=selectionMode]').val();
}
oRes.selectObject = [];
this.element.find(':input[name^=selectObject]:checked').each(function() {
oRes.selectObject.push($(this).val());
});
oRes.storedSelection = [];
this.element.find(':input[name^=storedSelection]').each(function() {
oRes.storedSelection.push($(this).val());
});
return oRes;
}
});
});

View File

@@ -1,4 +1,5 @@
// jQuery UI style "widget" for selecting and sorting "fields"
//@deprecated
$(function()
{
// the widget definition, where "itop" is the namespace,

View File

@@ -193,7 +193,10 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
theMap['selectionMode'] = sMode;
$('#fs_SearchFormToAdd_'+me.id+' :input').each(
function (i) {
theMap[this.name] = this.value;
if(this.name !="")
{
theMap[this.name] = this.value;
}
}
);
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
@@ -206,10 +209,11 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
theMap[this.name].push(this.value);
$(this).remove(); // Remove the selection for the next time the dialog re-opens
});
theMap["storedSelection[]"]=eval("oSelectedItemsadd_"+me.id);
// Retrieve the 'filter' definition
var table = $('#ResultsToAdd_'+me.id).find('table.listResults')[0];
theMap['filter'] = table.config.filter;
theMap['extra_params'] = table.config.extra_params;
theMap['filter'] = $(':input[name=filter]', context).val();
theMap['extra_params'] = $(':input[name=extra_params]', context).val();
}
// else
// {

View File

@@ -380,7 +380,7 @@ $(function()
// Prepare base DOM structure
this.element
.append('<div class="sfc_header"><div class="sfc_title"></div><span class="sfc_toggle"><a class="fas fa-caret-down"' + ' href="#"></a></span></div>')
.append('<div class="sfc_form_group"><div class="sfc_fg_operators"></div><div class="sfc_fg_buttons"></div></div>');
.append('<div class="sfc_form_group ibo-form-group"><div class="sfc_fg_operators"></div><div class="sfc_fg_buttons"></div></div>');
// Bind events
// Note: No event to handle criteria closing when clicking outside of it as it is already handle by the form handler.

View File

@@ -203,8 +203,8 @@ $(function()
$('#ibo-breadcrumbs')
.breadcrumb('destroy')
.breadcrumb({
.breadcrumbs('destroy')
.breadcrumbs({
itop_instance_id: oData['breadcrumb_instance_id'],
max_count: oData['breadcrumb_max_count'],
new_entry: {
@@ -373,17 +373,17 @@ $(function()
{
oCriterionAreaElem = $('<div></div>').appendTo(this.element);
}
oCriterionAreaElem.addClass('sf_criterion_area');
oCriterionAreaElem.addClass('sf_criterion_area ibo-criterion-area');
this.elements.criterion_area = oCriterionAreaElem;
// Clean area
oCriterionAreaElem
.html('')
.append('<div class="sf_criterion_row"></div>');
.append('<div class="sf_criterion_row ibo-criterion-row"></div>');
// Prepare content
this._prepareMoreCriterionMenu();
this._prepareExistingCriterion();
this._prepareMoreCriterionMenu();
this._prepareSubmitButton();
},
// - Prepare "more" button
@@ -398,7 +398,7 @@ $(function()
// Header part
var oHeaderElem = $('<div class="sfm_header"></div>')
.append('<a class="sfm_toggler" href="#"><span class="sfm_tg_title">' + Dict.S('UI:Search:Criterion:MoreMenu:AddCriteria') + '</span><span class="sfm_tg_icon fas fa-plus"></span></a>')
.append('<a class="sfm_toggler" href="#"><span class="sfm_tg_icon fas fa-plus"></span></a>')
.appendTo(this.elements.more_criterion);
// Content part
@@ -695,7 +695,7 @@ $(function()
else
{
var oCriterionRowElem = $('<div></div>')
.addClass('sf_criterion_row')
.addClass('sf_criterion_row ibo-criterion-row')
.appendTo(this.elements.criterion_area);
}
@@ -706,7 +706,7 @@ $(function()
else
{
var oCriterionGroupElem = $('<div></div>')
.addClass('sf_criterion_group')
.addClass('sf_criterion_group ibo-criterion-group')
.appendTo(oCriterionRowElem);
}
@@ -754,7 +754,7 @@ $(function()
oResultAreaElem = $('<div class="display_block"></div>').insertAfter(this.element.closest('.display_block'));
}
}
oResultAreaElem.addClass('sf_results_area');
//oResultAreaElem.addClass('display_block sf_results_area');
// Make placeholder if nothing yet
if(oResultAreaElem.html() === '')

View File

@@ -262,11 +262,11 @@ function UpdateFileName(id, sNewFileName) {
* Reload a search form for the specified class
*/
function ReloadSearchForm(divId, sClassName, sBaseClass, sContext, sTableId, sExtraParams) {
var oDiv = $('#ds_'+divId);
var oDiv = $('#'+divId);
oDiv.block();
// deprecated in jQuery 1.8
//var oFormEvents = $('#ds_'+divId+' form').data('events');
var oForm = $('#ds_'+divId+' form');
var oForm = $('#'+divId+' form');
var oFormEvents = $._data(oForm[0], "events");
// Save the submit handlers
@@ -276,11 +276,11 @@ function ReloadSearchForm(divId, sClassName, sBaseClass, sContext, sTableId, sEx
aSubmit [index] = {data: oFormEvents.submit[index].data, namespace: oFormEvents.submit[index].namespace, handler: oFormEvents.submit[index].handler};
}
}
sAction = $('#ds_'+divId+' form').attr('action');
sAction = $('#'+divId+' form').attr('action');
// Save the current values in the form
var oMap = {};
$('#ds_'+divId+" form :input[name!='']").each(function () {
$('#'+divId+" form :input[name!='']").each(function () {
oMap[this.name] = this.value;
});
oMap.operation = 'search_form';

View File

@@ -161,6 +161,9 @@ return array(
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletContainer' => $baseDir . '/sources/application/UI/Component/Dashlet/DashletContainer.php',
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletFactory' => $baseDir . '/sources/application/UI/Component/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletHeaderStatic' => $baseDir . '/sources/application/UI/Component/Dashlet/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableBlock' => $baseDir . '/sources/application/UI/Component/DataTable/DataTable.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableFactory' => $baseDir . '/sources/application/UI/Component/DataTable/DataTableFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableSettings' => $baseDir . '/sources/application/UI/Component/DataTable/DataTableSettings.php',
'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => $baseDir . '/sources/application/UI/Component/FieldSet/FieldSet.php',
'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => $baseDir . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => $baseDir . '/sources/application/UI/Component/Form/Form.php',
@@ -331,7 +334,6 @@ return array(
'DashletProxy' => $baseDir . '/application/dashlet.class.inc.php',
'DashletUnknown' => $baseDir . '/application/dashlet.class.inc.php',
'DataTable' => $baseDir . '/application/datatable.class.inc.php',
'DataTableSettings' => $baseDir . '/application/datatable.class.inc.php',
'Datamatrix' => $vendorDir . '/combodo/tcpdf/include/barcodes/datamatrix.php',
'DateTimeFormat' => $baseDir . '/core/datetimeformat.class.inc.php',
'DeadLockLog' => $baseDir . '/core/log.class.inc.php',

View File

@@ -391,6 +391,9 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletContainer' => __DIR__ . '/../..' . '/sources/application/UI/Component/Dashlet/DashletContainer.php',
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\Dashlet\\DashletHeaderStatic' => __DIR__ . '/../..' . '/sources/application/UI/Component/Dashlet/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableBlock' => __DIR__ . '/../..' . '/sources/application/UI/Component/DataTable/DataTable.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/DataTable/DataTableFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\DataTable\\DataTableSettings' => __DIR__ . '/../..' . '/sources/application/UI/Component/DataTable/DataTableSettings.php',
'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => __DIR__ . '/../..' . '/sources/application/UI/Component/FieldSet/FieldSet.php',
'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => __DIR__ . '/../..' . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => __DIR__ . '/../..' . '/sources/application/UI/Component/Form/Form.php',
@@ -561,7 +564,6 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'DashletProxy' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletUnknown' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DataTable' => __DIR__ . '/../..' . '/application/datatable.class.inc.php',
'DataTableSettings' => __DIR__ . '/../..' . '/application/datatable.class.inc.php',
'Datamatrix' => __DIR__ . '/..' . '/combodo/tcpdf/include/barcodes/datamatrix.php',
'DateTimeFormat' => __DIR__ . '/../..' . '/core/datetimeformat.class.inc.php',
'DeadLockLog' => __DIR__ . '/../..' . '/core/log.class.inc.php',

View File

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 160 B

View File

Before

Width:  |  Height:  |  Size: 148 B

After

Width:  |  Height:  |  Size: 148 B

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

View File

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 158 B

View File

Before

Width:  |  Height:  |  Size: 146 B

After

Width:  |  Height:  |  Size: 146 B

View File

@@ -208,6 +208,7 @@ function SetObjectBreadCrumbEntry(DBObject $oObj, WebPage $oPage)
*/
function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '', $sFormat = '', $bDoSearch = true, $bSearchFormOpen = true)
{
$oBlockForm=null;
if ($bSearchForm)
{
$aParams = array('open' => $bSearchFormOpen, 'table_id' => '1');
@@ -215,22 +216,24 @@ function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '',
{
$aParams['baseClass'] = $sBaseClass;
}
$oBlock = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oP, 0);
$oBlockForm = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, $aParams);
if (!$bDoSearch)
{
$oBlockForm->Display($oP, 0);
}
}
if ($bDoSearch)
{
if (strtolower($sFormat) == 'csv')
{
$oBlock = new DisplayBlock($oFilter, 'csv', false);
$oBlock->Display($oP, 1);
// Adjust the size of the Textarea containing the CSV to fit almost all the remaining space
$oP->add_ready_script(" $('#1>textarea').height($('#1').parent().height() - $('#0').outerHeight() - 30).width( $('#1').parent().width() - 20);"); // adjust the size of the block
}
else
{
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, 1);
// Breadcrumb
//$iCount = $oBlock->GetDisplayedCount();
@@ -238,6 +241,22 @@ function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '',
$sLabel = MetaModel::GetName($oFilter->GetClass());
$oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
if ($bSearchForm) {
$oUIBlockForm=$oBlockForm->GetDisplay($oP,'0');
$sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
if($sTableId=='')
{
$sTableId = '1';
}
$oUIBlock=$oBlock->GetDisplay($oP, $sTableId);
$oUIBlock->AddCSSClasses("display_block sf_results_area");
//$oUIBlockForm->AddSubBlock($oUIBlock);
$oP->AddUiBlock($oUIBlockForm);
$oP->AddUiBlock($oUIBlock);
}
else {
$oBlock->Display($oP, 1);
}
}
}

View File

@@ -17,10 +17,12 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\UI\Layout\ActivityPanel\ActivityEntry\ActivityEntryFactory;
use Combodo\iTop\Controller\AjaxRenderController;
use Combodo\iTop\Renderer\BlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
use Combodo\iTop\Application\UI\Component\DataTable\DataTableFactory;
require_once('../approot.inc.php');
require_once(APPROOT.'application/application.inc.php');
@@ -67,7 +69,7 @@ try
}
LoginWebPage::DoLoginEx($sRequestedPortalId, false);
$oPage = new ajax_page("");
$oPage = new AjaxPage("");
$oPage->no_cache();
@@ -230,6 +232,190 @@ try
$oKPI->ComputeAndReport('Data fetch and format');
break;
case 'search_and_refresh':
$oPage->SetContentType('application/json');
$extraParams = utils::ReadParam('extra_param', '', false, 'raw_data');
$aExtraParams = array();
if (is_array($extraParams))
{
$aExtraParams = $extraParams;
}
else
{
$sExtraParams = stripslashes($extraParams);
if (!empty($sExtraParams))
{
$val = json_decode(str_replace("'", '"', $sExtraParams), true /* associative array */);
if ($val !== null)
{
$aExtraParams = $val;
}
}
}
$iLength = utils::ReadParam('end', 10);
$aColumns = utils::ReadParam('columns', array(), false, 'raw_data');
$sSelectMode = utils::ReadParam('select_mode', '');
$aResult = DataTableFactory::GetOptionsForRendering( $aColumns, $sSelectMode, $sFilter, $iLength, $aExtraParams);
$oPage->add(json_encode($aResult));
break;
case 'search':
$oPage->SetContentType('application/json');
$extraParams = utils::ReadParam('extra_param', '', false, 'raw_data');
$aExtraParams = array();
if (is_array($extraParams))
{
$aExtraParams = $extraParams;
}
else
{
$sExtraParams = stripslashes($extraParams);
if (!empty($sExtraParams))
{
$val = json_decode(str_replace("'", '"', $sExtraParams), true /* associative array */);
if ($val !== null)
{
$aExtraParams = $val;
}
}
}
if ($sEncoding == 'oql')
{
$oFilter = DBSearch::FromOQL($sFilter);
}
else
{
$oFilter = DBSearch::unserialize($sFilter);
}
$iStart = utils::ReadParam('start', 0);
$iEnd = utils::ReadParam('end', 1);
$iDrawNumber= utils::ReadParam('draw', 1);
$iSortCol = utils::ReadParam('sort_col', 'null');
$sSelectMode = utils::ReadParam('select_mode', '');
if (!empty($sSelectMode) && ($sSelectMode != 'none'))
{
// The first column is used for the selection (radio / checkbox) and is not sortable
$iSortCol--;
}
$bDisplayKey = utils::ReadParam('display_key', 'true') == 'true';
$aColumns = utils::ReadParam('columns', array(), false, 'raw_data');
$aClassAliases = utils::ReadParam('class_aliases', array());
$iListId = utils::ReadParam('list_id', 0);
// Filter the list to removed linked set since we are not able to display them here
$sIdName ="";
$aOrderBy = array();
$iSortIndex = 0;
$aColumnsLoad = array();
foreach($aClassAliases as $sAlias => $sClassName)
{
$aColumnsLoad[$sAlias] = array();
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'] == 'true')
{
$aColumns[$sAlias][$sAttCode]['checked'] = true;
if ($sAttCode == '_key_')
{
if($sIdName == ""){
$sIdName = $sAlias."/_key_";
}
if ($iSortCol == $iSortIndex)
{
if (!MetaModel::HasChildrenClasses($oFilter->GetClass()))
{
$aNameSpec = MetaModel::GetNameSpec($oFilter->GetClass());
if ($aNameSpec[0] == '%1$s')
{
// The name is made of a single column, let's sort according to the sort algorithm for this column
$aOrderBy[$sAlias.'.'.$aNameSpec[1][0]] = (utils::ReadParam('sort_order', 'asc') == 'asc');
}
else
{
$aOrderBy[$sAlias.'.'.'friendlyname'] = (utils::ReadParam('sort_order', 'asc') == 'asc');
}
}
else
{
$aOrderBy[$sAlias.'.'.'friendlyname'] = (utils::ReadParam('sort_order', 'asc') == 'asc');
}
}
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet)
{
// Removed from the display list
unset($aColumns[$sAlias][$sAttCode]);
}
else
{
$aColumnsLoad[$sAlias][] = $sAttCode;
}
if ($iSortCol == $iSortIndex)
{
if ($oAttDef->IsExternalKey())
{
$sSortCol = $sAttCode.'_friendlyname';
}
else
{
$sSortCol = $sAttCode;
}
$aOrderBy[$sAlias.'.'.$sSortCol] = (utils::ReadParam('sort_order', 'asc') == 'asc');
}
}
$iSortIndex++;
}
else
{
$aColumns[$sAlias][$sAttCode]['checked'] = false;
}
}
}
// Load only the requested columns
$oSet = new DBObjectSet($oFilter, $aOrderBy, $aExtraParams, null, $iEnd - $iStart, $iStart);
$oSet->OptimizeColumnLoad($aColumnsLoad);
if (isset($aExtraParams['show_obsolete_data'])) {
$bShowObsoleteData = $aExtraParams['show_obsolete_data'];
}
else {
$bShowObsoleteData = utils::ShowObsoleteData();
}
$oSet->SetShowObsoleteData($bShowObsoleteData);
$oKPI = new ExecutionKPI();
$aResult["draw"] = $iDrawNumber;
$aResult["recordsTotal"] = $oSet->Count() ;
$aResult["recordsFiltered"] = $oSet->Count() ;
$aResult["data"] = [];
while ($aObject = $oSet->FetchAssoc()) {
foreach($aClassAliases as $sAlias=>$sClass) {
foreach($aColumns[$sAlias] as $sAttCode => $oAttDef) {
if($sAttCode=="_key_") {
$aObj[$sAlias."/".$sAttCode ] = $aObject[$sAlias]->GetKey();
}
else {
$aObj[$sAlias."/".$sAttCode ] = $aObject[$sAlias]->Get($sAttCode);
}
}
}
if($sIdName!="")
{
$aObj["id" ] = $aObj[$sIdName];
}
array_push($aResult["data"], $aObj);
}
$oPage->add(json_encode($aResult));
$oKPI->ComputeAndReport('Data fetch and format');
break;
case 'datatable_save_settings':
$oPage->SetContentType('text/plain');
$iPageSize = utils::ReadParam('page_size', 10);

View File

@@ -47,7 +47,7 @@ try
throw new AjaxSearchException("Invalid query (empty filter)", 400);
}
$oPage = new ajax_page("");
$oPage = new AjaxPage("");
$oPage->no_cache();
$oPage->SetContentType('text/html');

View File

@@ -0,0 +1,127 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Component\DataTable;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
/**
* Class DataTable
*
* @package Combodo\iTop\Application\UI\Component\DataTable
* @since 3.0.0
*/
class DataTableBlock extends UIContentBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-datatable';
public const HTML_TEMPLATE_REL_PATH = 'components/datatable/layout';
public const JS_TEMPLATE_REL_PATH = 'components/datatable/layout';
protected $aOptions;//list of specific options for display datatable
protected $sAjaxUrl;
protected $sAjaxData;
protected $aDisplayColumns;
protected $aResultColumns;
/**
* Panel constructor.
*
*/
public function __construct(?string $sId = null)
{
parent::__construct($sId);
}
/**
* @return mixed
*/
public function GetAjaxUrl(): string
{
return $this->sAjaxUrl;
}
/**
* @param mixed $sAjaxUrl
*/
public function SetAjaxUrl(string $sAjaxUrl): void
{
$this->sAjaxUrl = $sAjaxUrl;
}
/**
* @return mixed
*/
public function GetAjaxData(): string
{
return $this->sAjaxData;
}
/**
* @param mixed $sAjaxData
*/
public function SetAjaxData(string $sAjaxData): void
{
$this->sAjaxData = $sAjaxData;
}
/**
* @return mixed
*/
public function GetDisplayColumns(): array
{
return $this->aDisplayColumns;
}
/**
* @param mixed $aColumns
*/
public function SetDisplayColumns($aColumns): void
{
$this->aDisplayColumns = $aColumns;
}
/**
* @return mixed
*/
public function GetResultColumns(): array
{
return $this->aResultColumns;
}
/**
* @return mixed
*/
public function GetResultColumnsAsJson(): string
{
return json_encode($this->aResultColumns);
}
/**
* @param mixed $aColumns
*/
public function SetResultColumns($aColumns): void
{
$this->aResultColumns = $aColumns;
}
/**
* @return mixed
*/
public function GetOptions(): array
{
return $this->aOptions;
}
/**
* @param mixed $aOptions
*/
public function SetOptions($aOptions): void
{
$this->aOptions = $aOptions;
}
}

View File

@@ -0,0 +1,589 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Component\DataTable;
use CMDBObjectSet;
use cmdbAbstractObject;
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Component\Panel\PanelFactory;
use MetaModel;
use appUserPreferences;
use UserRights;
use MenuBlock;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
use WebPage;
use Dict;
/**
* Class DataTableFactory
*
* @internal
* @package Combodo\iTop\Application\UI\Component\DataTable
* @since 3.0.0
*/
class DataTableFactory
{
public static function MakeForResult(WebPage $oPage, string $sListId, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oPanel = PanelFactory::MakeForClass( $oSet->GetClass(), "Result");
$oDataTable = DataTableFactory::MakeForRendering( $sListId, $oSet, $aExtraParams );
$oPanel->AddMainBlock($oDataTable);
$oMenuBlock = new MenuBlock($oSet->GetFilter(), 'list');
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $sListId);
$oBlockMenu = new UIContentBlock();
$oBlockMenu->AddSubBlock($oBlock);
$oPanel->AddToolbarBlock($oBlockMenu);
return $oPanel;
}
public static function MakeForObject(WebPage $oPage, string $sListId, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oPanel = PanelFactory::MakeForClass( $oSet->GetClass(), "Result");
$oDataTable = DataTableFactory::MakeForRenderingObject( $sListId, $oSet, $aExtraParams );
$oPanel->AddMainBlock($oDataTable);
$oMenuBlock = new MenuBlock($oSet->GetFilter(), 'list');
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $sListId);
$oBlockMenu = new UIContentBlock();
$oBlockMenu->AddSubBlock($oBlock);
$oPanel->AddToolbarBlock($oBlockMenu);
return $oPanel;
}
/**
* Make a basis Panel component
*
* @param string $sTitle
*
* @return DataTableBlock
*/
public static function MakeForRendering(string $sListId, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oDataTable = new DataTableBlock('datatable_'.$sListId);
///////////////////////////////////////////////////
/*TODO 3.0.0 PrintableVersion
if ($oPage->IsPrintableVersion() || $oPage->is_pdf())
{
return self::GetDisplaySetForPrinting($oPage, $oSet, $aExtraParams);
}
*/
// Initialize and check the parameters
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
$sLinkageAttribute = isset($aExtraParams['link_attr']) ? $aExtraParams['link_attr'] : '';
$iLinkedObjectId = isset($aExtraParams['object_id']) ? $aExtraParams['object_id'] : 0;
$sTargetAttr = isset($aExtraParams['target_attr']) ? $aExtraParams['target_attr'] : '';
if (!empty($sLinkageAttribute)) {
if ($iLinkedObjectId == 0) {
// if 'links' mode is requested the id of the object to link to must be specified
throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_object_id'));
}
if ($sTargetAttr == '') {
// if 'links' mode is requested the d of the object to link to must be specified
throw new ApplicationException(Dict::S('UI:Error:MandatoryTemplateParameter_target_attr'));
}
}
$bSelectMode = isset($aExtraParams['selection_mode']) ? $aExtraParams['selection_mode'] == true : false;
$bSingleSelectMode = isset($aExtraParams['selection_type']) ? ($aExtraParams['selection_type'] == 'single') : false;
$aExtraFieldsRaw = isset($aExtraParams['extra_fields']) ? explode(',',
trim($aExtraParams['extra_fields'])) : array();
$aExtraFields = array();
foreach ($aExtraFieldsRaw as $sFieldName) {
// Ignore attributes not of the main queried class
if (preg_match('/^(.*)\.(.*)$/', $sFieldName, $aMatches)) {
$sClassAlias = $aMatches[1];
$sAttCode = $aMatches[2];
if ($sClassAlias == $oSet->GetFilter()->GetClassAlias()) {//$oSet->GetFilter()->GetSelectedClasses()
$aExtraFields[] = $sAttCode;
}
} else {
$aExtraFields[] = $sFieldName;
}
}
$sClassName = $oSet->GetFilter()->GetClass();
$sZListName = isset($aExtraParams['zlist']) ? ($aExtraParams['zlist']) : 'list';
if ($sZListName !== false) {
$aList = cmdbAbstractObject::FlattenZList(MetaModel::GetZListItems($sClassName, $sZListName));
$aList = array_merge($aList, $aExtraFields);
} else {
$aList = $aExtraFields;
}
// Filter the list to removed linked set since we are not able to display them here
foreach ($aList as $index => $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet) {
// Removed from the display list
unset($aList[$index]);
}
}
if (!empty($sLinkageAttribute)) {
// The set to display is in fact a set of links between the object specified in the $sLinkageAttribute
// and other objects...
// The display will then group all the attributes related to the link itself:
// | Link_attr1 | link_attr2 | ... || Object_attr1 | Object_attr2 | Object_attr3 | .. | Object_attr_n |
$aDisplayList = array();
$aAttDefs = MetaModel::ListAttributeDefs($sClassName);
assert(isset($aAttDefs[$sLinkageAttribute]));
$oAttDef = $aAttDefs[$sLinkageAttribute];
assert($oAttDef->IsExternalKey());
// First display all the attributes specific to the link record
foreach ($aList as $sLinkAttCode) {
$oLinkAttDef = $aAttDefs[$sLinkAttCode];
if ((!$oLinkAttDef->IsExternalKey()) && (!$oLinkAttDef->IsExternalField())) {
$aDisplayList[] = $sLinkAttCode;
}
}
// Then display all the attributes neither specific to the link record nor to the 'linkage' object (because the latter are constant)
foreach ($aList as $sLinkAttCode) {
$oLinkAttDef = $aAttDefs[$sLinkAttCode];
if (($oLinkAttDef->IsExternalKey() && ($sLinkAttCode != $sLinkageAttribute))
|| ($oLinkAttDef->IsExternalField() && ($oLinkAttDef->GetKeyAttCode() != $sLinkageAttribute))) {
$aDisplayList[] = $sLinkAttCode;
}
}
// First display all the attributes specific to the link
// Then display all the attributes linked to the other end of the relationship
$aList = $aDisplayList;
}
$sSelectMode = 'none';
if ($bSelectMode) {
$sSelectMode = $bSingleSelectMode ? 'single' : 'multiple';
}
$sClassAlias = $oSet->GetClassAlias();
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
$sTableId = isset($aExtraParams['table_id']) ? $aExtraParams['table_id'] : null;
$aClassAliases = array($sClassAlias => $sClassName);
$oDefaultSettings = DataTableSettings::GetDataModelSettings($aClassAliases, $bViewLink, array($sClassAlias => $aList));
if ($bDisplayLimit) {
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oDefaultSettings->iDefaultPageSize = $iDefaultPageSize;
} else {
$oDefaultSettings->iDefaultPageSize = 0;
}
$oDefaultSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
$bUseCustomSettings = false;
// Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($aClassAliases, $sTableId);
if ($oCustomSettings != null) {
// Custom settings overload the default ones
$bUseCustomSettings = true;
if ($oDefaultSettings->iDefaultPageSize == 0) {
$oCustomSettings->iDefaultPageSize = 0;
}
} else {
$oCustomSettings = $oDefaultSettings;
}
if ($oCustomSettings->iDefaultPageSize > 0) {
$oSet->SetLimit($oCustomSettings->iDefaultPageSize);
}
$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 = $aClassAliases[$sAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->alwaysLoadInTables()) {
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
}
}
}
}
$oSet->OptimizeColumnLoad($aColumnsToLoad);
$aColumnDefinition = [];
foreach ($aClassAliases as $sClassAlias => $sClassName) {
foreach ($oCustomSettings->aColumns[$sClassAlias] as $sAttCode => $aData) {
if ($aData['checked']) {
if ($sAttCode == '_key_') {
$aColumnDefinition[] = [
'description' => $aData['label'],
'object_class' => $sClassName,
'class_alias' => $sClassAlias,
'attribute_code' => $sAttCode,
'attribute_type' => '_key_',
'attribute_label' => $aData['alias'],
"render" => "return '<a class=\'object-ref-link\' href= \'UI.php?operation=details&class=".$sClassName."&id='+data+'\'>'+row['".$sClassAlias."/friendlyname']+'</a>' ;",
];
} else {
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aColumnDefinition[] = [
'description' => $oAttDef->GetOrderByHint(),
'object_class' => $sClassName,
'class_alias' => $sClassAlias,
'attribute_code' => $sAttCode,
'attribute_type' => $sAttDefClass,
'attribute_label' => $sAttLabel,
"render" => $oAttDef->GetRenderForDataTable($sClassAlias),
];
}
}
}
}
$aOptions = [];
if($oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = json_encode(array('iDefaultPageSize' => $oDefaultSettings->iDefaultPageSize, 'oColumns' => $oDefaultSettings->aColumns));
}
if ($sSelectMode == 'multiple') {
$aOptions['select'] = "multi";
} else if ($sSelectMode == 'single') {
$aOptions['select'] = "single";
}
$aOptions['iPageSize'] = 10;
if ($oCustomSettings->iDefaultPageSize > 0) {
$aOptions['iPageSize'] = $oCustomSettings->iDefaultPageSize;
}
$aOptions['sTableId'] =$sTableId;
$aOptions['bUseCustomSettings'] =$bUseCustomSettings;
$aOptions['bViewLink'] =$bViewLink;
$oDataTable->SetOptions($aOptions);
$oDataTable->SetAjaxUrl("ajax.render.php");
$oDataTable->SetAjaxData(json_encode([
"operation" => 'search',
"filter" => $oSet->GetFilter()->serialize(),
"columns" => $oCustomSettings->aColumns,
"extra_params" => $aExtraParams,
"class_aliases" => $aClassAliases,
]));
$oDataTable->SetDisplayColumns($aColumnDefinition);
$oDataTable->SetResultColumns($oCustomSettings->aColumns);
return $oDataTable;
}
public static function MakeForRenderingObject(string $sListId, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oDataTable = new DataTableBlock('datatable_'.$sListId);
$aList = array();
// Initialize and check the parameters
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
// Check if there is a list of aliases to limit the display to...
$aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',',
$aExtraParams['display_aliases']) : array();
$sZListName = isset($aExtraParams['zlist']) ? ($aExtraParams['zlist']) : 'list';
$aExtraFieldsRaw = isset($aExtraParams['extra_fields']) ? explode(',',
trim($aExtraParams['extra_fields'])) : array();
$aExtraFields = array();
$sAttCode = '';
foreach($aExtraFieldsRaw as $sFieldName)
{
// Ignore attributes not of the main queried class
if (preg_match('/^(.*)\.(.*)$/', $sFieldName, $aMatches))
{
$sClassAlias = $aMatches[1];
$sAttCode = $aMatches[2];
if (array_key_exists($sClassAlias, $oSet->GetSelectedClasses()))
{
$aExtraFields[$sClassAlias][] = $sAttCode;
}
}
else
{
$aExtraFields['*'] = $sAttCode;
}
}
$aClassAliases = $oSet->GetFilter()->GetSelectedClasses();
$aAuthorizedClasses = array();
foreach($aClassAliases as $sAlias => $sClassName)
{
if ((UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) &&
((count($aDisplayAliases) == 0) || (in_array($sAlias, $aDisplayAliases))))
{
$aAuthorizedClasses[$sAlias] = $sClassName;
}
}
foreach($aAuthorizedClasses as $sAlias => $sClassName)
{
if (array_key_exists($sAlias, $aExtraFields))
{
$aList[$sAlias] = $aExtraFields[$sAlias];
}
else
{
$aList[$sAlias] = array();
}
if ($sZListName !== false)
{
$aDefaultList = self::FlattenZList(MetaModel::GetZListItems($sClassName, $sZListName));
$aList[$sAlias] = array_merge($aDefaultList, $aList[$sAlias]);
}
// Filter the list to removed linked set since we are not able to display them here
foreach ($aList[$sAlias] as $index => $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet)
{
// Removed from the display list
unset($aList[$sAlias][$index]);
}
}
if (empty($aList[$sAlias]))
{
unset($aList[$sAlias], $aAuthorizedClasses[$sAlias]);
}
}
$sSelectMode = 'none';
$oDefaultSettings = DataTableSettings::GetDataModelSettings($aAuthorizedClasses, $bViewLink, $aList);
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
if ($bDisplayLimit)
{
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size',
MetaModel::GetConfig()->GetMinDisplayLimit());
$oDefaultSettings->iDefaultPageSize = $iDefaultPageSize;
}
$sTableId = isset($aExtraParams['table_id']) ? $aExtraParams['table_id'] : null;
$oDefaultSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
$bUseCustomSettings = false;
// Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($aClassAliases, $sTableId);
if ($oCustomSettings != null) {
// Custom settings overload the default ones
$bUseCustomSettings = true;
if ($oDefaultSettings->iDefaultPageSize == 0) {
$oCustomSettings->iDefaultPageSize = 0;
}
} else {
$oCustomSettings = $oDefaultSettings;
}
if ($oCustomSettings->iDefaultPageSize > 0) {
$oSet->SetLimit($oCustomSettings->iDefaultPageSize);
}
$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 = $aClassAliases[$sAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->alwaysLoadInTables()) {
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
}
}
}
}
$oSet->OptimizeColumnLoad($aColumnsToLoad);
$aColumnDefinition = [];
foreach ($aClassAliases as $sClassAlias => $sClassName) {
foreach ($oCustomSettings->aColumns[$sClassAlias] as $sAttCode => $aData) {
if ($aData['checked']) {
if ($sAttCode == '_key_') {
$aColumnDefinition[] = [
'description' => $aData['label'],
'object_class' => $sClassName,
'class_alias' => $sClassAlias,
'attribute_code' => $sAttCode,
'attribute_type' => '_key_',
'attribute_label' => $aData['alias'],
"render" => "return '<a class=\'object-ref-link\' href= \'UI.php?operation=details&class=".$sClassName."&id='+data+'\'>'+row['".$sClassAlias."/friendlyname']+'</a>' ;",
];
} else {
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aColumnDefinition[] = [
'description' => $oAttDef->GetOrderByHint(),
'object_class' => $sClassName,
'class_alias' => $sClassAlias,
'attribute_code' => $sAttCode,
'attribute_type' => $sAttDefClass,
'attribute_label' => $sAttLabel,
"render" => $oAttDef->GetRenderForDataTable($sClassAlias),
];
}
}
}
}
$aOptions = [];
if($oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = json_encode(array('iDefaultPageSize' => $oDefaultSettings->iDefaultPageSize, 'oColumns' => $oDefaultSettings->aColumns));
}
if ($sSelectMode == 'multiple') {
$aOptions['select'] = "multi";
} else if ($sSelectMode == 'single') {
$aOptions['select'] = "single";
}
$aOptions['iPageSize'] = 10;
if ($oCustomSettings->iDefaultPageSize > 0) {
$aOptions['iPageSize'] = $oCustomSettings->iDefaultPageSize;
}
$aOptions['sTableId'] =$sTableId;
$aOptions['bUseCustomSettings'] =$bUseCustomSettings;
$aOptions['bViewLink'] =$bViewLink;
$oDataTable->SetOptions($aOptions);
$oDataTable->SetAjaxUrl("ajax.render.php");
$oDataTable->SetAjaxData(json_encode([
"operation" => 'search',
"filter" => $oSet->GetFilter()->serialize(),
"columns" => $oCustomSettings->aColumns,
"extra_params" => $aExtraParams,
"class_aliases" => $aClassAliases,
]));
$oDataTable->SetDisplayColumns($aColumnDefinition);
$oDataTable->SetResultColumns($oCustomSettings->aColumns);
return $oDataTable;
}
public static function GetOptionsForRendering(array $aColumns,string $sSelectMode, string $sFilter, int $iLength, array $aExtraParams)
{
$aOptions = [];
$aColumnsDefinitions = [];
$aColumnDefinition = [];
$aClassAliases = [];
foreach ($aColumns as $sClassName => $aClassColumns) {
$aClassAliases[$sClassName]=$sClassName;
foreach ($aClassColumns as $sAttCode => $aData) {
if ($aData['checked'] == "true") {
$aColumnDefinition["width"] = "auto";
$aColumnDefinition["searchable"]= false;
$aColumnDefinition["sortable"]= true;
$aColumnDefinition["defaultContent"]= "";
$aColumnDefinition["type"]= "html";
if ($sAttCode == '_key_') {
$aColumnDefinition["title"] =$aData['alias'];
$aColumnDefinition['metadata'] =[
'object_class'=> $sClassName,
'attribute_code'=> $sAttCode,
'attribute_type'=> '_key_',
'attribute_label'=> $aData['alias'],
];
$aColumnDefinition["data"] = $sClassName."/".$sAttCode;
$aColumnDefinition["render"] =[
"display"=> "return '<a class=\'object-ref-link\' href=\'UI.php?operation=details&class=".$sClassName."&id='+data+'\'>'+row['".$sClassName."/friendlyname']+'</a>' ;",
"_"=>$sClassName."/".$sAttCode,
];
} else {
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aColumnDefinition["title"] =$sAttLabel;
$aColumnDefinition['metadata'] =[
'object_class'=> $sClassName,
'attribute_code'=> $sAttCode,
'attribute_type'=> $sAttDefClass,
'attribute_label'=> $sAttLabel,
];
$aColumnDefinition["data"] = $sClassName."/".$sAttCode;
$aColumnDefinition["render"] =[
"display"=> $oAttDef->GetRenderForDataTable($sClassName),
"_"=>$sClassName."/".$sAttCode,
];
}
array_push($aColumnsDefinitions,$aColumnDefinition);
}
}
}
$aOptions['select'] =$sSelectMode;
$aOptions['pageLength'] = $iLength;
$sAjaxData=json_encode([
"operation" => 'search',
"filter" => $sFilter,
"columns" => $aColumns,
"extra_params" => $aExtraParams,
"class_aliases" => $aClassAliases,
]);
$aOptions[] = [
"language" =>
["processing"=> Dict::Format('UI:Datatables:Language:Processing'),
"search"=> Dict::Format('UI:Datatables:Language:Search'),
"lengthMenu"=> Dict::Format('UI:Datatables:Language:LengthMenu'),
"zeroRecords"=> Dict::Format('UI:Datatables:Language:ZeroRecords'),
"info"=> Dict::Format('UI:Datatables:Language:Info'),
"infoEmpty"=> Dict::Format('UI:Datatables:Language:InfoEmpty'),
"infoFiltered"=> Dict::Format('UI:Datatables:Language:InfoFiltered'),
"emptyTable"=> Dict::Format('UI:Datatables:Language:EmptyTable'),
"paginate"=> [
"first"=> "<<",
"previous"=> "<",
"next"=> ">",
"last"=> ">>"
],
"aria"=> [
"sortAscending"=> Dict::Format( 'UI:Datatables:Language:Sort:Ascending'),
"sortDescending"=> Dict::Format('UI:Datatables:Language:Sort:Descending')
],
],
"lengthMenu" => Dict::Format( 'Portal:Datatables:Language:DisplayLength:All'),
"dom"=> "<'ibo-datatable-toolbar'pil>t<'ibo-datatable-toolbar'pil>",
"order"=> [],
"filter"=> false,
"processing"=> true,
"serverSide"=> true,
"columns"=> $aColumnsDefinitions,
"allColumns"=> $aColumns,
'ajax' => '$.fn.dataTable.pipeline( {
"url": "ajax.render.php",
"data": '.$sAjaxData.',
"method": "post",
"pages": 5 // number of pages to cache
} )'
];
return $aOptions;
}
}

View File

@@ -0,0 +1,355 @@
<?php
namespace Combodo\iTop\Application\UI\Component\DataTable;
use appUserPreferences;
use AttributeDashboard;
use AttributeFriendlyName;
use AttributeLinkedSet;
use cmdbAbstract;
use Dict;
use Metamodel;
use Serializable;
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
/**
* DataTableSettings constructor.
*
* @param $aClassAliases
* @param null $sTableId
*/
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
/**
* @param $iDefaultPageSize
* @param $aSortOrder
* @param $aColumns
*/
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
/**
* @return string
*/
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,
)
);
}
/**
* @param string $sData
*
* @throws \Exception
*/
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();
}
/**
* @param $aClassAliases
* @param $bViewLink
* @param $aDefaultLists
*
* @return \DataTableSettings
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public static 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';
}
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
if (array_key_exists($sNormalizedFName, $aSortOrder)) {
$sSort = $aSortOrder[$sNormalizedFName] ? '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;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
/**
* @throws \CoreException
*/
protected function FixVisibleColumns()
{
foreach ($this->aClassAliases as $sAlias => $sClass) {
if (!isset($this->aColumns[$sAlias])) {
continue;
}
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), sorted in alphabetical order
$aTempData = array();
foreach ($aList as $sAttCode => $oAttDef) {
if ((!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard))) {
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach ($aTempData as $sLabel => $aFieldData) {
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
/**
* @param $aClassAliases
* @param null $sTableId
* @param bool $bOnlyOnTable
*
* @return \DataTableSettings|null
* @throws \Exception
*/
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
{
$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) {
if (!$bOnlyOnTable) {
// 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;
}
/**
* @return array
*/
public function GetSortOrder()
{
$aSortOrder = array();
foreach ($this->aColumns as $sAlias => $aColumns) {
foreach ($aColumns as $aColumn) {
if ($aColumn['sort'] != 'none') {
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort'] == 'asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
/**
* @param null $sTargetTableId
*
* @return bool
*/
public function Save($sTargetTableId = null)
{
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
return true;
}
/**
* @return bool
*/
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); // escape the | character
$sPattern = '#^' . str_replace(array('*'), array('.*'), $sPattern) . '$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
} else {
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
/**
* @param null $sTableId
*
* @return string
*/
protected function GetPrefsKey($sTableId = null)
{
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
}
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
{
if ($sTableId === null) {
$sTableId = '*';
}
$aKeys = array();
foreach ($aClassAliases as $sAlias => $sClass) {
$aKeys[] = $sAlias . '-' . $sClass;
}
return implode('/', $aKeys) . '|' . $sTableId;
}
/**
* @param $sAlias
* @param $sAttCode
* @param $oAttDef
* @param $bChecked
* @param $sSort
*
* @return array|bool
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
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()) {
if ($oAttDef->IsFriendlyName()) {
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
} else {
$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;
}
}

View File

@@ -40,13 +40,31 @@ class NiceWebPage extends WebPage
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui.custom.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
//TODO deprecated in 3.0.0
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
// table sorting
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
//TODO end deprecated in 3.0.0
// Datatables added in 3.0.0
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/jquery.dataTables.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/dataTables.bootstrap.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/dataTables.fixedHeader.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/dataTables.responsive.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/dataTables.scroller.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'lib/datatables/js/dataTables.select.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/dataTables.settings.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/dataTables.pipeline.js');
/*$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/dataTables.bootstrap.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/fixedHeader.bootstrap.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/responsive.bootstrap.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/scroller.bootstrap.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/select.bootstrap.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'lib/datatables/css/select.dataTables.min.css');*/
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.popupmenu.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/searchformforeignkeys.js');
@@ -69,52 +87,7 @@ class NiceWebPage extends WebPage
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboardwidget.js');
$this->add_dict_entries('UI:Combo');
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("tbody tr:even",table).addClass('even');
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
$("tbody tr:odd",table).removeClass('even');
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->LoadTheme();
$this->LoadTheme();
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);

View File

@@ -31,6 +31,14 @@ use AttributeFriendlyName;
use AttributeTagSet;
use CMDBObjectSet;
use Combodo\iTop\Application\Search\CriterionConversion\CriterionToSearchForm;
use Combodo\iTop\Application\UI\Component\Form\Form;
use Combodo\iTop\Application\UI\Component\DataContainer\DataContainer;
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Component\Input\InputFactory;
use Combodo\iTop\Application\UI\Component\Panel\Panel;
use Combodo\iTop\Application\UI\Component\Panel\PanelFactory;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
use Combodo\iTop\Renderer\BlockRenderer;
use CoreException;
use DBObjectSearch;
use DBObjectSet;
@@ -41,6 +49,7 @@ use FieldExpression;
use IssueLog;
use MetaModel;
use MissingQueryArgument;
use ScssPhp\ScssPhp\Block;
use TrueExpression;
use utils;
use WebPage;
@@ -60,7 +69,12 @@ class SearchForm
*/
public function GetSearchForm(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
$sHtml = '';
$oPage->AddUiBlock($this->GetSearchFormUIBlock($oPage, $oSet, $aExtraParams));
return '';
}
public function GetSearchFormUIBlock(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
$oUiBlock = new UIContentBlock();
$oAppContext = new ApplicationContext();
$sClassName = $oSet->GetFilter()->GetClass();
$aListParams = array();
@@ -79,7 +93,7 @@ class SearchForm
{
$iSearchFormId = $oPage->GetUniqueId();
$sSearchFormId = 'SimpleSearchForm'.$iSearchFormId;
$sHtml .= "<div id=\"ds_$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">\n";
$oUiBlock->AddHtml("<div id=\"ds_$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">");
$aListParams['currentId'] = "$iSearchFormId";
}
// Check if the current class has some sub-classes
@@ -109,7 +123,7 @@ class SearchForm
if (!isset($aExtraParams['result_list_outer_selector']))
{
if (isset($aExtraParams['table_id']))
if (isset($aExtraParams['table_id']) )
{
$aExtraParams['result_list_outer_selector'] = $aExtraParams['table_id'];
}
@@ -170,21 +184,34 @@ class SearchForm
}
$sAction = (isset($aExtraParams['action'])) ? $aExtraParams['action'] : utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
$sStyle = ($bOpen == 'true') ? '' : 'closed';
$sStyle = "ibo-search-form";
$sStyle .= ($bOpen == 'true') ? '' : ' closed';
$sStyle .= ($bAutoSubmit === true) ? '' : ' no_auto_submit';
$sHtml .= "<form id=\"fs_{$sSearchFormId}\" action=\"{$sAction}\" class=\"{$sStyle}\">\n"; // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
$sHtml .= "<h2 class=\"sf_title\"><span class=\"sft_long\">" . Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo) . "</span><span class=\"sft_short\">" . Dict::S('UI:SearchToggle') . "</span>";
$sHtml .= "<a class=\"sft_toggler fas fa-caret-down pull-right\" href=\"#\" title=\"" . Dict::S('UI:Search:Toggle') . "\"></a>";
//(string $sTitle = '', array $aSubBlocks = [], string $sColor = self::DEFAULT_COLOR, ?string $sId = null)
$oUiSearchBlock = new Panel(Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo), [],Panel::DEFAULT_COLOR, $sSearchFormId);
$oUiSearchBlock->SetCSSClasses("display_block");
$oUiBlock->AddSubBlock($oUiSearchBlock);
$sHtml = "<a class=\"sft_toggler fas fa-caret-down pull-right\" href=\"#\" title=\"" . Dict::S('UI:Search:Toggle') . "\"></a>";
$sHtml .= "<span class=\"pull-right\">";
$sHtml .= "<span class=\"sfobs_hint pull-right\">" . Dict::S('UI:Search:Obsolescence:DisabledHint') . "</span>";
$sHtml .= "<br class='clearboth' />";
$sHtml .= "<span class=\"sft_hint pull-right\">" . Dict::S('UI:Search:AutoSubmit:DisabledHint') . "</span>";
$sHtml .= "</span>";
$sHtml .= "<br class='clearboth' />";
$sHtml .= "</h2>\n";
$sHtml .= "<div id=\"fs_{$sSearchFormId}_message\" class=\"sf_message header_message\"></div>\n";
$sHtml .= "<div id=\"fs_{$sSearchFormId}_criterion_outer\">\n</div>\n";
$sHtml .= "</form>\n";
$oUiSearchBlock->AddToolbarBlock(new Html($sHtml));
$oFormSearch=new Form("fs_".$sSearchFormId);
$oFormSearch->SetAction($sAction)
->AddCSSClasses($sStyle);
$oUiSearchBlock->AddSubBlock($oFormSearch);
$oFormSearch->AddSubBlock(InputFactory::MakeForHidden("class", $sClassName));
$oFormSearch->AddHtml( "<div id=\"fs_{$sSearchFormId}_message\" class=\"sf_message header_message\"></div>");//class sf_message header_message
$oCriterionBlock = new UIContentBlock("fs_{$sSearchFormId}_criterion_outer","sf_criterion_area ibo-criterion-area");
$oFormSearch->AddSubBlock($oCriterionBlock);
if (isset($aExtraParams['query_params']))
{
@@ -289,9 +316,8 @@ class SearchForm
$oPage->add_ready_script('$("#fs_'.$sSearchFormId.'").search_form_handler('.json_encode($aSearchParams).');');
return $sHtml;
return $oUiBlock;
}
/**
* @param \DBObjectSet $oSet
*

View File

@@ -0,0 +1,61 @@
{% for oSubBlock in oUIBlock.GetSubBlocks() %}{{ render_block(oSubBlock, {aPage: aPage}) }}{% endfor %}
{% if oUIBlock.GetOptions()["select"] is defined %}
<input type="hidden" name="selectionMode" value="positive"/>
<input type="hidden" name="extra_params" value="{{ oUIBlock.GetAjaxData()["extra_params"]}}"/>
<input type="hidden" name="filter" value="{{ oUIBlock.GetAjaxData()["filter"]}}"/>
{% endif %}
<table id="{{ oUIBlock.GetId() }}" width="100%" class="ibo-datatable">
<thead>
{% if oUIBlock.GetOptions()["select"] is defined %}
<th></th>
{% endif %}
{% for aColumn in oUIBlock.GetDisplayColumns() %}
<th class="ibo-datatable-header" title="{{ aColumn["description"] }}\">{{ aColumn["attribute_label"] }} </th>
{% endfor %}
</thead>
</table>
<div id="datatable_dlg_{{ oUIBlock.GetId() }}" style="display: none; background : white;" class="">
<form id="form_{{ oUIBlock.GetId() }}" onsubmit="return false">
<p>
<input id="dtbl_dlg_settings_{{ oUIBlock.GetId() }}" type="radio" name="settings" {% if (oUIBlock.GetOptions()['bUseCustomSettings'] == false) %} checked {% endif %} value="defaults">
<label for="dtbl_dlg_settings_{{ oUIBlock.GetId() }}">&nbsp;{{ 'UI:UseDefaultSettings'|dict_s }}</label>
</p>
<fieldset>
<legend class="transparent">
<input id="dtbl_dlg_specific_{{ oUIBlock.GetId() }}" type="radio" class="specific_settings" name="settings" {% if oUIBlock.GetOptions()["bUseCustomSettings"] %} checked {% endif %} value="specific">
<label for="dtbl_dlg_specific_{{ oUIBlock.GetId() }}">&nbsp;&nbsp;{{ 'UI:UseSpecificSettings'|dict_s }}</label>
</legend>
{{'UI:ColumnsAndSortOrder'|dict_s}}<br/>
<ul class="sortable_field_list" id="sfl_{{ oUIBlock.GetId() }}">
</ul>
<p> {{ 'UI:Display_X_ItemsPerPage_prefix'|dict_s }}<input type="text" size="4" name="page_size" value="{{ oUIBlock.GetOptions()["iPageSize"]}}">{{ 'UI:Display_X_ItemsPerPage_suffix'|dict_s }}</p>
</fieldset>
<fieldset>
<legend class="transparent">
<input id="dtbl_dlg_save_{{ oUIBlock.GetId() }}" type="checkbox" {% if oUIBlock.GetOptions()["sTableId"] != null %}checked{% endif %} name="save_settings">
<label for="dtbl_dlg_save_{{ oUIBlock.GetId() }}">&nbsp;&nbsp;{{ 'UI:UseSavetheSettings'|dict_s }}</label>
</legend>
<p>
<input id="dtbl_dlg_this_list_{{ oUIBlock.GetId() }}" type="radio" name="scope" {% if oUIBlock.GetOptions()["sTableId"] != null %} checked {% else %} disabled="disabled" stay-disabled="true"{% endif %} value="this_list">
<label for="dtbl_dlg_this_list_{{ oUIBlock.GetId() }}">&nbsp;&nbsp;{{ 'UI:OnlyForThisList'|dict_s }}</label>&nbsp;&nbsp;&nbsp;&nbsp;
<input id="dtbl_dlg_all_{{ oUIBlock.GetId() }}" type="radio" name="scope" {% if oUIBlock.GetOptions()["sTableId"] == null %} checked {% endif %} value="defaults">
<label for="dtbl_dlg_all_{{ oUIBlock.GetId() }}">&nbsp;&nbsp;{{ 'UI:ForAllLists'|dict_s }}</label>
</p>
</fieldset>
<table style="width:100%">
<tr>
<td style="text-align:center;">
<button type="button" onclick="$('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings('onDlgCancel'); $('#datatable_dlg_{{ oUIBlock.GetId() }}').dialog('close')">&nbsp;{{ 'UI:Button:Cancel'|dict_s }}</button>
</td>
<td style="text-align:center;">
<button type="submit" onclick="$('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings('onDlgOk'); $('#datatable_dlg_{{ oUIBlock.GetId() }}').dialog('close');">&nbsp;{{ 'UI:Button:Ok'|dict_s }}</button>
</td>
</tr>
</table>
</form>
</div>

View File

@@ -0,0 +1,256 @@
function checkAllDataTable(table, value)
{
if (value) {
$(table).DataTable().rows().select();
}
else {
$(table).DataTable().rows({ page: 'current' }).deselect();
}
// Mark all the displayed items as check or unchecked depending on the value
$(table).find(':checkbox[name^=selectObj]:not([disabled])').each(function (index, element) {
var $currentCheckbox = $(this);
$currentCheckbox.prop('checked', value);
$currentLine = $currentCheckbox.closest("tr");
(value) ? $currentLine.addClass("selected") : $currentLine.removeClass("selected");
});
// Set the 'selectionMode' for the future objects to load
var selectionMode = 'positive';
if (value)
{
selectionMode = 'negative';
}
$(table).parent().parent().find(':input[name=selectionMode]').val(selectionMode);
// Reset the list of saved selection...
$(':input[name^=storedSelection]').remove();
$(table).parent().find(':checkbox[name^=selectObj]').trigger("change");
//updateCounter(table);
return true;
}
$('#{{ oUIBlock.GetId() }}').closest( "[role=dialog]" ).on( "dialogbeforeclose", function( event, ui ) {
console.warn("destroy on close");
$('#{{ oUIBlock.GetId() }}').DataTable().clear();
// $('#{{ oUIBlock.GetId() }}').DataTable().destroy(false);
} );
{% if oUIBlock.GetOptions()["select"] is defined %}
var oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }} = [];
{% endif %}
if ( $.fn.dataTable.isDataTable( '#{{ oUIBlock.GetId() }}' ) ) {
console.warn("destroy on load");
$('#{{ oUIBlock.GetId() }}').DataTable().destroy(false);
}
var oTable{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').DataTable({
"language": {
"processing": "{{ 'UI:Datatables:Language:Processing'|dict_s }}",
"search": "{{ 'UI:Datatables:Language:Search'|dict_s }}",
"lengthMenu": " Showing _MENU_ out",// "{{ 'UI:Datatables:Language:LengthMenu'|dict_s }}",
"zeroRecords": "{{ 'UI:Datatables:Language:ZeroRecords'|dict_s }}",
"info": "of _TOTAL_ items",//"{{ 'UI:Datatables:Language:Info'|dict_s }}",
"infoEmpty": "{{ 'UI:Datatables:Language:InfoEmpty'|dict_s }}",
"infoFiltered": "({{ 'UI:Datatables:Language:InfoFiltered'|dict_s }})",
"emptyTable": "{{ 'UI:Datatables:Language:EmptyTable'|dict_s }}",
"paginate": {
"first": "<<",
"previous": "<",
"next": ">",
"last": ">>"
},
"aria": {
"sortAscending": ": {{ 'UI:Datatables:Language:Sort:Ascending'|dict_s }}",
"sortDescending": ": {{ 'UI:Datatables:Language:Sort:Descending'|dict_s }}"
}
},
"lengthMenu": [[ {{ oUIBlock.GetOptions()["iPageSize"] }}, {{ oUIBlock.GetOptions()["iPageSize"]*2 }}, {{ oUIBlock.GetOptions()["iPageSize"]*3 }}, {{ oUIBlock.GetOptions()["iPageSize"]*4 }}, -1], [ {{ oUIBlock.GetOptions()["iPageSize"] }}, {{ oUIBlock.GetOptions()["iPageSize"]*2 }}, {{ oUIBlock.GetOptions()["iPageSize"]*3 }}, {{ oUIBlock.GetOptions()["iPageSize"]*4 }}, "{{ 'Portal:Datatables:Language:DisplayLength:All'|dict_s }}"]],
"dom": "<'ibo-datatable-toolbar'pil>t<'ibo-datatable-toolbar'pil>",
"order": [[1, "asc"]],
{% if oUIBlock.GetOptions()["select"] is defined %}
"select": {
"style": "{{ oUIBlock.GetOptions()["select"] }}"
},
"rowCallback": function(oRow, oData){
// Hiding pagination if only one page
if ($(this).closest('.ibo-panel--body').find('[name=selectionMode]')=="negative") {
if(! oData.id in oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }})
{
$(oRow).select();
$(oRow).find('td:first-child input').prop('checked', true);
}
//$(table).DataTable().rows({ page: 'current' }).select();
}
else {
if(oData.id in oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }})
{
$(oRow).select();
$(oRow).find('td:first-child input').prop('checked', true);
}
}
},
"drawCallback": function (settings) {
// Hiding pagination if only one page
if ($(this).closest('.ibo-panel--body').find('[name=selectionMode]')=="negative") {
$(this).find('[name=selectAll]').checked();
$(table).DataTable().rows({ page: 'current' }).select();
}
else {
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
}
},
{% endif %}
"rowId": "id",
"filter":false,
"retrieve": true,
"destroy": true,
"processing": true,
"serverSide": true,
"columns":[
{% if oUIBlock.GetOptions()["select"] is defined %}
{"width": "auto",
"searchable": false,
"sortable": false,
"title": '<span class="row_input"><input type="checkbox" onclick="checkAllDataTable(\'#{{ oUIBlock.GetId() }}\',this.checked);" class="checkAll" id="field_{{ oUIBlock.GetId() }}_check_all" name="field_{{ oUIBlock.GetId() }}_check_all" title="{{'UI:SearchValue:CheckAll'|dict_s}} / {{'UI:SearchValue:UncheckAll'|dict_s}}" /></span>',
"type": "html",
"data": "",
"render": function(data, type, row)
{
var oCheckboxElem = $('<span class="row_input"><input type="checkbox" class="selectList{{ oUIBlock.GetId() }}" name="selectObject[]" /></span>');
if(row.limited_access)
{
oCheckboxElem.html('-');
}
else
{
oCheckboxElem.find(':input').attr('data-object-id', row.id).attr('data-target-object-id', row.target_id);
}
return oCheckboxElem.prop('outerHTML');
}
},
{% endif %}
{% for aColumn in oUIBlock.GetDisplayColumns() %}
{
"width": "auto",
"searchable": false,
"sortable": true,
"title":"{{ aColumn["attribute_label"] }}",
"defaultContent": "",
"type": "html",
'metadata': {
'object_class': "{{ aColumn["object_class"] }}",
'attribute_code': "{{ aColumn["attribute_code"] }}",
'attribute_type': "{{ aColumn["attribute_type"] }}",
'attribute_label': "{{ aColumn["attribute_label"] }}",
},
"data": "{{ aColumn["class_alias"] }}/{{ aColumn["attribute_code"] }}",
"render": {
"display": function ( data, type, row ) { {{ aColumn["render"]|raw }}},
"_":"{{ aColumn["class_alias"] }}/{{ aColumn["attribute_code"] }}",
},
},
{% endfor %}
],
"ajax": $.fn.dataTable.pipeline( {
"url": "{{ oUIBlock.GetAjaxUrl() }}",
"data": {{ oUIBlock.GetAjaxData() |raw}},
"method": "post",
"pages": 5 // number of pages to cache
} )
});
oTable{{ oUIBlock.GetId() }}.off('select').on('select', function(oEvent, dt, type, indexes){
var aData = oTable{{ oUIBlock.GetId() }}.rows(indexes).data().toArray();
// Checking input
$('#{{ oUIBlock.GetId() }} tr[role="row"].selected td:first-child input').prop('checked', true);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(!(iItemId in oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}))
{
oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}.push(iItemId);
}
}
if ((oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}.length == oTable{{ oUIBlock.GetId() }}.page.info()["recordsTotal"] && $(this).closest('.ibo-panel--body').find('[name=selectionMode]').val()=="negative"))
{
$('#btn_ok_{{ oUIBlock.GetOptions()['sTableId'] }}').prop('disabled', true);
}
else{
$('#btn_ok_{{ oUIBlock.GetOptions()['sTableId'] }}').prop('disabled', false);
}
});
oTable{{ oUIBlock.GetId() }}.off('deselect').on('deselect', function(oEvent, dt, type, indexes){
var aData = oTable{{ oUIBlock.GetId() }}.rows(indexes).data().toArray();
// Checking input
$('#{{ oUIBlock.GetId() }} tr[role="row"]:not(.selected) td:first-child input').prop('checked', false);
// Saving values in temp array
for(var i in aData)
{
var iItemId = aData[i].id;
if(iItemId in oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }})
{
oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}.splice( $.inArray(removeItem, oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}), 1 );
}
}
if ((oSelectedItems{{ oUIBlock.GetOptions()['sTableId'] }}.length == 0 && $(this).closest('.ibo-panel--body').find('[name=selectionMode]').val()=="positive"))
{
$('#btn_ok_{{ oUIBlock.GetOptions()['sTableId'] }}').prop('disabled', true);
}
else{
$('#btn_ok_{{ oUIBlock.GetOptions()['sTableId'] }}').prop('disabled', false);
}
});
// Handles submit button
//$('#form_{{ oUIBlock.GetId() }} .form_buttons .form_btn_submit').off('click').on('click', function(oEvent){
// Extracting value(s) to be send back to the source form
{% if bMultipleSelect %}
//var oData = {values: oSelectedItems};
{% else %}
/*var oData = {value: {}};
var sItemId = Object.keys(oSelectedItems)[0];
var sItemName = oSelectedItems[sItemId];
oData.value[sItemId] = sItemName;*/
{% endif %}
// Triggering value setting on the source field
//$('[data-form-path="{{aSource.sFormPath}}"][data-field-id="{{aSource.sFieldId}}"]').triggerHandler('set_current_value', oData);
// Closing the modal
{% if tIsModal is defined and tIsModal == true %}
//$('#{{ sFormId }}').closest('.modal').modal('hide');
{% endif %}
//});
$('#datatable_dlg_{{ oUIBlock.GetId() }}').dialog(
{
autoOpen: false,
title: "{{ 'UI:ListConfigurationTitle'|dict_s }}",
width: 500,
close: function() { //save data and refresh
$('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings('onDlgCancel');
}
});
$aOptions = {
'sListId' : '{{ oUIBlock.GetId() }}',
'oColumns' : {{ oUIBlock.GetResultColumnsAsJson()|raw }},
'sViewLink': '{{ oUIBlock.GetOptions()["bViewLink"] }}' ,
'iPageSize' : '{{ oUIBlock.GetOptions()["iPageSize"]}}',
'sTableId' :'{{ oUIBlock.GetOptions()["sTableId"]}}',
"sRenderUrl": "{{ oUIBlock.GetAjaxUrl() }}",
"sSelectMode": "{{ oUIBlock.GetOptions()["select"] }}",
"oData": {{ oUIBlock.GetAjaxData() |raw}},
'oLabels' : {"moveup": "{{'UI:Button:MoveUp'|dict_s}}", "movedown": "{{'UI:Button:MoveDown'|dict_s}}"},
'oDefaultSettings' : {{ oUIBlock.GetOptions()["oDefaultSettings"]|raw}},
};
console.warn($aOptions);
//if (!typeof $('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings() !== "undefined")
if ($('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings())
{
$('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings( "destroy");
}
$('#datatable_dlg_{{ oUIBlock.GetId() }}').DataTableSettings( $aOptions);

View File

@@ -1,10 +1,9 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% apply spaceless %}
<div id="{{ oUIBlock.GetId() }}" class="ibo-panel ibo-is-{{ oUIBlock.GetColor() }}">
<div id="{{ oUIBlock.GetId() }}" class="ibo-panel ibo-is-{{ oUIBlock.GetColor() }} {{ oUIBlock.GetCSSClasses() }}">
<div class="ibo-panel--header">
{% block iboPanelHeader %}
<div class="ibo-panel--title">{% block iboPanelTitle %}{{ oUIBlock.GetTitle() }}{% endblock %}</div>
<div class="ibo-panel--toolbar">
{% block iboPanelToolbar %}
{% for oToolbarBlock in oUIBlock.GetToolbarBlocks() %}
@@ -12,6 +11,7 @@
{% endfor %}
{% endblock %}
</div>
<div class="ibo-panel--title">{% block iboPanelTitle %}{{ oUIBlock.GetTitle()|raw }}{% endblock %}</div>
{% endblock %}
</div>
<div class="ibo-panel--body">

View File

@@ -1093,7 +1093,6 @@ input.dp-applied {
border-radius: $search-criteria-box-radius;
box-shadow: $box-shadow-regular;
}
.sfc_form_group,
.sfm_content{
position: absolute;
z-index: -1;