mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Issue/5074 - Routage, Block UI relations, Links row actions (#369)
* datatable row actions
Below is a sample of extra param to enable feature:
$aExtraParams['row_actions'] = [
[
'tooltip' => 'remove an element',
'icon_css_class' => 'fa-minus',
'js_row_action' => 'console.log("You clicked the remove button");',
'confirmation' => [
'message' => 'UI:ConfirmationMessage',
'message_row_data' => "name",
'remember_choice_pref_key' => 'remove_do_not_show_again',
],
],
[
'tooltip' => 'open in new tab',
'icon_css_class' => 'fa-external-link-square-alt',
'on_action_js' => 'window.open("http://localhost/itop-branchs/dev/pages/UI.php?operation=details&class=UserRequest&id=" + aData.id + "&c[menu]=UserRequest%3AOpenRequests");',
],
[
'tooltip' => 'other actions',
'icon_css_class' => 'fa-ellipsis-v',
'on_action_js' => 'console.log(event);',
],
];
* Contrôleur pour la suppression et le détachement de liens
* Block UI pour l'édition des relations
* Block UI pour la visualisation des relations
* Boutons d'actions pour la suppression et le détachement de liens
* Gestion dialogue de confirmation pour les row actions
This commit is contained in:
@@ -39,6 +39,8 @@ use Combodo\iTop\Application\UI\Base\Layout\Object\ObjectFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\TabContainer\Tab\AjaxTab;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksViewTable;
|
||||
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinksViewTable;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
|
||||
|
||||
@@ -650,8 +652,7 @@ HTML
|
||||
}
|
||||
|
||||
// Display mode
|
||||
if (!$oAttDef->IsLinkset())
|
||||
{
|
||||
if (!$oAttDef->IsLinkset()) {
|
||||
continue;
|
||||
} // Process only linkset attributes...
|
||||
|
||||
@@ -662,12 +663,9 @@ HTML
|
||||
$oLinkSet = $oOrmLinkSet->ToDBObjectSet(utils::ShowObsoleteData());
|
||||
|
||||
$iCount = $oLinkSet->Count();
|
||||
if ($this->IsNew())
|
||||
{
|
||||
if ($this->IsNew()) {
|
||||
$iFlags = $this->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$iFlags = $this->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
// Adjust the flags according to user rights
|
||||
@@ -712,103 +710,20 @@ HTML
|
||||
|
||||
$aArgs = array('this' => $this);
|
||||
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE));
|
||||
if ($bEditMode && (!$bReadOnly))
|
||||
{
|
||||
if ($bEditMode && (!$bReadOnly)) {
|
||||
$sInputId = $this->m_iFormId.'_'.$sAttCode;
|
||||
|
||||
if ($oAttDef->IsIndirect())
|
||||
{
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote());
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sTargetClass = $sLinkedClass;
|
||||
}
|
||||
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($sTargetClass, false));
|
||||
$oClassIcon->SetDescription($oAttDef->GetDescription())->AddCSSClass('ibo-block-list--medallion');
|
||||
$oPage->AddUiBlock($oClassIcon);
|
||||
|
||||
$sDisplayValue = ''; // not used
|
||||
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode,
|
||||
$oAttDef, $oLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
|
||||
$this->AddToFieldsMap($sAttCode, $sInputId);
|
||||
$oPage->add($sHTMLValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display mode
|
||||
if (!$oAttDef->IsIndirect())
|
||||
{
|
||||
// 1:n links
|
||||
$sTargetClass = $sLinkedClass;
|
||||
|
||||
$aDefaults = array($oAttDef->GetExtKeyToMe() => $this->GetKey());
|
||||
$oAppContext = new ApplicationContext();
|
||||
foreach($oAppContext->GetNames() as $sKey)
|
||||
{
|
||||
// The linked object inherits the parent's value for the context
|
||||
if (MetaModel::IsValidAttCode($sClass, $sKey))
|
||||
{
|
||||
$aDefaults[$sKey] = $this->Get($sKey);
|
||||
}
|
||||
}
|
||||
$aParams = array(
|
||||
'target_attr' => $oAttDef->GetExtKeyToMe(),
|
||||
'object_id' => $this->GetKey(),
|
||||
'menu' => MetaModel::GetConfig()->Get('allow_menu_on_linkset'),
|
||||
//'menu_actions_target' => '_blank',
|
||||
'default' => $aDefaults,
|
||||
'table_id' => $sClass.'_'.$sAttCode,
|
||||
);
|
||||
} else {
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
$oBlockLinkViewTable = new BlockIndirectLinksViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
|
||||
} else {
|
||||
$oBlockLinkViewTable = new BlockDirectLinksViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
|
||||
}
|
||||
else {
|
||||
// n:n links
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote());
|
||||
$sLinkingAttCode = $oLinkingAttDef->GetCode();
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
|
||||
// N°2334 fields to display for n:n relations
|
||||
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
|
||||
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($sTargetClass);
|
||||
$aLnkAttCodesToDisplay = array_map(function ($oLnkAttDef) {
|
||||
return ormLinkSet::LINK_ALIAS.'.'.$oLnkAttDef->GetCode();
|
||||
},
|
||||
$aLnkAttDefsToDisplay
|
||||
);
|
||||
if (!in_array(ormLinkSet::LINK_ALIAS.'.'.$sLinkingAttCode, $aLnkAttCodesToDisplay)) {
|
||||
// we need to display a link to the remote class instance !
|
||||
$aLnkAttCodesToDisplay[] = ormLinkSet::LINK_ALIAS.'.'.$sLinkingAttCode;
|
||||
}
|
||||
$aRemoteAttCodesToDisplay = array_map(function ($oRemoteAttDef) {
|
||||
return ormLinkSet::REMOTE_ALIAS.'.'.$oRemoteAttDef->GetCode();
|
||||
},
|
||||
$aRemoteAttDefsToDisplay
|
||||
);
|
||||
$aAttCodesToDisplay = array_merge($aLnkAttCodesToDisplay, $aRemoteAttCodesToDisplay);
|
||||
$sAttCodesToDisplay = implode(',', $aAttCodesToDisplay);
|
||||
|
||||
$aParams = array(
|
||||
'link_attr' => $oAttDef->GetExtKeyToMe(),
|
||||
'object_id' => $this->GetKey(),
|
||||
'target_attr' => $oAttDef->GetExtKeyToRemote(),
|
||||
'view_link' => false,
|
||||
'menu' => false,
|
||||
//'menu_actions_target' => '_blank',
|
||||
// By default limit the list to speed up the initial load & display
|
||||
'display_limit' => true,
|
||||
'table_id' => $sClass.'_'.$sAttCode,
|
||||
// N°2334 specify fields to display for n:n relations
|
||||
'zlist' => false,
|
||||
'extra_fields' => $sAttCodesToDisplay,
|
||||
);
|
||||
}
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($sTargetClass, false));
|
||||
$oClassIcon->SetDescription($oAttDef->GetDescription())->AddCSSClass('ibo-block-list--medallion');
|
||||
$oPage->AddUiBlock($oClassIcon);
|
||||
$oBlock = new DisplayBlock($oLinkSet->GetFilter(), 'list', false);
|
||||
$oBlock->Display($oPage, 'rel_'.$sAttCode, $aParams);
|
||||
$oPage->AddUiBlock($oBlockLinkViewTable);
|
||||
}
|
||||
if (array_key_exists($sAttCode, $aRedundancySettings)) {
|
||||
foreach ($aRedundancySettings[$sAttCode] as $oRedundancyAttDef) {
|
||||
@@ -871,6 +786,10 @@ HTML
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add hidden input for linkset transactions
|
||||
$oInputHidden = InputUIBlockFactory::MakeForHidden('linkset_transactions_id', utils::GetNewTransactionId(), 'linkset_transactions_id');
|
||||
$oPage->AddUiBlock($oInputHidden);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1471,6 +1471,7 @@ JS
|
||||
} else {
|
||||
$iListId = $aExtraParams['currentId'];
|
||||
}
|
||||
|
||||
$oBlock = DataTableUIBlockFactory::MakeForRendering($iListId, $oSet, $aExtraParams);
|
||||
$oHtml->AddHtml("<tr><td>");
|
||||
$oContentBlock->AddSubBlock($oBlock);
|
||||
@@ -1838,7 +1839,7 @@ class MenuBlock extends DisplayBlock
|
||||
if ($bIsModifyAllowed) {
|
||||
$aRegularActions['UI:Menu:Modify'] = array(
|
||||
'label' => Dict::S('UI:Menu:Modify'),
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?operation=object.modify&class=$sClass&id=$id{$sContext}#",
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?route=object.modify&class=$sClass&id=$id{$sContext}#",
|
||||
) + $aActionParams;
|
||||
}
|
||||
if ($bIsCreationAllowed) {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinksEditTable;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
/**
|
||||
* Class UILinksWidgetDirect
|
||||
@@ -23,6 +23,7 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* UILinksWidgetDirect constructor.
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sInputId
|
||||
@@ -80,97 +81,10 @@ class UILinksWidgetDirect
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
if (empty($aArgs)) {
|
||||
$aArgs = [];
|
||||
}
|
||||
$oBlock = new BlockDirectLinksEditTable($this, $this->sInputid);
|
||||
$oBlock->InitTable($oPage, $oValue, $sFormPrefix);
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
case LINKSET_EDITMODE_NONE: // The linkset is read-only
|
||||
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_ADDONLY: // The only possible action is to open (in a new window) the form to create a new object
|
||||
if ($oCurrentObj && !$oCurrentObj->IsNew())
|
||||
{
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$sDefault = "default[$sExtKeyToMe]=".$oCurrentObj->GetKey();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
$oPage->p("<a target=\"_blank\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sTargetClass&$sParams&{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sTargetClass))."</a>\n");
|
||||
}
|
||||
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
|
||||
$this->DisplayEditInPlace($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_ADDREMOVE: // The whole linkset can be edited 'in-place'
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$oExtKeyDef = MetaModel::GetAttributeDef($sTargetClass, $sExtKeyToMe);
|
||||
$aButtons = array('add');
|
||||
if ($oExtKeyDef->IsNullAllowed())
|
||||
{
|
||||
$aButtons = array('add', 'remove');
|
||||
}
|
||||
$this->DisplayEditInPlace($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_ACTIONS:
|
||||
default:
|
||||
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, always called with default value)
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
if ($oCurrentObj && $oCurrentObj->IsNew() && $bDisplayMenu)
|
||||
{
|
||||
$oPage->p(Dict::Format('UI:BeforeAdding_Class_ObjectsSaveThisObject', MetaModel::GetName($sTargetClass)));
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = new DBObjectSearch($sTargetClass);
|
||||
$oFilter->AddCondition($oLinksetDef->GetExtKeyToMe(), $oCurrentObj->GetKey(),'=');
|
||||
|
||||
$aDefaults = array($oLinksetDef->GetExtKeyToMe() => $oCurrentObj->GetKey());
|
||||
$oAppContext = new ApplicationContext();
|
||||
foreach($oAppContext->GetNames() as $sKey)
|
||||
{
|
||||
// The linked object inherits the parent's value for the context
|
||||
if (MetaModel::IsValidAttCode($this->sClass, $sKey) && $oCurrentObj)
|
||||
{
|
||||
$aDefaults[$sKey] = $oCurrentObj->Get($sKey);
|
||||
}
|
||||
}
|
||||
$aParams = array(
|
||||
'target_attr' => $oLinksetDef->GetExtKeyToMe(),
|
||||
'object_id' => $oCurrentObj ? $oCurrentObj->GetKey() : null,
|
||||
'menu' => $bDisplayMenu,
|
||||
'menu_actions_target' => '_blank',
|
||||
'default' => $aDefaults,
|
||||
'table_id' => $this->sClass.'_'.$this->sAttCode,
|
||||
);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oPage, $this->sInputid, $aParams);
|
||||
}
|
||||
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,55 +143,6 @@ class UILinksWidgetDirect
|
||||
$oPage->add('</div></div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, caller already handles it)
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$oValue->Rewind();
|
||||
$aData = array();
|
||||
while ($oLinkObj = $oValue->Fetch()) {
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oDiv = UIContentBlockUIBlockFactory::MakeStandard($this->sInputid, ['listContainer']);
|
||||
$oPage->AddSubBlock($oDiv);
|
||||
$oDatatable = DataTableUIBlockFactory::MakeForForm($this->sInputid, $aAttribs, $aData);
|
||||
$oDatatable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
|
||||
$oDiv->AddSubBlock($oDatatable);
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject $oCurrentObj
|
||||
@@ -433,18 +298,21 @@ HTML
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function GetTableConfig()
|
||||
|
||||
public function GetTableConfig()
|
||||
{
|
||||
$aAttribs = array();
|
||||
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
|
||||
$aAttribs['form::select'] = array(
|
||||
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);oWidget".$this->sInputid.".directlinks('instance')._onSelectChange();\" class=\"checkAll\"></input>",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
|
||||
$aAttribs[$sLinkedAttCode] = array('label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint());
|
||||
}
|
||||
return $aAttribs;
|
||||
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,12 +411,43 @@ HTML
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
|
||||
{
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) {
|
||||
$oSearch->AddCondition($sAttCode, $defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetClass(): string
|
||||
{
|
||||
return $this->sClass;
|
||||
}
|
||||
|
||||
public function GetLinkedClass(): string
|
||||
{
|
||||
return $this->sLinkedClass;
|
||||
}
|
||||
|
||||
public function GetAttCode(): string
|
||||
{
|
||||
return $this->sAttCode;
|
||||
}
|
||||
|
||||
public function GetInputId(): string
|
||||
{
|
||||
return $this->sInputid;
|
||||
}
|
||||
|
||||
public function GetNameSuffix(): string
|
||||
{
|
||||
return $this->sNameSuffix;
|
||||
}
|
||||
|
||||
public function GetZList(): array
|
||||
{
|
||||
return $this->aZlist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEdit\BlockIndirectLinksEdit;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog\BlockObjectPickerDialog;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEditTable;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
require_once(APPROOT.'application/displayblock.class.inc.php');
|
||||
|
||||
class UILinksWidget
|
||||
class UILinksWidget
|
||||
{
|
||||
protected $m_sClass;
|
||||
protected $m_sAttCode;
|
||||
protected $m_sNameSuffix;
|
||||
protected $m_iInputId;
|
||||
protected $m_sInputId;
|
||||
protected $m_aAttributes;
|
||||
protected $m_sExtKeyToRemote;
|
||||
protected $m_sExtKeyToMe;
|
||||
@@ -33,7 +33,7 @@ class UILinksWidget
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode AttributeLinkedSetIndirect attcode
|
||||
* @param int $iInputId
|
||||
* @param string $sInputId
|
||||
* @param string $sNameSuffix
|
||||
* @param bool $bDuplicatesAllowed
|
||||
*
|
||||
@@ -41,13 +41,14 @@ class UILinksWidget
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '', $bDuplicatesAllowed = false)
|
||||
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '', $bDuplicatesAllowed = false)
|
||||
{
|
||||
$this->m_sClass = $sClass;
|
||||
$this->m_sAttCode = $sAttCode;
|
||||
$this->m_sInputId = $sInputId;
|
||||
$this->m_sNameSuffix = $sNameSuffix;
|
||||
$this->m_iInputId = $iInputId;
|
||||
$this->m_bDuplicatesAllowed = $bDuplicatesAllowed;
|
||||
|
||||
$this->m_aEditableFields = array();
|
||||
|
||||
/** @var AttributeLinkedSetIndirect $oAttDef */
|
||||
@@ -63,7 +64,7 @@ class UILinksWidget
|
||||
$this->m_aEditableFields = array();
|
||||
$this->m_aTableConfig = array();
|
||||
$this->m_aTableConfig['form::checkbox'] = array(
|
||||
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">",
|
||||
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_sInputId.".OnSelectChange();\">",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
|
||||
@@ -91,234 +92,13 @@ class UILinksWidget
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-row form for editing a link record
|
||||
*
|
||||
* @param WebPage $oP Web page used for the ouput
|
||||
* @param DBObject $oLinkedObj Remote object
|
||||
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param int $iUniqueId A unique identifier of new links
|
||||
* @param boolean $bReadOnly Display link as editable or read-only. Default is false (editable)
|
||||
*
|
||||
* @return array The HTML fragment of the one-row form
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
|
||||
{
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
{
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$iKey][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if ($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
}
|
||||
|
||||
$sState = $linkObjOrId->GetState();
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
|
||||
}
|
||||
else
|
||||
{
|
||||
// form for creating a new record
|
||||
if (is_object($linkObjOrId))
|
||||
{
|
||||
// New link existing only in memory
|
||||
$oNewLinkObj = $linkObjOrId;
|
||||
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRemoteObjKey = $linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
|
||||
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"0\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
|
||||
|
||||
if ($iUniqueId > 0)
|
||||
{
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
//
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rows added before loading the form don't have to call OnLinkAdded.
|
||||
// Listeners are already present and DOM is not recreated
|
||||
$iPositiveUniqueId = -$iUniqueId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId}.AddLink($iPositiveUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
|
||||
$sValue = $oNewLinkObj->Get($sFieldCode);
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
$sState = '';
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->m_sExtKeyToRemote);
|
||||
}
|
||||
|
||||
if (!$bReadOnly)
|
||||
{
|
||||
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
|
||||
// Adding fields from remote class
|
||||
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
|
||||
$aRemoteFieldsMap = [];
|
||||
foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
|
||||
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
|
||||
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
// id field is needed so that remote object could be load server side
|
||||
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
|
||||
|
||||
// Generate WizardHelper to update dependant fields
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->m_sLinkedClass, $sState, $aFieldsMap);
|
||||
//instantiate specific WizarHelper instance for remote class fields refresh
|
||||
$bHasExtKeyUpdatingRemoteClassFields = (
|
||||
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
|
||||
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
|
||||
);
|
||||
if ($bHasExtKeyUpdatingRemoteClassFields)
|
||||
{
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->m_sRemoteClass, $sState, $aRemoteFieldsMap);
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
|
||||
{
|
||||
if (($sFieldCode === $this->m_sExtKeyToRemote))
|
||||
{
|
||||
// current field is the lnk extkey to the remote class
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
|
||||
$sRowFieldCode = 'static::key';
|
||||
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
|
||||
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
$aRemoteCodes = array_map(
|
||||
function ($value) {
|
||||
return $value->GetCode();
|
||||
},
|
||||
$aRemoteAttDefs
|
||||
);
|
||||
$aArgs['remoteCodes'] = $aRemoteCodes;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
|
||||
$sRowFieldCode = $sFieldCode;
|
||||
}
|
||||
$sValue = $oLnk->Get($sFieldCode);
|
||||
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
|
||||
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
|
||||
.cmdbAbstractObject::GetFormElementForField(
|
||||
$oP,
|
||||
$this->m_sLinkedClass,
|
||||
$sFieldCode,
|
||||
$oAttDef,
|
||||
$sValue,
|
||||
$sDisplayValue,
|
||||
$sSafeFieldId,
|
||||
$sNameSuffix,
|
||||
0,
|
||||
$aArgs
|
||||
)
|
||||
.'</div></div></div>';
|
||||
}
|
||||
|
||||
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
$sFieldId = $this->m_sInputId.'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
|
||||
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
|
||||
{
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<JS
|
||||
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
|
||||
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
|
||||
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
|
||||
$sWizardHelperVarName.SetReturnNotEditableFields(true);
|
||||
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table with the form for editing all the links at once
|
||||
@@ -356,92 +136,12 @@ JS
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj): string
|
||||
{
|
||||
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
|
||||
|
||||
$oBlock = new BlockIndirectLinksEdit("linkedset_{$sLinkedSetId}", ["ibo-block-indirect-links--edit"]);
|
||||
|
||||
$oBlock->sLinkedSetId = $sLinkedSetId;
|
||||
$oBlock->sClass = $this->m_sClass;
|
||||
$oBlock->sAttCode = $this->m_sAttCode;
|
||||
$oBlock->iInputId = $this->m_iInputId;
|
||||
$oBlock->sNameSuffix = $this->m_sNameSuffix;
|
||||
$oBlock->bDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
$oBlock->oWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oBlock->sExtKeyToRemote = $this->m_sExtKeyToRemote;
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$oBlock->bJSDoSearch = utils::IsHighCardinality($this->m_sRemoteClass) ? 'false' : 'true';
|
||||
$oBlock->sFormPrefix = $sFormPrefix;
|
||||
$oBlock->sRemoteClass = $this->m_sRemoteClass;
|
||||
|
||||
$oValue->Rewind();
|
||||
$aForm = array();
|
||||
$iMaxAddedId = 0;
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
$oBlock->aRemoved = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->m_sAttCode}_tbd", '[]', 'raw_data'));
|
||||
while ($oCurrentLink = $oValue->Fetch()) {
|
||||
// We try to retrieve the remote object as usual
|
||||
if (!in_array($oCurrentLink->GetKey(), $oBlock->aRemoved)) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
}
|
||||
$oBlock->iMaxAddedId = (int)$iMaxAddedId;
|
||||
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm);
|
||||
$oDataTable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
|
||||
$oBlock->AddSubBlock($oDataTable);
|
||||
|
||||
$oBlock->AddControls();
|
||||
$oBlock = new BlockIndirectLinksEditTable($this);
|
||||
$oBlock->InitTable($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $this->m_aTableConfig);
|
||||
|
||||
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected static function GetTargetClass($sClass, $sAttCode)
|
||||
{
|
||||
/** @var AttributeLinkedSet $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$sTargetClass = '';
|
||||
switch(get_class($oAttDef))
|
||||
{
|
||||
case 'AttributeLinkedSetIndirect':
|
||||
/** @var AttributeExternalKey $oLinkingAttDef */
|
||||
/** @var AttributeLinkedSetIndirect $oAttDef */
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote());
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
break;
|
||||
|
||||
case 'AttributeLinkedSet':
|
||||
$sTargetClass = $sLinkedClass;
|
||||
break;
|
||||
}
|
||||
|
||||
return $sTargetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject $oCurrentObj
|
||||
@@ -473,11 +173,11 @@ JS
|
||||
|
||||
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
|
||||
|
||||
$oBlock = new BlockObjectPickerDialog();
|
||||
$oBlock = new BlockObjectPickerDialog($this);
|
||||
$oPage->AddUiBlock($oBlock);
|
||||
|
||||
$oBlock->sLinkedSetId = $sLinkedSetId;
|
||||
$oBlock->iInputId = $this->m_iInputId;
|
||||
$oBlock->iInputId = $this->m_sInputId;
|
||||
$oBlock->sLinkedClassName = MetaModel::GetName($this->m_sLinkedClass);
|
||||
$oBlock->sClassName = MetaModel::GetName($this->m_sClass);
|
||||
|
||||
@@ -548,7 +248,8 @@ JS
|
||||
foreach ($aLinkedObjectIds as $iObjectId) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oBlock = new BlockIndirectLinksEditTable($this);
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
|
||||
$oP->AddUiBlock($oRow);
|
||||
$iAdditionId++;
|
||||
@@ -575,7 +276,8 @@ JS
|
||||
foreach ($aLinkedObjectIds as $iObjectId) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oBlock = new BlockIndirectLinksEditTable($this);
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$aData = [];
|
||||
foreach ($aRow as $item) {
|
||||
$aData[] = $item;
|
||||
@@ -636,24 +338,77 @@ JS
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
if ($sHierarchicalKeyCode !== false) {
|
||||
$oFilter = new DBObjectSearch($sTargetClass);
|
||||
$oFilter->AddCondition('id', $defaultValue);
|
||||
$oHKFilter = new DBObjectSearch($sTargetClass);
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
||||
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
}
|
||||
} catch (Exception $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
catch (Exception $e) {
|
||||
}
|
||||
} else {
|
||||
$oSearch->AddCondition($sAttCode, $defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLinkedSetId(): string
|
||||
{
|
||||
return "{$this->m_sAttCode}{$this->m_sNameSuffix}";
|
||||
}
|
||||
|
||||
public function GetClass(): string
|
||||
{
|
||||
return $this->m_sClass;
|
||||
}
|
||||
|
||||
public function GetLinkedClass(): string
|
||||
{
|
||||
return $this->m_sLinkedClass;
|
||||
}
|
||||
|
||||
public function GetAttCode(): string
|
||||
{
|
||||
return $this->m_sAttCode;
|
||||
}
|
||||
|
||||
public function GetInputId(): string
|
||||
{
|
||||
return $this->m_sInputId;
|
||||
}
|
||||
|
||||
public function GetNameSuffix(): string
|
||||
{
|
||||
return $this->m_sNameSuffix;
|
||||
}
|
||||
|
||||
public function IsDuplicatesAllowed(): bool
|
||||
{
|
||||
return $this->m_bDuplicatesAllowed;
|
||||
}
|
||||
|
||||
public function GetExternalKeyToRemote(): string
|
||||
{
|
||||
return $this->m_sExtKeyToRemote;
|
||||
}
|
||||
|
||||
public function GetExternalKeyToMe(): string
|
||||
{
|
||||
return $this->m_sExtKeyToMe;
|
||||
}
|
||||
|
||||
public function GetRemoteClass(): string
|
||||
{
|
||||
return $this->m_sRemoteClass;
|
||||
}
|
||||
|
||||
public function GetEditableFields(): array
|
||||
{
|
||||
return $this->m_aEditableFields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -148,4 +148,20 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
@extend %ibo-font-ral-sembol-100;
|
||||
border-bottom: $ibo-vendors-datatables--columns-header--border-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#table-row-action-confirmation-dialog{
|
||||
|
||||
.ibo-row-action--confirmation--explanation{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.ibo-row-action--confirmation--do-not-show-again--checkbox{
|
||||
height: auto;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 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
|
||||
*/
|
||||
|
||||
// Display DataTable
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Links:ActionRow:detach' => 'Detach item',
|
||||
'UI:Links:ActionRow:detach:confirmation' => 'Do you really want to detach <b>{item}</b> from current object ?',
|
||||
'UI:Links:ActionRow:delete' => 'Delete item',
|
||||
'UI:Links:ActionRow:delete:confirmation' => 'Do you really want to delete <b>{item}</b> from current object ?',
|
||||
));
|
||||
@@ -19,16 +19,18 @@
|
||||
|
||||
// Display DataTable
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Datatables:Language:Processing' => 'Please wait...',
|
||||
'UI:Datatables:Language:LengthMenu' => '_MENU_ per page',
|
||||
'UI:Datatables:Language:ZeroRecords' => 'No result',
|
||||
'UI:Datatables:Language:Info' => '_TOTAL_ item(s)',
|
||||
'UI:Datatables:Language:InfoEmpty' => 'No information',
|
||||
'UI:Datatables:Language:EmptyTable' => 'No data available in this table',
|
||||
'UI:Datatables:Language:Error' => 'An error occured while running the query',
|
||||
'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',
|
||||
'UI:Datatables:Column:RowActions:Label' => '',
|
||||
'UI:Datatables:Column:RowActions:Description' => '',
|
||||
'UI:Datatables:Language:Processing' => 'Please wait...',
|
||||
'UI:Datatables:Language:LengthMenu' => '_MENU_ per page',
|
||||
'UI:Datatables:Language:ZeroRecords' => 'No result',
|
||||
'UI:Datatables:Language:Info' => '_TOTAL_ item(s)',
|
||||
'UI:Datatables:Language:InfoEmpty' => 'No information',
|
||||
'UI:Datatables:Language:EmptyTable' => 'No data available in this table',
|
||||
'UI:Datatables:Language:Error' => 'An error occured while running the query',
|
||||
'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',
|
||||
'UI:Datatables:Column:RowActions:Label' => '',
|
||||
'UI:Datatables:Column:RowActions:Description' => '',
|
||||
'UI:Datatables:RowActions:ConfirmationDialog' => 'Action Confirmation',
|
||||
'UI:Datatables:RowActions:ConfirmationMessage' => 'Do you confirm action ?',
|
||||
));
|
||||
@@ -80,28 +80,3 @@ function getMultipleSelectionParams(listId)
|
||||
return oRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return column JSON declaration for row actions.
|
||||
* Could be part of column or columnDefs declaration of datatable.js.
|
||||
*
|
||||
* @param sTableId
|
||||
* @param iColumnTargetIndex
|
||||
* @returns {*}
|
||||
* @since 3.1.0
|
||||
*/
|
||||
function getRowActionsColumnDefinition(sTableId, iColumnTargetIndex = -1)
|
||||
{
|
||||
let aColumn = {
|
||||
type: "html",
|
||||
orderable: false,
|
||||
render: function ( data, type, row, meta ) {
|
||||
return $(`#${sTableId}_actions_buttons_template`).html();
|
||||
}
|
||||
};
|
||||
|
||||
if (iColumnTargetIndex !== -1) {
|
||||
aColumn['targets'] = iColumnTargetIndex;
|
||||
}
|
||||
|
||||
return aColumn;
|
||||
}
|
||||
|
||||
106
js/dataTables.row-actions.js
Normal file
106
js/dataTables.row-actions.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
const TABLE_ACTION_CONFIRMATION_PREFIX = 'table_action_row';
|
||||
const TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR = '#table-row-action-confirmation-dialog';
|
||||
|
||||
/**
|
||||
* Return column JSON declaration for row actions.
|
||||
* Could be part of column or columnDefs declaration of datatable.js.
|
||||
*
|
||||
* @param sTableId
|
||||
* @param iColumnTargetIndex
|
||||
* @returns {*}
|
||||
* @since 3.1.0
|
||||
*/
|
||||
function getRowActionsColumnDefinition(sTableId, iColumnTargetIndex = -1)
|
||||
{
|
||||
let aColumn = {
|
||||
type: "html",
|
||||
orderable: false,
|
||||
render: function ( data, type, row, meta ) {
|
||||
return $(`#${sTableId}_actions_buttons_template`).html();
|
||||
}
|
||||
};
|
||||
|
||||
if (iColumnTargetIndex !== -1) {
|
||||
aColumn['targets'] = iColumnTargetIndex;
|
||||
}
|
||||
|
||||
return aColumn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HandleActionRowConfirmation.
|
||||
*
|
||||
* @param sTitle title for confirmation dialog
|
||||
* @param sMessage message of the confirmation dialog
|
||||
* @param sDoNotShowAgainPreferenceKey iTop preference key to store "do not show again" flag
|
||||
* @param oConfirmHandler confirm button handler
|
||||
* @param aConfirmHandlerData confirm button handler data
|
||||
* @constructor
|
||||
*/
|
||||
const HandleActionRowConfirmation = function (sTitle, sMessage, sDoNotShowAgainPreferenceKey, oConfirmHandler, aConfirmHandlerData){
|
||||
|
||||
// confirmation preference
|
||||
if(sDoNotShowAgainPreferenceKey != null){
|
||||
|
||||
// retrieve need confirmation user preference
|
||||
let bNeedConfirmation = GetUserPreferenceAsBoolean(`${TABLE_ACTION_CONFIRMATION_PREFIX}.${sDoNotShowAgainPreferenceKey}`, true);
|
||||
|
||||
// confirm handler if no confirmation requested
|
||||
if(!bNeedConfirmation){
|
||||
oConfirmHandler(aConfirmHandlerData.datatable, aConfirmHandlerData.tr_element, aConfirmHandlerData.action_id, aConfirmHandlerData.row_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// fill confirmation dialog
|
||||
$('.ibo-row-action--confirmation--explanation', $(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR)).html(sMessage);
|
||||
$('.ibo-row-action--confirmation--do-not-show-again', $(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR)).toggle(sDoNotShowAgainPreferenceKey != null);
|
||||
|
||||
// open confirmation dialog
|
||||
$(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR).dialog({
|
||||
autoOpen: false,
|
||||
minWidth: 400,
|
||||
modal: true,
|
||||
title: sTitle,
|
||||
autoOpen: true,
|
||||
position: {my: "center center", at: "center center", of: $('body')},
|
||||
close: function () {
|
||||
// destroy dialog object
|
||||
$(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR).dialog( "destroy" );
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: Dict.S('UI:Button:Cancel'),
|
||||
class: 'ibo-is-alternative',
|
||||
click: function () {
|
||||
// close dialog
|
||||
$(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR).dialog('close');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: Dict.S('UI:Button:Ok'),
|
||||
class: 'ibo-is-primary',
|
||||
click: function () {
|
||||
// handle "do not show again" user preference
|
||||
if(sDoNotShowAgainPreferenceKey != null){
|
||||
// save preference
|
||||
const bDoNotShowAgain = $(this).find($('.ibo-row-action--confirmation--do-not-show-again--checkbox')).prop('checked');
|
||||
if (bDoNotShowAgain) {
|
||||
SetUserPreference(`${TABLE_ACTION_CONFIRMATION_PREFIX}.${sDoNotShowAgainPreferenceKey}`, 'false', true);
|
||||
}
|
||||
}
|
||||
// call confirm handler and close dialog
|
||||
if(oConfirmHandler(aConfirmHandlerData.datatable, aConfirmHandlerData.tr_element, aConfirmHandlerData.action_id, aConfirmHandlerData.row_data)){
|
||||
$(TABLE_ACTION_CONFIRMATION_DIALOG_SELECTOR).dialog('close');
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
58
js/links/link_set_worker.js
Normal file
58
js/links/link_set_worker.js
Normal file
@@ -0,0 +1,58 @@
|
||||
let LinkSetWorker = new function(){
|
||||
|
||||
// defines
|
||||
const ROUTER_BASE_URL = '../pages/ajax.render.php';
|
||||
const ROUTE_LINK_SET_DELETE_OBJECT = 'linkset.DeleteLinkedObject';
|
||||
const ROUTE_LINK_SET_DETACH_OBJECT = 'linkset.DetachLinkedObject';
|
||||
|
||||
/**
|
||||
* CallAjaxDeleteLinkedObject.
|
||||
*
|
||||
* @param sLinkedObjectClass
|
||||
* @param sLinkedObjectKey
|
||||
* @constructor
|
||||
*/
|
||||
const CallAjaxDeleteLinkedObject = function(sLinkedObjectClass, sLinkedObjectKey){
|
||||
$.post(`${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_DELETE_OBJECT}`, {
|
||||
linked_object_class: sLinkedObjectClass,
|
||||
linked_object_key: sLinkedObjectKey,
|
||||
transaction_id: $('#linkset_transactions_id').val()
|
||||
}, function (data) {
|
||||
if(data.data.success){
|
||||
alert('Operation succeeded, todo refresh table !!');
|
||||
}
|
||||
else{
|
||||
alert('Operation failed, todo feedback !!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* CallAjaxDetachLinkedObject.
|
||||
*
|
||||
* @param sLinkedObjectClass
|
||||
* @param sLinkedObjectKey
|
||||
* @param sExternalKeyAttCode
|
||||
* @constructor
|
||||
*/
|
||||
const CallAjaxDetachLinkedObject = function(sLinkedObjectClass, sLinkedObjectKey, sExternalKeyAttCode){
|
||||
$.post(`${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_DETACH_OBJECT}`, {
|
||||
linked_object_class: sLinkedObjectClass,
|
||||
linked_object_key: sLinkedObjectKey,
|
||||
external_key_att_code: sExternalKeyAttCode,
|
||||
transaction_id: $('#linkset_transactions_id').val()
|
||||
}, function (data) {
|
||||
if(data.data.success){
|
||||
alert('Operation succeeded, todo refresh table !!');
|
||||
}
|
||||
else{
|
||||
alert('Operation failed, todo feedback !!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
DeleteLinkedObject: CallAjaxDeleteLinkedObject,
|
||||
DetachLinkedObject: CallAjaxDetachLinkedObject
|
||||
}
|
||||
};
|
||||
@@ -32,18 +32,19 @@ $(function()
|
||||
do_search: true,
|
||||
submit_to: '../pages/ajax.render.php',
|
||||
submit_parameters: {},
|
||||
labels: { 'delete': 'Delete',
|
||||
modify: 'Modify...' ,
|
||||
creation_title: 'Creation of a new object...' ,
|
||||
create: 'Create...',
|
||||
add: 'Add...',
|
||||
remove: 'Remove',
|
||||
labels: {
|
||||
// 'delete': 'Delete',
|
||||
// modify: 'Modify...' ,
|
||||
creation_title: 'Creation of a new object...' ,
|
||||
// create: 'Create...',
|
||||
// add: 'Add...',
|
||||
// remove: 'Remove',
|
||||
selection_title: 'Objects selection'
|
||||
},
|
||||
buttons: ['create', 'delete'],
|
||||
// buttons: ['create', 'delete'],
|
||||
oWizardHelper: null
|
||||
},
|
||||
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
@@ -53,15 +54,14 @@ $(function()
|
||||
this.element
|
||||
.addClass('itop-directlinks');
|
||||
|
||||
|
||||
this.datatable = this.element.find('table.listResults');
|
||||
|
||||
var aButtonsTypes = ['delete', 'remove', 'modify', 'add', 'create'];
|
||||
this.oButtons = {};
|
||||
for(k in aButtonsTypes)
|
||||
{
|
||||
this.oButtons[aButtonsTypes[k]] = $('<button class="ibo-button ibo-is-regular ibo-is-neutral" type="button">' + this.options.labels[aButtonsTypes[k]] + '</button>');
|
||||
}
|
||||
// var aButtonsTypes = ['delete', 'remove', 'modify', 'add', 'create'];
|
||||
// this.oButtons = {};
|
||||
// for(k in aButtonsTypes)
|
||||
// {
|
||||
// this.oButtons[aButtonsTypes[k]] = $('<button class="ibo-button ibo-is-regular ibo-is-neutral" type="button">' + this.options.labels[aButtonsTypes[k]] + '</button>');
|
||||
// }
|
||||
this.indicator = $('<span></span>');
|
||||
this.inputToBeCreated = $('<input type="hidden" name="'+this.options.input_name+'_tbc" value="{}">');
|
||||
this.toBeCreated = {};
|
||||
@@ -78,33 +78,33 @@ $(function()
|
||||
.after(this.inputToBeDeleted)
|
||||
.after(this.inputToBeAdded)
|
||||
.after(this.inputToBeRemoved)
|
||||
.after('<span style="float:left"> <img src="../images/tv-item-last.gif"> ')
|
||||
.after(this.indicator);
|
||||
for (k in this.options.buttons) {
|
||||
this.element.after(this.oButtons[this.options.buttons[k]]).after(' ');
|
||||
}
|
||||
|
||||
// for (k in this.options.buttons) {
|
||||
// this.element.after(this.oButtons[this.options.buttons[k]]).after(' ');
|
||||
// }
|
||||
|
||||
this.element.find('.selectList'+this.id).bind('change', function () {
|
||||
me._updateButtons();
|
||||
});
|
||||
this.oButtons['delete'].on('click', function () {
|
||||
$('.selectList'+me.id+':checked', me.element).each(function () {
|
||||
me._deleteRow($(this));
|
||||
});
|
||||
});
|
||||
this.oButtons['create'].on('click', function () {
|
||||
me._createRow();
|
||||
});
|
||||
this.oButtons['remove'].on('click', function () {
|
||||
$('.selectList'+me.id+':checked', me.element).each(function () {
|
||||
me._removeRow($(this));
|
||||
});
|
||||
});
|
||||
this.oButtons['add'].on('click', function () {
|
||||
me._selectToAdd();
|
||||
});
|
||||
// this.oButtons['delete'].on('click', function () {
|
||||
// me._deleteSelection();
|
||||
// });
|
||||
// this.oButtons['create'].on('click', function () {
|
||||
// me._createRow();
|
||||
// });
|
||||
// this.oButtons['remove'].on('click', function () {
|
||||
// $('.selectList'+me.id+':checked', me.element).each(function () {
|
||||
// me._removeRow($(this));
|
||||
// });
|
||||
// });
|
||||
// this.oButtons['add'].on('click', function () {
|
||||
// me._selectToAdd();
|
||||
// });
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
me._updateTableInformation();
|
||||
},
|
||||
|
||||
// called when created, and later when changing options
|
||||
@@ -135,24 +135,43 @@ $(function()
|
||||
var oChecked = $('.selectList'+this.id+':checked', this.element);
|
||||
switch (oChecked.length) {
|
||||
case 0:
|
||||
this.oButtons['delete'].prop('disabled', true);
|
||||
this.oButtons['remove'].prop('disabled', true);
|
||||
this.oButtons['modify'].prop('disabled', true);
|
||||
// this.oButtons['delete'].prop('disabled', true);
|
||||
// this.oButtons['remove'].prop('disabled', true);
|
||||
// this.oButtons['modify'].prop('disabled', true);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
this.oButtons['delete'].prop('disabled', false);
|
||||
this.oButtons['remove'].prop('disabled', false);
|
||||
this.oButtons['modify'].prop('disabled', false);
|
||||
// this.oButtons['delete'].prop('disabled', false);
|
||||
// this.oButtons['remove'].prop('disabled', false);
|
||||
// this.oButtons['modify'].prop('disabled', false);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.oButtons['delete'].prop('disabled', false);
|
||||
this.oButtons['remove'].prop('disabled', false);
|
||||
this.oButtons['modify'].prop('disabled', true);
|
||||
// this.oButtons['delete'].prop('disabled', false);
|
||||
// this.oButtons['remove'].prop('disabled', false);
|
||||
// this.oButtons['modify'].prop('disabled', true);
|
||||
break;
|
||||
}
|
||||
},
|
||||
_updateTableInformation: function(){
|
||||
|
||||
let nbChecked = $('tbody tr input:checked', this.element).length;
|
||||
let count = $('tbody tr input', this.element).length;
|
||||
|
||||
$('#linkedset_'+this.id+'_alert_information').toggleClass('ibo-is-information', nbChecked > 0);
|
||||
|
||||
if(nbChecked > 0){
|
||||
$('#'+this.id+'_btnRemove').prop('disabled', false);
|
||||
$('#linkedset_'+this.id+'_alert_information span[data-role="ibo-datatable-selection-value"]').text(nbChecked + ' / ' + count + ' éléments sélectionnés');
|
||||
}
|
||||
else{
|
||||
$('#'+this.id+'_btnRemove').prop('disabled', true);
|
||||
$('#linkedset_'+this.id+'_alert_information span[data-role="ibo-datatable-selection-value"]').text(count + ' éléments');
|
||||
}
|
||||
},
|
||||
_onSelectChange: function () {
|
||||
this._updateTableInformation();
|
||||
},
|
||||
_updateTable: function () {
|
||||
var me = this;
|
||||
/*
|
||||
@@ -167,7 +186,7 @@ $(function()
|
||||
this.oDlg.dialog('option', {position: {my: "center", at: "center", of: window}});
|
||||
},
|
||||
_createRow: function () {
|
||||
this.oButtons['create'].prop('disabled', true);
|
||||
// this.oButtons['create'].prop('disabled', true);
|
||||
this.indicator.html('<img src="../images/indicator.gif">');
|
||||
oParams = this.options.submit_parameters;
|
||||
oParams.operation = 'createObject';
|
||||
@@ -206,14 +225,14 @@ $(function()
|
||||
}
|
||||
});
|
||||
me.indicator.html('');
|
||||
me.oButtons['create'].prop('disabled', false);
|
||||
// me.oButtons['create'].prop('disabled', false);
|
||||
me._updateDlgPosition();
|
||||
|
||||
});
|
||||
},
|
||||
_selectToAdd: function()
|
||||
{
|
||||
this.oButtons['add'].prop('disabled', true);
|
||||
// this.oButtons['add'].prop('disabled', true);
|
||||
this.indicator.html('<img src="../images/indicator.gif">');
|
||||
oParams = this.options.submit_parameters;
|
||||
oParams.operation = 'selectObjectsToAdd';
|
||||
@@ -279,7 +298,7 @@ $(function()
|
||||
|
||||
});
|
||||
me.indicator.html('');
|
||||
me.oButtons['add'].prop('disabled', false);
|
||||
// me.oButtons['add'].prop('disabled', false);
|
||||
if (me.options.do_search)
|
||||
{
|
||||
me._onSearchToAdd();
|
||||
@@ -425,7 +444,9 @@ $(function()
|
||||
|
||||
var me = this;
|
||||
$.post(this.options.submit_to, oParams, function(data) {
|
||||
|
||||
var oInserted = $(data);
|
||||
|
||||
oInserted.find('input:checkbox').each(function() {
|
||||
var iKey = parseInt($(this).val(), 10); // Number in base 10
|
||||
me.toBeAdded.push(iKey);
|
||||
@@ -436,12 +457,20 @@ $(function()
|
||||
me.inputToBeRemoved.val(JSON.stringify(me.toBeRemoved));
|
||||
me.inputToBeDeleted.val(JSON.stringify(me.toBeDeleted));
|
||||
|
||||
//me.datatable.find('tbody').append(data);
|
||||
$('#datatable_'+me.id+' .dataTables_empty').hide();
|
||||
me.datatable.find('tbody').append(data);
|
||||
|
||||
// add actions on each row...
|
||||
oInserted.each(function(){
|
||||
$('td:last-child',$(this)).after('<td>' + $(`#datatable_${oParams.iInputId}_actions_buttons_template`).html() +'</td>');
|
||||
me.datatable.find('tbody').append(this.outerHTML);
|
||||
});
|
||||
|
||||
|
||||
me._updateTable();
|
||||
me.indicator.html('');
|
||||
me.oButtons['add'].prop('disabled', false);
|
||||
// me.oButtons['add'].prop('disabled', false);
|
||||
|
||||
me._updateTableInformation();
|
||||
});
|
||||
},
|
||||
subclassSelected: function()
|
||||
@@ -506,7 +535,7 @@ $(function()
|
||||
oParams.tempId = nextIdx;
|
||||
var me = this;
|
||||
|
||||
this.oButtons['create'].prop('disabled', true);
|
||||
// this.oButtons['create'].prop('disabled', true);
|
||||
this.indicator.html('<img src="../images/indicator.gif">');
|
||||
|
||||
$.post(this.options.submit_to, oParams, function (data) {
|
||||
@@ -516,7 +545,7 @@ $(function()
|
||||
|
||||
me._updateTable();
|
||||
me.indicator.html('');
|
||||
me.oButtons['create'].prop('disabled', false);
|
||||
// me.oButtons['create'].prop('disabled', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -530,6 +559,12 @@ $(function()
|
||||
$('.wizContainer', this.oDlg).height(dlgHeight-20);
|
||||
$('#SearchResultsToAdd_'+this.id).height(dlgHeight-50-searchHeight);
|
||||
},
|
||||
_deleteSelection: function(){
|
||||
var me = this;
|
||||
$('.selectList'+me.id+':checked', me.element).each(function () {
|
||||
me._deleteRow($(this));
|
||||
});
|
||||
},
|
||||
_deleteRow: function (oCheckbox) {
|
||||
var iObjKey = parseInt(oCheckbox.val(), 10); // Number in base 10
|
||||
|
||||
@@ -555,6 +590,13 @@ $(function()
|
||||
oRow.remove();
|
||||
this._updateButtons();
|
||||
this._updateTable();
|
||||
this._updateTableInformation();
|
||||
},
|
||||
_removeSelection: function(){
|
||||
var me = this;
|
||||
$('.selectList'+me.id+':checked', me.element).each(function () {
|
||||
me._removeRow($(this));
|
||||
});
|
||||
},
|
||||
_removeRow: function(oCheckbox)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* @param sExtKeyToRemote
|
||||
* @param bDoSearch
|
||||
* @param iMaxAddedId
|
||||
* @param aRemoved
|
||||
* @constructor
|
||||
*
|
||||
* @since 3.0.0 Add iMaxAddedId parameter
|
||||
@@ -56,13 +57,47 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
|
||||
oInput.closest('form').on('submit', function () {
|
||||
return me.OnFormSubmit();
|
||||
});
|
||||
|
||||
this.UpdateTableInformation();
|
||||
};
|
||||
|
||||
this.UpdateTableInformation = function(){
|
||||
|
||||
let nbChecked = $('#linkedset_'+me.id+' .selection:checked').length;
|
||||
let count = $('#linkedset_'+this.id+' tbody tr').length;
|
||||
|
||||
$('#linkedset_'+me.iInputId+'_alert_information').toggleClass('ibo-is-information', nbChecked > 0);
|
||||
|
||||
if(nbChecked > 0){
|
||||
$('#'+me.id+'_btnRemove').prop('disabled', false);
|
||||
$('#linkedset_'+me.iInputId+'_alert_information span[data-role="ibo-datatable-selection-value"]').text(nbChecked + ' / ' + count + ' éléments sélectionnés');
|
||||
}
|
||||
else{
|
||||
$('#'+me.id+'_btnRemove').prop('disabled', true);
|
||||
$('#linkedset_'+me.iInputId+'_alert_information span[data-role="ibo-datatable-selection-value"]').text(count + ' éléments');
|
||||
}
|
||||
}
|
||||
|
||||
this.RemoveSelected = function () {
|
||||
let my_id = '#'+me.id;
|
||||
$('#linkedset_'+me.id+' .selection:checked').closest('tr').each(function () {
|
||||
$('#datatable_'+me.id).DataTable().row($(this)).remove().draw();
|
||||
var oCheckbox = $(this).find('.selection');
|
||||
me.Remove($(this));
|
||||
});
|
||||
// Disable the button since all the selected items have been removed
|
||||
$(my_id+'_btnRemove').prop('disabled', true);
|
||||
|
||||
if ($('#linkedset_'+this.id+' .selection').length == 0)
|
||||
{
|
||||
// All items were removed: add a dummy hidden input to make sure that the linkset will be updated (emptied) when posted
|
||||
$('#'+me.id+'_empty_row').show();
|
||||
}
|
||||
|
||||
this.UpdateTableInformation();
|
||||
};
|
||||
|
||||
this.Remove = function(oRowElement){
|
||||
$('#datatable_'+me.id).DataTable().row($(oRowElement)).remove().draw();
|
||||
var oCheckbox = $(oRowElement).find('.selection');
|
||||
let iLink = $(oCheckbox).attr('data-link-id');
|
||||
if (iLink > 0) {
|
||||
me.aRemoved.push(iLink);
|
||||
@@ -79,32 +114,16 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
|
||||
}
|
||||
me.aAdded[iUniqueId] = null;
|
||||
}
|
||||
});
|
||||
// Disable the button since all the selected items have been removed
|
||||
$(my_id+'_btnRemove').prop('disabled', true);
|
||||
|
||||
if ($('#linkedset_'+this.id+' .selection').length == 0)
|
||||
{
|
||||
// All items were removed: add a dummy hidden input to make sure that the linkset will be updated (emptied) when posted
|
||||
$('#'+me.id+'_empty_row').show();
|
||||
this.UpdateTableInformation();
|
||||
}
|
||||
};
|
||||
|
||||
this.OnSelectChange = function () {
|
||||
let nbChecked = $('#linkedset_'+me.id+' .selection:checked').length;
|
||||
if (nbChecked > 0)
|
||||
{
|
||||
$('#'+me.id+'_btnRemove').prop('disabled', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#'+me.id+'_btnRemove').prop('disabled', true);
|
||||
}
|
||||
this.UpdateTableInformation();
|
||||
};
|
||||
|
||||
this.AddObjects = function () {
|
||||
let me = this;
|
||||
$('#'+me.id+'_indicatorAdd').html(' <img src="../images/indicator.gif"/>');
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
|
||||
let sPromiseId = 'ajax_promise_'+me.id;
|
||||
@@ -179,6 +198,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
|
||||
};
|
||||
|
||||
this.DoAddObjects = function () {
|
||||
|
||||
let theMap = {
|
||||
sAttCode: me.sAttCode,
|
||||
iInputId: me.iInputId,
|
||||
|
||||
@@ -29,6 +29,10 @@ class InstalledVersions
|
||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
|
||||
@@ -229,6 +229,8 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\StaticTable\\FormTable\\FormTable' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/StaticTable/FormTable/FormTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\StaticTable\\StaticTable' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/StaticTable/StaticTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\tTableRowActions' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/tTableRowActions.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dialog\\Dialog' => $baseDir . '/sources/Application/UI/Base/Component/Dialog/Dialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dialog\\DialogUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Dialog/DialogUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldBadge\\FieldBadge' => $baseDir . '/sources/Application/UI/Base/Component/FieldBadge/FieldBadge.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldBadge\\FieldBadgeUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/FieldBadge/FieldBadgeUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldSet\\FieldSet' => $baseDir . '/sources/Application/UI/Base/Component/FieldSet/FieldSet.php',
|
||||
@@ -342,8 +344,12 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\DisplayBlock\\BlockCsv\\BlockCsv' => $baseDir . '/sources/Application/UI/DisplayBlock/BlockCsv/BlockCsv.php',
|
||||
'Combodo\\iTop\\Application\\UI\\DisplayBlock\\BlockList\\BlockList' => $baseDir . '/sources/Application/UI/DisplayBlock/BlockList/BlockList.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Helper\\UIHelper' => $baseDir . '/sources/Application/UI/Helper/UIHelper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksEdit\\BlockIndirectLinksEdit' => $baseDir . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksEdit/BlockIndirectLinksEdit.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockObjectPickerDialog\\BlockObjectPickerDialog' => $baseDir . '/sources/Application/UI/Links/Indirect/BlockObjectPickerDialog/BlockObjectPickerDialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\AbstractBlockLinksViewTable' => $baseDir . '/sources/Application/UI/Links/AbstractBlockLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Direct\\BlockDirectLinksEditTable' => $baseDir . '/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Direct\\BlockDirectLinksViewTable' => $baseDir . '/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksEditTable' => $baseDir . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksViewTable' => $baseDir . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockObjectPickerDialog' => $baseDir . '/sources/Application/UI/Links/Indirect/BlockObjectPickerDialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Preferences\\BlockShortcuts\\BlockShortcuts' => $baseDir . '/sources/Application/UI/Preferences/BlockShortcuts/BlockShortcuts.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Printable\\BlockPrintHeader\\BlockPrintHeader' => $baseDir . '/sources/Application/UI/Printable/BlockPrintHeader/BlockPrintHeader.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => $baseDir . '/sources/Composer/iTopComposer.php',
|
||||
@@ -351,6 +357,7 @@ return array(
|
||||
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
|
||||
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => $baseDir . '/sources/Controller/Base/Layout/ActivityPanelController.php',
|
||||
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => $baseDir . '/sources/Controller/Base/Layout/ObjectController.php',
|
||||
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => $baseDir . '/sources/Controller/Links/LinksetController.php',
|
||||
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => $baseDir . '/sources/Controller/OAuth/OAuthLandingController.php',
|
||||
'Combodo\\iTop\\Controller\\PreferencesController' => $baseDir . '/sources/Controller/PreferencesController.php',
|
||||
'Combodo\\iTop\\Controller\\iController' => $baseDir . '/sources/Controller/iController.php',
|
||||
@@ -2927,6 +2934,7 @@ return array(
|
||||
'iTopStandardURLMaker' => $baseDir . '/application/applicationcontext.class.inc.php',
|
||||
'iTopWebPage' => $baseDir . '/sources/Application/WebPage/iTopWebPage.php',
|
||||
'iTopWizardWebPage' => $baseDir . '/sources/Application/WebPage/iTopWizardWebPage.php',
|
||||
'iTopXmlException' => $baseDir . '/application/exceptions/iTopXmlException.php',
|
||||
'iWorkingTimeComputer' => $baseDir . '/core/computing.inc.php',
|
||||
'lnkTriggerAction' => $baseDir . '/core/trigger.class.inc.php',
|
||||
'ormCaseLog' => $baseDir . '/core/ormcaselog.class.inc.php',
|
||||
|
||||
@@ -594,6 +594,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\StaticTable\\FormTable\\FormTable' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/StaticTable/FormTable/FormTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\StaticTable\\StaticTable' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/StaticTable/StaticTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\tTableRowActions' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/tTableRowActions.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dialog\\Dialog' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dialog/Dialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dialog\\DialogUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dialog/DialogUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldBadge\\FieldBadge' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/FieldBadge/FieldBadge.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldBadge\\FieldBadgeUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/FieldBadge/FieldBadgeUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\FieldSet\\FieldSet' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/FieldSet/FieldSet.php',
|
||||
@@ -707,8 +709,12 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\DisplayBlock\\BlockCsv\\BlockCsv' => __DIR__ . '/../..' . '/sources/Application/UI/DisplayBlock/BlockCsv/BlockCsv.php',
|
||||
'Combodo\\iTop\\Application\\UI\\DisplayBlock\\BlockList\\BlockList' => __DIR__ . '/../..' . '/sources/Application/UI/DisplayBlock/BlockList/BlockList.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Helper\\UIHelper' => __DIR__ . '/../..' . '/sources/Application/UI/Helper/UIHelper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksEdit\\BlockIndirectLinksEdit' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksEdit/BlockIndirectLinksEdit.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockObjectPickerDialog\\BlockObjectPickerDialog' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Indirect/BlockObjectPickerDialog/BlockObjectPickerDialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\AbstractBlockLinksViewTable' => __DIR__ . '/../..' . '/sources/Application/UI/Links/AbstractBlockLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Direct\\BlockDirectLinksEditTable' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Direct\\BlockDirectLinksViewTable' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksEditTable' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockIndirectLinksViewTable' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Links\\Indirect\\BlockObjectPickerDialog' => __DIR__ . '/../..' . '/sources/Application/UI/Links/Indirect/BlockObjectPickerDialog.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Preferences\\BlockShortcuts\\BlockShortcuts' => __DIR__ . '/../..' . '/sources/Application/UI/Preferences/BlockShortcuts/BlockShortcuts.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Printable\\BlockPrintHeader\\BlockPrintHeader' => __DIR__ . '/../..' . '/sources/Application/UI/Printable/BlockPrintHeader/BlockPrintHeader.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => __DIR__ . '/../..' . '/sources/Composer/iTopComposer.php',
|
||||
@@ -716,6 +722,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
|
||||
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ActivityPanelController.php',
|
||||
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ObjectController.php',
|
||||
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => __DIR__ . '/../..' . '/sources/Controller/Links/LinksetController.php',
|
||||
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => __DIR__ . '/../..' . '/sources/Controller/OAuth/OAuthLandingController.php',
|
||||
'Combodo\\iTop\\Controller\\PreferencesController' => __DIR__ . '/../..' . '/sources/Controller/PreferencesController.php',
|
||||
'Combodo\\iTop\\Controller\\iController' => __DIR__ . '/../..' . '/sources/Controller/iController.php',
|
||||
@@ -3292,6 +3299,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'iTopStandardURLMaker' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
|
||||
'iTopWebPage' => __DIR__ . '/../..' . '/sources/Application/WebPage/iTopWebPage.php',
|
||||
'iTopWizardWebPage' => __DIR__ . '/../..' . '/sources/Application/WebPage/iTopWizardWebPage.php',
|
||||
'iTopXmlException' => __DIR__ . '/../..' . '/application/exceptions/iTopXmlException.php',
|
||||
'iWorkingTimeComputer' => __DIR__ . '/../..' . '/core/computing.inc.php',
|
||||
'lnkTriggerAction' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
|
||||
'ormCaseLog' => __DIR__ . '/../..' . '/core/ormcaselog.class.inc.php',
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '8a3e07dd80c8316d68ad44a892c51f4ed5de572c',
|
||||
'reference' => '0520e72b9d1190cab294aebc5ab7542a18d2bc51',
|
||||
'name' => 'combodo/itop',
|
||||
'dev' => true,
|
||||
),
|
||||
@@ -25,7 +25,7 @@
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '8a3e07dd80c8316d68ad44a892c51f4ed5de572c',
|
||||
'reference' => '0520e72b9d1190cab294aebc5ab7542a18d2bc51',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'combodo/tcpdf' => array(
|
||||
|
||||
@@ -1056,7 +1056,7 @@ EOF
|
||||
$aParams = utils::ReadParam('params', '', false, 'raw_data');
|
||||
$sDashletClass = $aParams['attr_dashlet_class'];
|
||||
$sDashletType = $aParams['attr_dashlet_type'];
|
||||
$sDashletId = utils::HtmlEntities($aParams['attr_dashlet_id']);
|
||||
$sDashletId = utils::HtmlEntities($aParams['attr_dashlet_id']);
|
||||
$aUpdatedProperties = $aParams['updated']; // Code of the changed properties as an array: 'attr_xxx', 'attr_xxy', etc...
|
||||
$aPreviousValues = $aParams['previous_values']; // hash array: 'attr_xxx' => 'old_value'
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet')) {
|
||||
|
||||
@@ -40,6 +40,7 @@ class DataTable extends UIContentBlock
|
||||
'js/dataTables.main.js',
|
||||
'js/dataTables.settings.js',
|
||||
'js/dataTables.pipeline.js',
|
||||
'js/dataTables.row-actions.js',
|
||||
];
|
||||
|
||||
protected $aOptions;//list of specific options for display datatable
|
||||
@@ -52,6 +53,8 @@ class DataTable extends UIContentBlock
|
||||
*/
|
||||
protected $aInitDisplayData;
|
||||
|
||||
public const DEFAULT_ACTION_ROW_CONFIRMATION = true;
|
||||
|
||||
|
||||
/**
|
||||
* Panel constructor.
|
||||
|
||||
@@ -211,7 +211,7 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
|
||||
foreach ($oTable->GetRowActions() as $iKey => $aAction) {
|
||||
$oButton = ButtonUIBlockFactory::MakeIconAction(
|
||||
array_key_exists('icon_classes', $aAction) ? $aAction['icon_classes'] : 'fas fa-question',
|
||||
array_key_exists('tooltip', $aAction) ? $aAction['tooltip'] : '',
|
||||
array_key_exists('tooltip', $aAction) ? Dict::S($aAction['tooltip']) : '',
|
||||
array_key_exists('name', $aAction) ? $aAction['name'] : 'undefined'
|
||||
);
|
||||
$oButton->SetDataAttributes(['action-id' => $iKey]);
|
||||
@@ -522,7 +522,6 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
|
||||
$oDataTable->SetRowActions($aExtraParams['row_actions']);
|
||||
}
|
||||
|
||||
|
||||
return $oDataTable;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ class StaticTable extends UIContentBlock
|
||||
'js/dataTables.main.js',
|
||||
'js/dataTables.settings.js',
|
||||
'js/dataTables.pipeline.js',
|
||||
'js/dataTables.row-actions.js',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\DataTable;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Dialog\DialogUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
|
||||
/**
|
||||
* Trait tTableRowActions
|
||||
*
|
||||
@@ -17,12 +21,20 @@ namespace Combodo\iTop\Application\UI\Base\Component\DataTable;
|
||||
*/
|
||||
trait tTableRowActions
|
||||
{
|
||||
/** @var bool static dialog initialized flag to avoid multiple html markups */
|
||||
static public bool $bDialogInitialized = false;
|
||||
|
||||
/**
|
||||
* @var $aRowActions array array of row actions
|
||||
* action => {
|
||||
* tooltip: string,
|
||||
* icon_classes: string,
|
||||
* js_row_action: string
|
||||
* js_row_action: string,
|
||||
* confirmation => {
|
||||
* message: string,
|
||||
* message_row_data: string,
|
||||
* remember_choice_pref_key: string
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
protected $aRowActions;
|
||||
@@ -70,4 +82,31 @@ trait tTableRowActions
|
||||
{
|
||||
return DataTableUIBlockFactory::MakeActionRowToolbarTemplate($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetRowActionsConfirmDialog.
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Component\Html\Html
|
||||
*/
|
||||
public function GetRowActionsConfirmDialog()
|
||||
{
|
||||
static::$bDialogInitialized = true;
|
||||
|
||||
$oDialog = DialogUIBlockFactory::MakeNeutral('', '<div class="ibo-row-action--confirmation--explanation"></div>', 'table-row-action-confirmation-dialog');
|
||||
|
||||
$oContent = UIContentBlockUIBlockFactory::MakeStandard();
|
||||
$oContent->AddCSSClass('ibo-row-action--confirmation--do-not-show-again');
|
||||
$checkBox = InputUIBlockFactory::MakeStandard('checkbox', 'do_not_show_again', false);
|
||||
$checkBox->AddCSSClass('ibo-row-action--confirmation--do-not-show-again--checkbox');
|
||||
$checkBox->SetLabel(\Dict::S('UI:UserPref:DoNotShowAgain'));
|
||||
$oContent->AddSubBlock($checkBox);
|
||||
$oDialog->AddSubBlock($oContent);
|
||||
|
||||
return $oDialog;
|
||||
}
|
||||
|
||||
public function GetRowActionsConfirmDialogInitializedFlag()
|
||||
{
|
||||
return static::$bDialogInitialized;
|
||||
}
|
||||
}
|
||||
109
sources/Application/UI/Base/Component/Dialog/Dialog.php
Normal file
109
sources/Application/UI/Base/Component/Dialog/Dialog.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 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
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\Dialog;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
|
||||
/**
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Base\Component\Dialog
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class Dialog extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-dialog';
|
||||
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/dialog/layout';
|
||||
public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'base/components/dialog/layout';
|
||||
public const DEFAULT_JS_FILES_REL_PATH = [
|
||||
'js/components/dialog.js',
|
||||
];
|
||||
|
||||
/** @var string $sTitle */
|
||||
protected string $sTitle;
|
||||
|
||||
/** @var string $sContent */
|
||||
protected string $sContent;
|
||||
|
||||
/**
|
||||
* Alert constructor.
|
||||
*
|
||||
* @param string $sTitle
|
||||
* @param string $sContent
|
||||
* @param string|null $sId
|
||||
*/
|
||||
public function __construct(string $sTitle = '', string $sContent = '', ?string $sId = null)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->sContent = $sContent;
|
||||
if (!empty($sContent)) {
|
||||
$this->AddSubBlock(new Html($sContent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetTitle(): string
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTitle Title of the alert
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetTitle(string $sTitle): Dialog
|
||||
{
|
||||
$this->sTitle = $sTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw HTML content, should be already sanitized.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetContent(): string
|
||||
{
|
||||
return $this->sContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the raw HTML content, must be already sanitized.
|
||||
*
|
||||
* @param string $sContent The raw HTML content, must be already sanitized
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetContent(string $sContent): Dialog
|
||||
{
|
||||
$this->sContent = $sContent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 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
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\Dialog;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\AbstractUIBlockFactory;
|
||||
|
||||
/**
|
||||
* Class DialogUIBlockFactory
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Base\Component\Dialog
|
||||
*/
|
||||
class DialogUIBlockFactory extends AbstractUIBlockFactory
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public const TWIG_TAG_NAME = 'UIDialog';
|
||||
/** @inheritDoc */
|
||||
public const UI_BLOCK_CLASS_NAME = Dialog::class;
|
||||
|
||||
/**
|
||||
* Make a basis Dialog component
|
||||
*
|
||||
* @param string $sTitle Title of the alert
|
||||
* @param string $sContent The raw HTML content, must be already sanitized
|
||||
* @param string|null $sId id of the html block
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Component\Alert\Alert
|
||||
*/
|
||||
public static function MakeNeutral(string $sTitle = '', string $sContent = '', ?string $sId = null)
|
||||
{
|
||||
return new Dialog($sTitle, $sContent, $sId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
170
sources/Application/UI/Links/AbstractBlockLinksViewTable.php
Normal file
170
sources/Application/UI/Links/AbstractBlockLinksViewTable.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class AbstractBlockLinksViewTable
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Links
|
||||
*/
|
||||
abstract class AbstractBlockLinksViewTable extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-abstract-block-links-view-table';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/layout';
|
||||
public const DEFAULT_JS_FILES_REL_PATH = [
|
||||
'js/links/link_set_worker.js',
|
||||
];
|
||||
|
||||
/** @var \DBObject $oDbObject db object witch link set belongs to */
|
||||
protected \DBObject $oDbObject;
|
||||
|
||||
/** @var string $sObjectClass db object class name */
|
||||
protected string $sObjectClass;
|
||||
|
||||
/** @var string $sAttCode db object link set attribute code */
|
||||
protected string $sAttCode;
|
||||
|
||||
/** @var \AttributeLinkedSet $oAttDef attribute link set */
|
||||
protected \AttributeLinkedSet $oAttDef;
|
||||
|
||||
/** @var string $sTargetClass links target classname */
|
||||
protected string $sTargetClass;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param \DBObject $oDbObject
|
||||
* @param string $sObjectClass
|
||||
* @param string $sAttCode
|
||||
* @param \AttributeLinkedSet $oAttDef
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(\WebPage $oPage, \DBObject $oDbObject, string $sObjectClass, string $sAttCode, \AttributeLinkedSet $oAttDef)
|
||||
{
|
||||
parent::__construct('', ["ibo-block-links-table"]);
|
||||
|
||||
// retrieve parameters
|
||||
$this->oAttDef = $oAttDef;
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->sObjectClass = $sObjectClass;
|
||||
$this->oDbObject = $oDbObject;
|
||||
|
||||
// Initialization
|
||||
$this->Init();
|
||||
|
||||
// UI Initialization
|
||||
$this->InitUI($oPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function Init()
|
||||
{
|
||||
$this->sTargetClass = $this->GetTargetClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize UI.
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private function InitUI(\WebPage $oPage)
|
||||
{
|
||||
// header
|
||||
$this->InitHeader();;
|
||||
|
||||
// Table
|
||||
$this->InitTable($oPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* InitHeader.
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private function InitHeader()
|
||||
{
|
||||
// MedallionIcon
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($this->sTargetClass, false));
|
||||
$oClassIcon->SetDescription($this->oAttDef->GetDescription())->AddCSSClass('ibo-block-list--medallion');
|
||||
$this->AddSubBlock($oClassIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* InitTable.
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @return void
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
private function InitTable(\WebPage $oPage)
|
||||
{
|
||||
// retrieve db object set
|
||||
$oOrmLinkSet = $this->oDbObject->Get($this->sAttCode);
|
||||
$oLinkSet = $oOrmLinkSet->ToDBObjectSet(\utils::ShowObsoleteData());
|
||||
|
||||
// add list block
|
||||
$oBlock = new \DisplayBlock($oLinkSet->GetFilter(), 'list', false);
|
||||
$this->AddSubBlock($oBlock->GetRenderContent($oPage, $this->GetExtraParam(), 'rel_'.$this->sAttCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* GetExtraParam.
|
||||
*
|
||||
* Provide parameters for display block as list.
|
||||
*
|
||||
* @see \DisplayBlock::RenderList
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
abstract function GetExtraParam(): array;
|
||||
|
||||
/**
|
||||
* Return row actions.
|
||||
*
|
||||
* Register row actions for table.
|
||||
*
|
||||
* @see \Combodo\iTop\Application\UI\Base\Component\DataTable\tTableRowActions
|
||||
*
|
||||
* @return \string[][]
|
||||
*/
|
||||
abstract function GetRowActions(): array;
|
||||
|
||||
/**
|
||||
* GetTargetClass.
|
||||
*
|
||||
* Return link set target class.
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
abstract function GetTargetClass(): string;
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Direct;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class BlockDirectLinksEditTable
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Links\Direct
|
||||
*/
|
||||
class BlockDirectLinksEditTable extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-block-direct-links-edit-table';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/direct/block-direct-links-edit-table/layout';
|
||||
|
||||
/** @var \UILinksWidgetDirect */
|
||||
public \UILinksWidgetDirect $oUILinksDirectWidget;
|
||||
|
||||
/** @var \AttributeLinkedSet */
|
||||
private \AttributeLinkedSet $oAttributeLinkedSet;
|
||||
|
||||
/** @var string */
|
||||
public string $sInputName;
|
||||
|
||||
/** @var array */
|
||||
public array $aLabels;
|
||||
|
||||
/** @var string */
|
||||
public string $sSubmitUrl;
|
||||
|
||||
/** @var string */
|
||||
public string $sWizHelper;
|
||||
|
||||
/** @var string */
|
||||
public string $sJSDoSearch;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \UILinksWidgetDirect $oUILinksDirectWidget
|
||||
* @param string $sId
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(\UILinksWidgetDirect $oUILinksDirectWidget, string $sId)
|
||||
{
|
||||
parent::__construct($sId, ["ibo-block-direct-links--edit-in-place"]);
|
||||
|
||||
// Retrieve parameters
|
||||
$this->oUILinksDirectWidget = $oUILinksDirectWidget;
|
||||
|
||||
// compute
|
||||
$this->aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
|
||||
);
|
||||
$oContext = new \ApplicationContext();
|
||||
$this->sSubmitUrl = \utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !\utils::IsHighCardinality($this->oUILinksDirectWidget->GetLinkedClass());
|
||||
$this->sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
|
||||
// Initialization
|
||||
$this->Init();
|
||||
|
||||
// Initialize UI
|
||||
$this->InitUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisation.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function Init()
|
||||
{
|
||||
$this->oAttributeLinkedSet = MetaModel::GetAttributeDef($this->oUILinksDirectWidget->GetClass(), $this->oUILinksDirectWidget->GetAttCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize UI.
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function InitUI()
|
||||
{
|
||||
// MedallionIcon
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($this->oUILinksDirectWidget->GetLinkedClass(), false));
|
||||
$oClassIcon->SetDescription($this->oAttributeLinkedSet->GetDescription());
|
||||
$oClassIcon->AddCSSClass('ibo-block-list--medallion');
|
||||
$this->AddSubBlock($oClassIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param \DBObjectSet $oValue
|
||||
* @param string $sFormPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitTable(\WebPage $oPage, \DBObjectSet $oValue, string $sFormPrefix)
|
||||
{
|
||||
/** @todo fields initialization */
|
||||
$this->sInputName = $sFormPrefix.'attr_'.$this->oUILinksDirectWidget->GetAttCode();
|
||||
$this->sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
|
||||
try {
|
||||
$aAttribs = $this->oUILinksDirectWidget->GetTableConfig();
|
||||
$aRows = $this->GetTableRows($oPage, $oValue);
|
||||
$aRowActions = $this->GetRowActions();
|
||||
$oDatatable = DataTableUIBlockFactory::MakeForForm($this->oUILinksDirectWidget->GetInputId(), $aAttribs, $aRows, '', $aRowActions);
|
||||
$oDatatable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
|
||||
$aTablePanel = PanelUIBlockFactory::MakeNeutral('');
|
||||
$aTablePanel->SetSubTitle(sprintf('Total: %d objects.', count($aRows)));
|
||||
$oToolbar = ToolbarUIBlockFactory::MakeForButton();
|
||||
$oActionButtonUnlink = ButtonUIBlockFactory::MakeNeutral('Unlink');
|
||||
$oActionButtonUnlink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._removeSelection();");
|
||||
$oToolbar->AddSubBlock($oActionButtonUnlink);
|
||||
$oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link');
|
||||
$oActionButtonLink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._selectToAdd();");
|
||||
$oToolbar->AddSubBlock($oActionButtonLink);
|
||||
$oActionButtonCreate = ButtonUIBlockFactory::MakeNeutral('Create');
|
||||
$oActionButtonCreate->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._createRow();");
|
||||
$oToolbar->AddSubBlock($oActionButtonCreate);
|
||||
$oActionButtonDelete = ButtonUIBlockFactory::MakeNeutral('Delete');
|
||||
$oActionButtonDelete->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._deleteSelection();");
|
||||
$oToolbar->AddSubBlock($oActionButtonDelete);
|
||||
$aTablePanel->AddToolbarBlock($oToolbar);
|
||||
$aTablePanel->AddSubBlock($oDatatable);
|
||||
$this->AddSubBlock($aTablePanel);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$oAlert = AlertUIBlockFactory::MakeForDanger('error', 'error while trying to load datatable');
|
||||
$oAlert->SetIsClosable(false);
|
||||
$oAlert->SetIsCollapsible(false);
|
||||
$this->AddSubBlock($oAlert);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return table rows.
|
||||
*
|
||||
* @param \DBObjectSet $oValue
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function GetTableRows(\WebPage $oPage, \DBObjectSet $oValue): array
|
||||
{
|
||||
// result data
|
||||
$aRows = array();
|
||||
|
||||
// set pointer to start
|
||||
$oValue->Rewind();
|
||||
|
||||
// create a row table for each value...
|
||||
while ($oLinkObj = $oValue->Fetch()) {
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->oUILinksDirectWidget->GetInputId().'" onClick="oWidget'.$this->oUILinksDirectWidget->GetInputId().'.directlinks(\'instance\')._onSelectChange();" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach ($this->oUILinksDirectWidget->GetZList() as $sLinkedAttCode) {
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
|
||||
// tentative d'ajout des attributs en édition
|
||||
// $sValue = $oLinkObj->Get($sLinkedAttCode);
|
||||
// $sDisplayValue = $oLinkObj->GetEditValue($sLinkedAttCode);
|
||||
// $oAttDef = MetaModel::GetAttributeDef($this->oUILinksDirectWidget->GetLinkedClass(), $sLinkedAttCode);
|
||||
//
|
||||
// $aRow[$sLinkedAttCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
|
||||
// .\cmdbAbstractObject::GetFormElementForField(
|
||||
// $oPage,
|
||||
// $this->oUILinksDirectWidget->GetLinkedClass(),
|
||||
// $sLinkedAttCode,
|
||||
// $oAttDef,
|
||||
// $sValue,
|
||||
// $sDisplayValue,
|
||||
// $this->GetFieldId($oValue, $sLinkedAttCode),
|
||||
// ']',
|
||||
// 0,
|
||||
// []
|
||||
// )
|
||||
// .'</div></div></div>';
|
||||
}
|
||||
$aRows[] = $aRow;
|
||||
}
|
||||
|
||||
return $aRows;
|
||||
}
|
||||
|
||||
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
|
||||
{
|
||||
$sFieldId = $this->oUILinksDirectWidget->GetInputId().'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
|
||||
return ($bSafe) ? \utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return row actions.
|
||||
*
|
||||
* @return \string[][]
|
||||
*/
|
||||
private function GetRowActions(): array
|
||||
{
|
||||
$aRowActions = array();
|
||||
|
||||
if (!$this->oAttributeLinkedSet->GetReadOnly()) {
|
||||
$aRowActions[] = array(
|
||||
'tooltip' => 'remove link',
|
||||
'icon_classes' => 'fas fa-minus',
|
||||
'js_row_action' => "$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._deleteRow($(':checkbox', oTrElement));",
|
||||
);
|
||||
}
|
||||
|
||||
return $aRowActions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Direct;
|
||||
|
||||
use Combodo\iTop\Application\UI\Links\AbstractBlockLinksViewTable;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class BlockDirectLinksViewTable
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Links\Direct
|
||||
*/
|
||||
class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
|
||||
{
|
||||
public const BLOCK_CODE = 'ibo-block-direct-links-view-table';
|
||||
public const REQUIRES_ANCESTORS_DEFAULT_JS_FILES = true;
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetTargetClass(): string
|
||||
{
|
||||
return $this->oAttDef->GetLinkedClass();
|
||||
}
|
||||
|
||||
/** @inheritdoc * */
|
||||
public function GetExtraParam(): array
|
||||
{
|
||||
return array(
|
||||
'target_attr' => $this->oAttDef->GetExtKeyToMe(),
|
||||
'object_id' => $this->oDbObject->GetKey(),
|
||||
'menu' => MetaModel::GetConfig()->Get('allow_menu_on_linkset'),
|
||||
'default' => $this->GetDefault(),
|
||||
'table_id' => $this->sObjectClass.'_'.$this->sAttCode,
|
||||
'row_actions' => $this->GetRowActions(),
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritdoc * */
|
||||
public function GetRowActions(): array
|
||||
{
|
||||
$aRowActions = array();
|
||||
|
||||
if (!$this->oAttDef->GetReadOnly()) {
|
||||
|
||||
switch ($this->oAttDef->GetRelationType()) {
|
||||
|
||||
case LINKSET_RELATIONTYPE_LINK:
|
||||
$aRowActions[] = array(
|
||||
'tooltip' => 'UI:Links:ActionRow:detach',
|
||||
'icon_classes' => 'fas fa-minus',
|
||||
'js_row_action' => "LinkSetWorker.DetachLinkedObject('{$this->sTargetClass}', aRowData['{$this->sTargetClass}/_key_/raw'], '{$this->oAttDef->GetExtKeyToMe()}');",
|
||||
'confirmation' => [
|
||||
'message' => 'UI:Links:ActionRow:detach:confirmation',
|
||||
'message_row_data' => "{$this->sTargetClass}/hyperlink",
|
||||
'remember_choice_pref_key' => 'LinkSetWorker.DetachLinkedObject',
|
||||
],
|
||||
);
|
||||
break;
|
||||
|
||||
case LINKSET_RELATIONTYPE_PROPERTY:
|
||||
$aRowActions[] = array(
|
||||
'tooltip' => 'UI:Links:ActionRow:delete',
|
||||
'icon_classes' => 'fas fa-trash',
|
||||
'js_row_action' => "LinkSetWorker.DeleteLinkedObject('{$this->oAttDef->GetLinkedClass()}', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw']);",
|
||||
'confirmation' => [
|
||||
'message' => 'UI:Links:ActionRow:delete:confirmation',
|
||||
'message_row_data' => "{$this->sTargetClass}/hyperlink",
|
||||
'remember_choice_pref_key' => 'LinkSetWorker.DeleteLinkedObject',
|
||||
],
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $aRowActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetDefault.
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function GetDefault(): array
|
||||
{
|
||||
$aDefaults = array($this->oAttDef->GetExtKeyToMe() => $this->oDbObject->GetKey());
|
||||
$oAppContext = new \ApplicationContext();
|
||||
foreach ($oAppContext->GetNames() as $sKey) {
|
||||
if (MetaModel::IsValidAttCode($this->sObjectClass, $sKey)) {
|
||||
$aDefaults[$sKey] = $this->oDbObject->Get($sKey);
|
||||
}
|
||||
}
|
||||
|
||||
return $aDefaults;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEdit;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class BlockIndirectLinksEdit
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEdit
|
||||
*/
|
||||
class BlockIndirectLinksEdit extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-block-indirect-links-edit';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/indirect/block-indirect-links-edit/layout';
|
||||
|
||||
/** @var int */
|
||||
public $iInputId;
|
||||
/** @var string */
|
||||
public $sLinkedSetId;
|
||||
/** @var string */
|
||||
public $sClass;
|
||||
/** @var string */
|
||||
public $sAttCode;
|
||||
/** @var string */
|
||||
public $sNameSuffix;
|
||||
/** @var bool */
|
||||
public $bDuplicates;
|
||||
/** @var string containing a js object name */
|
||||
public $oWizHelper;
|
||||
/** @var string */
|
||||
public $sExtKeyToRemote;
|
||||
/** @var bool */
|
||||
public $bJSDoSearch;
|
||||
/** @var int */
|
||||
public $iMaxAddedId = 0;
|
||||
/** @var array */
|
||||
public $aRemoved = [];
|
||||
|
||||
/** @var string */
|
||||
public $sFormPrefix;
|
||||
/** @var string */
|
||||
public $sRemoteClass;
|
||||
|
||||
|
||||
public function AddControls()
|
||||
{
|
||||
$this->AddSubBlock(InputUIBlockFactory::MakeForHidden("{$this->sFormPrefix}{$this->iInputId}", '', "{$this->sFormPrefix}{$this->iInputId}"));
|
||||
|
||||
$oToolbar = ToolbarUIBlockFactory::MakeStandard(null, ['ibo-datatable--selection-validation-buttons-toolbar']);
|
||||
$this->AddSubBlock($oToolbar);
|
||||
$oRemoveButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:RemoveLinkedObjectsOf_Class'), null, null, false, "{$this->sLinkedSetId}_btnRemove");
|
||||
$oRemoveButton->SetOnClickJsCode("oWidget{$this->iInputId}.RemoveSelected();");
|
||||
$oToolbar->AddSubBlock($oRemoveButton);
|
||||
|
||||
$oAddButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->sRemoteClass)), null, null, false, "{$this->sLinkedSetId}_btnAdd");
|
||||
$oAddButton->SetOnClickJsCode("oWidget{$this->iInputId}.AddObjects();");
|
||||
$oToolbar->AddSubBlock($oAddButton);
|
||||
|
||||
// To prevent adding forms inside the main form
|
||||
$oDeferredBlock = new UIContentBlock("dlg_{$this->sLinkedSetId}", ['ibo-block-indirect-links--edit--dialog']);
|
||||
$this->AddDeferredBlock($oDeferredBlock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Indirect;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use MetaModel;
|
||||
|
||||
/**
|
||||
* Class BlockIndirectLinksEditTable
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Links\Indirect
|
||||
*/
|
||||
class BlockIndirectLinksEditTable extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-block-indirect-links-edit-table';
|
||||
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/indirect/block-indirect-links-edit-table/layout';
|
||||
|
||||
/** @var \UILinksWidget */
|
||||
public \UILinksWidget $oUILinksWidget;
|
||||
|
||||
/** @var \AttributeLinkedSetIndirect */
|
||||
private \AttributeLinkedSetIndirect $oAttributeLinkedSetIndirect;
|
||||
|
||||
/** @var string */
|
||||
public string $sDuplicates;
|
||||
|
||||
/** @var string containing a js object name */
|
||||
public string $sWizHelper;
|
||||
|
||||
/** @var string */
|
||||
public string $sJSDoSearch;
|
||||
|
||||
/** @var int */
|
||||
public int $iMaxAddedId = 0;
|
||||
|
||||
/** @var array */
|
||||
public array $aRemoved = [];
|
||||
|
||||
/** @var string */
|
||||
public string $sFormPrefix;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \UILinksWidget $oUILinksWidget
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(\UILinksWidget $oUILinksWidget)
|
||||
{
|
||||
parent::__construct("linkedset_{$oUILinksWidget->GetLinkedSetId()}", ["ibo-block-indirect-links--edit"]);
|
||||
|
||||
// Retrieve parameters
|
||||
$this->oUILinksWidget = $oUILinksWidget;
|
||||
|
||||
// Compute
|
||||
$this->sDuplicates = ($oUILinksWidget->IsDuplicatesAllowed()) ? 'true' : 'false';
|
||||
$this->sJSDoSearch = \utils::IsHighCardinality($oUILinksWidget->GetRemoteClass()) ? 'false' : 'true'; // Don't automatically launch the search if the table is huge
|
||||
|
||||
// Initialization
|
||||
$this->Init();
|
||||
|
||||
// Initialize UI
|
||||
$this->InitUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function Init()
|
||||
{
|
||||
$this->oAttributeLinkedSetIndirect = MetaModel::GetAttributeDef($this->oUILinksWidget->GetClass(), $this->oUILinksWidget->GetAttCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize UI.
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function InitUI()
|
||||
{
|
||||
// MedallionIcon
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($this->oUILinksWidget->GetRemoteClass(), false));
|
||||
$oClassIcon->SetDescription($this->oAttributeLinkedSetIndirect->GetDescription());
|
||||
$oClassIcon->AddCSSClass('ibo-block-list--medallion');
|
||||
$this->AddSubBlock($oClassIcon);
|
||||
|
||||
// To prevent adding forms inside the main form
|
||||
$oDeferredBlock = new UIContentBlock("dlg_{$this->oUILinksWidget->GetLinkedSetId()}", ['ibo-block-indirect-links--edit--dialog']);
|
||||
$this->AddDeferredBlock($oDeferredBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateTableInformationAlert.
|
||||
*
|
||||
* @return iUIBlock
|
||||
*/
|
||||
private function CreateTableInformationAlert(): iUIBlock
|
||||
{
|
||||
// Selection alert
|
||||
$oAlert = AlertUIBlockFactory::MakeNeutral('', '', "linkedset_{$this->oUILinksWidget->GetInputId()}_alert_information");
|
||||
$oAlert->AddCSSClasses([
|
||||
'ibo-table--alert-information',
|
||||
]);
|
||||
$oAlert->SetIsClosable(false);
|
||||
$oAlert->SetIsCollapsible(false);
|
||||
$oAlert->AddSubBlock(new Html('<span class="ibo-table--alert-information--label" data-role="ibo-datatable-selection-value"></span>'));
|
||||
|
||||
// Delete button
|
||||
$oUIButton = ButtonUIBlockFactory::MakeForDestructiveAction("Détacher les {$this->oUILinksWidget->GetRemoteClass()}", 'table-selection');
|
||||
$oUIButton->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.RemoveSelected();");
|
||||
$oUIButton->AddCSSClass('ibo-table--alert-information--delete-button');
|
||||
$oAlert->AddSubBlock($oUIButton);
|
||||
|
||||
// Add button
|
||||
$oUIAddButton = ButtonUIBlockFactory::MakeForPrimaryAction("Attacher des {$this->oUILinksWidget->GetRemoteClass()}", 'table-selection');
|
||||
$oUIAddButton->AddCSSClass('ibo-table--alert-information--add-button');
|
||||
$oUIAddButton->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.AddObjects();");
|
||||
$oAlert->AddSubBlock($oUIAddButton);
|
||||
|
||||
return $oAlert;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $oValue
|
||||
* @param $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param $aTableConfig
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitTable(\WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aTableConfig)
|
||||
{
|
||||
$this->AddSubBlock(InputUIBlockFactory::MakeForHidden("{$sFormPrefix}{$this->oUILinksWidget->GetInputId()}", '', "{$sFormPrefix}{$this->oUILinksWidget->GetInputId()}"));
|
||||
$this->sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oValue->Rewind();
|
||||
$aForm = array();
|
||||
$iMaxAddedId = 0;
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
$this->aRemoved = json_decode(\utils::ReadPostedParam("attr_{$sFormPrefix}{$this->oUILinksWidget->GetAttCode()}_tbd", '[]', 'raw_data'));
|
||||
while ($oCurrentLink = $oValue->Fetch()) {
|
||||
// We try to retrieve the remote object as usual
|
||||
if (!in_array($oCurrentLink->GetKey(), $this->aRemoved)) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
}
|
||||
$this->iMaxAddedId = (int)$iMaxAddedId;
|
||||
|
||||
// Datatable
|
||||
$aRowActions = $this->GetRowActions();
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->oUILinksWidget->GetAttCode()}{$this->oUILinksWidget->GetNameSuffix()}", $aTableConfig, $aForm, '', $aRowActions);
|
||||
$oDataTable->SetOptions([
|
||||
'select_mode' => 'custom',
|
||||
'disable_hyperlinks' => true,
|
||||
]);
|
||||
$aTablePanel = PanelUIBlockFactory::MakeNeutral('');
|
||||
$aTablePanel->SetSubTitle(sprintf('Total: %d objects.', count($aForm)));
|
||||
$oToolbar = ToolbarUIBlockFactory::MakeForButton();
|
||||
$oActionButtonUnlink = ButtonUIBlockFactory::MakeNeutral('Unlink');
|
||||
$oActionButtonUnlink->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.RemoveSelected();");
|
||||
$oToolbar->AddSubBlock($oActionButtonUnlink);
|
||||
$oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link');
|
||||
$oActionButtonLink->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.AddObjects();");
|
||||
$oToolbar->AddSubBlock($oActionButtonLink);
|
||||
$aTablePanel->AddToolbarBlock($oToolbar);
|
||||
$aTablePanel->AddSubBlock($oDataTable);
|
||||
|
||||
$this->AddSubBlock($aTablePanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-row form for editing a link record
|
||||
*
|
||||
* @param WebPage $oP Web page used for the ouput
|
||||
* @param DBObject $oLinkedObj Remote object
|
||||
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param int $iUniqueId A unique identifier of new links
|
||||
* @param boolean $bReadOnly Display link as editable or read-only. Default is false (editable)
|
||||
*
|
||||
* @return array The HTML fragment of the one-row form
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetFormRow(\WebPage $oP, \DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
|
||||
{
|
||||
$sPrefix = "{$this->oUILinksWidget->GetAttCode()}{$this->oUILinksWidget->GetNameSuffix()}";
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew())) {
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->oUILinksWidget->GetExternalKeyToRemote());
|
||||
$sPrefix .= "[$iKey][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->oUILinksWidget->GetInputId()}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if ($bReadOnly) {
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode) {
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
} else {
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget{$this->oUILinksWidget->GetInputId()}.OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach ($this->oUILinksWidget->GetEditableFields() as $sFieldCode) {
|
||||
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
}
|
||||
|
||||
$sState = $linkObjOrId->GetState();
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->oUILinksWidget->GetExternalKeyToRemote());;
|
||||
} else {
|
||||
// form for creating a new record
|
||||
if (is_object($linkObjOrId)) {
|
||||
// New link existing only in memory
|
||||
$oNewLinkObj = $linkObjOrId;
|
||||
$iRemoteObjKey = $oNewLinkObj->Get($this->oUILinksWidget->GetExternalKeyToRemote());
|
||||
$oNewLinkObj->Set($this->oUILinksWidget->GetExternalKeyToMe(),
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
} else {
|
||||
$iRemoteObjKey = $linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->oUILinksWidget->GetLinkedClass());
|
||||
$oRemoteObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $iRemoteObjKey);
|
||||
$oNewLinkObj->Set($this->oUILinksWidget->GetExternalKeyToRemote(),
|
||||
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->oUILinksWidget->GetExternalKeyToMe(),
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->oUILinksWidget->GetInputId()}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"0\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget{$this->oUILinksWidget->GetInputId()}.OnSelectChange();\" value=\"$sInputValue\">";
|
||||
|
||||
if ($iUniqueId > 0) {
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
//
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
oWidget{$this->oUILinksWidget->GetInputId()}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
// Rows added before loading the form don't have to call OnLinkAdded.
|
||||
// Listeners are already present and DOM is not recreated
|
||||
$iPositiveUniqueId = -$iUniqueId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
oWidget{$this->oUILinksWidget->GetInputId()}.AddLink($iPositiveUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->oUILinksWidget->GetEditableFields() as $sFieldCode) {
|
||||
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
|
||||
$sValue = $oNewLinkObj->Get($sFieldCode);
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
oWidget{$this->oUILinksWidget->GetInputId()}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
$sState = '';
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->oUILinksWidget->GetExternalKeyToRemote());
|
||||
}
|
||||
|
||||
if (!$bReadOnly) {
|
||||
$sExtKeyToMeId = \utils::GetSafeId($sPrefix.$this->oUILinksWidget->GetExternalKeyToMe());
|
||||
$aFieldsMap[$this->oUILinksWidget->GetExternalKeyToMe()] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = \utils::GetSafeId($sPrefix.$this->oUILinksWidget->GetExternalKeyToRemote());
|
||||
$aFieldsMap[$this->oUILinksWidget->GetExternalKeyToRemote()] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
|
||||
// Adding fields from remote class
|
||||
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
|
||||
$aRemoteFieldsMap = [];
|
||||
foreach (MetaModel::GetZListItems($this->oUILinksWidget->GetRemoteClass(), 'list') as $sFieldCode) {
|
||||
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
|
||||
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
|
||||
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
// id field is needed so that remote object could be load server side
|
||||
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
|
||||
|
||||
// Generate WizardHelper to update dependant fields
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->oUILinksWidget->GetLinkedClass(), $sState, $aFieldsMap);
|
||||
//instantiate specific WizarHelper instance for remote class fields refresh
|
||||
$bHasExtKeyUpdatingRemoteClassFields = (
|
||||
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
|
||||
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
|
||||
);
|
||||
if ($bHasExtKeyUpdatingRemoteClassFields) {
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->oUILinksWidget->GetRemoteClass(), $sState, $aRemoteFieldsMap);
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
|
||||
{
|
||||
if (($sFieldCode === $this->oUILinksWidget->GetExternalKeyToRemote())) {
|
||||
// current field is the lnk extkey to the remote class
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
|
||||
$sRowFieldCode = 'static::key';
|
||||
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
|
||||
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->oUILinksWidget->GetRemoteClass());
|
||||
$aRemoteCodes = array_map(
|
||||
function ($value) {
|
||||
return $value->GetCode();
|
||||
},
|
||||
$aRemoteAttDefs
|
||||
);
|
||||
$aArgs['remoteCodes'] = $aRemoteCodes;
|
||||
} else {
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
|
||||
$sRowFieldCode = $sFieldCode;
|
||||
}
|
||||
$sValue = $oLnk->Get($sFieldCode);
|
||||
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->oUILinksWidget->GetLinkedClass(), $sFieldCode);
|
||||
|
||||
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
|
||||
.\cmdbAbstractObject::GetFormElementForField(
|
||||
$oP,
|
||||
$this->oUILinksWidget->GetLinkedClass(),
|
||||
$sFieldCode,
|
||||
$oAttDef,
|
||||
$sValue,
|
||||
$sDisplayValue,
|
||||
$sSafeFieldId,
|
||||
$sNameSuffix,
|
||||
0,
|
||||
$aArgs
|
||||
)
|
||||
.'</div></div></div>';
|
||||
}
|
||||
|
||||
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
|
||||
{
|
||||
$sFieldId = $this->oUILinksWidget->GetInputId().'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
|
||||
return ($bSafe) ? \utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
|
||||
{
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<JS
|
||||
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
|
||||
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
|
||||
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
|
||||
$sWizardHelperVarName.SetReturnNotEditableFields(true);
|
||||
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return row actions.
|
||||
*
|
||||
* @return \string[][]
|
||||
*/
|
||||
private function GetRowActions(): array
|
||||
{
|
||||
$aRowActions = array();
|
||||
|
||||
if (!$this->oAttributeLinkedSetIndirect->GetReadOnly()) {
|
||||
$aRowActions[] = array(
|
||||
'tooltip' => 'remove link',
|
||||
'icon_classes' => 'fas fa-minus',
|
||||
'js_row_action' => "oWidget{$this->oUILinksWidget->GetInputId()}.Remove(oTrElement);",
|
||||
);
|
||||
}
|
||||
|
||||
return $aRowActions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Indirect;
|
||||
|
||||
use Combodo\iTop\Application\UI\Links\AbstractBlockLinksViewTable;
|
||||
use MetaModel;
|
||||
use PHPUnit\Exception;
|
||||
|
||||
/**
|
||||
* Class BlockIndirectLinksViewTable
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Application\UI\Links\Indirect
|
||||
*/
|
||||
class BlockIndirectLinksViewTable extends AbstractBlockLinksViewTable
|
||||
{
|
||||
public const BLOCK_CODE = 'ibo-block-indirect-links-view-table';
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetTargetClass(): string
|
||||
{
|
||||
try {
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->oAttDef->GetLinkedClass(), $this->oAttDef->GetExtKeyToRemote());
|
||||
|
||||
return $oLinkingAttDef->GetTargetClass();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetExtraParam(): array
|
||||
{
|
||||
return array(
|
||||
'link_attr' => $this->oAttDef->GetExtKeyToMe(),
|
||||
'object_id' => $this->oDbObject->GetKey(),
|
||||
'target_attr' => $this->oAttDef->GetExtKeyToRemote(),
|
||||
'view_link' => false,
|
||||
'menu' => false,
|
||||
'display_limit' => true,
|
||||
'table_id' => $this->sObjectClass.'_'.$this->sAttCode,
|
||||
'zlist' => false,
|
||||
'extra_fields' => $this->GetAttCodesToDisplay(),
|
||||
'row_actions' => $this->GetRowActions(),
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetRowActions(): array
|
||||
{
|
||||
$aRowActions = array();
|
||||
|
||||
if (!$this->oAttDef->GetReadOnly()) {
|
||||
|
||||
$aRowActions[] = array(
|
||||
'tooltip' => 'UI:Links:ActionRow:detach',
|
||||
'icon_classes' => 'fas fa-minus',
|
||||
'js_row_action' => "LinkSetWorker.DeleteLinkedObject('{$this->oAttDef->GetLinkedClass()}', aRowData['Link/_key_/raw']);",
|
||||
'confirmation' => [
|
||||
'message' => 'UI:Links:ActionRow:detach:confirmation',
|
||||
'message_row_data' => "Remote/hyperlink",
|
||||
'remember_choice_pref_key' => 'LinkSetWorker.DetachLinkedObject',
|
||||
],
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $aRowActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetAttCodesToDisplay.
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private function GetAttCodesToDisplay(): string
|
||||
{
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->oAttDef->GetLinkedClass(), $this->oAttDef->GetExtKeyToRemote());
|
||||
$sLinkingAttCode = $oLinkingAttDef->GetCode();
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
|
||||
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($this->sObjectClass, $this->sAttCode);
|
||||
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($sTargetClass);
|
||||
$aLnkAttCodesToDisplay = array_map(function ($oLnkAttDef) {
|
||||
return \ormLinkSet::LINK_ALIAS.'.'.$oLnkAttDef->GetCode();
|
||||
},
|
||||
$aLnkAttDefsToDisplay
|
||||
);
|
||||
if (!in_array(\ormLinkSet::LINK_ALIAS.'.'.$sLinkingAttCode, $aLnkAttCodesToDisplay)) {
|
||||
// we need to display a link to the remote class instance !
|
||||
$aLnkAttCodesToDisplay[] = \ormLinkSet::LINK_ALIAS.'.'.$sLinkingAttCode;
|
||||
}
|
||||
$aRemoteAttCodesToDisplay = array_map(function ($oRemoteAttDef) {
|
||||
return \ormLinkSet::REMOTE_ALIAS.'.'.$oRemoteAttDef->GetCode();
|
||||
},
|
||||
$aRemoteAttDefsToDisplay
|
||||
);
|
||||
$aAttCodesToDisplay = array_merge($aLnkAttCodesToDisplay, $aRemoteAttCodesToDisplay);
|
||||
|
||||
return implode(',', $aAttCodesToDisplay);
|
||||
}
|
||||
}
|
||||
@@ -4,31 +4,40 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog;
|
||||
namespace Combodo\iTop\Application\UI\Links\Indirect;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Form\Form;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* Class BlockObjectPickerDialog
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog
|
||||
* @internal
|
||||
* @package Combodo\iTop\Application\UI\Links\Indirect
|
||||
*/
|
||||
class BlockObjectPickerDialog extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-block-object-picker-dialog';
|
||||
public const BLOCK_CODE = 'ibo-block-object-picker-dialog';
|
||||
public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'application/links/indirect/block-object-picker-dialog/layout';
|
||||
|
||||
public $sLinkedSetId;
|
||||
public $iInputId;
|
||||
public $sLinkedClassName;
|
||||
public $sClassName;
|
||||
/** @var \UILinksWidget */
|
||||
public \UILinksWidget $oUILinksWidget;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \UILinksWidget $oUILinksWidget
|
||||
*/
|
||||
public function __construct(\UILinksWidget $oUILinksWidget)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Retrieve parameters
|
||||
$this->oUILinksWidget = $oUILinksWidget;
|
||||
}
|
||||
|
||||
public function AddForm()
|
||||
{
|
||||
@@ -36,13 +45,13 @@ class BlockObjectPickerDialog extends UIContentBlock
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oForm = new Form("ObjectsAddForm_{$this->sLinkedSetId}");
|
||||
$oForm = new Form("ObjectsAddForm_{$this->oUILinksWidget->GetLinkedSetId()}");
|
||||
$this->AddSubBlock($oForm);
|
||||
$oBlock = new UIContentBlock("SearchResultsToAdd_{$this->sLinkedSetId}", ['ibo-block-object-picker-dialog--results']);
|
||||
$oBlock = new UIContentBlock("SearchResultsToAdd_{$this->oUILinksWidget->GetLinkedSetId()}", ['ibo-block-object-picker-dialog--results']);
|
||||
$oForm->AddSubBlock($oBlock);
|
||||
$oBlock->AddHtml("<p>{$sEmptyList}</p>");
|
||||
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden("count_{$this->sLinkedSetId}", '0', "count_{$this->sLinkedSetId}"));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden("count_{$this->oUILinksWidget->GetLinkedSetId()}", '0', "count_{$this->oUILinksWidget->GetLinkedSetId()}"));
|
||||
|
||||
}
|
||||
}
|
||||
103
sources/Controller/Links/LinksetController.php
Normal file
103
sources/Controller/Links/LinksetController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Controller\Links;
|
||||
|
||||
use Combodo\iTop\Controller\AbstractController;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class LinkSetController
|
||||
*
|
||||
* @internal
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Controller
|
||||
*/
|
||||
class LinkSetController extends AbstractController
|
||||
{
|
||||
public const ROUTE_NAMESPACE = 'linkset';
|
||||
|
||||
/**
|
||||
* OperationDeleteLinkedObject.
|
||||
*
|
||||
* @return \JsonPage
|
||||
*/
|
||||
public function OperationDeleteLinkedObject(): \JsonPage
|
||||
{
|
||||
$oPage = new \JsonPage();
|
||||
$sErrorMessage = null;
|
||||
$bOperationSuccess = false;
|
||||
|
||||
// retrieve parameters
|
||||
$sLinkedObjectClass = utils::ReadParam('linked_object_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$sLinkedObjectObjectKey = utils::ReadParam('linked_object_key', 0, false, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
$sTransactionId = utils::ReadParam('transaction_id', null, false, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
|
||||
// check transaction id
|
||||
if (utils::IsTransactionValid($sTransactionId, false)) {
|
||||
try {
|
||||
$oDeletionPlan = MetaModel::GetObject($sLinkedObjectClass, $sLinkedObjectObjectKey)->DBDelete();
|
||||
$bOperationSuccess = (count($oDeletionPlan->GetIssues()) === 0);
|
||||
if (!$bOperationSuccess) {
|
||||
$sErrorMessage = json_encode($oDeletionPlan->GetIssues());
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$sErrorMessage = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$sErrorMessage = 'invalid transaction id';
|
||||
}
|
||||
$oPage->SetData([
|
||||
'success' => $bOperationSuccess,
|
||||
'error_message' => $sErrorMessage,
|
||||
]);
|
||||
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* OperationDetachLinkedObject.
|
||||
*
|
||||
* @return \JsonPage
|
||||
*/
|
||||
public function OperationDetachLinkedObject(): \JsonPage
|
||||
{
|
||||
$oPage = new \JsonPage();
|
||||
$sErrorMessage = null;
|
||||
$bOperationSuccess = false;
|
||||
|
||||
// retrieve parameters
|
||||
$sLinkedObjectClass = utils::ReadParam('linked_object_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$sLinkedObjectKey = utils::ReadParam('linked_object_key', 0, false, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
$sExternalKeyAttCode = utils::ReadParam('external_key_att_code', null, false, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
$sTransactionId = utils::ReadParam('transaction_id', null, false, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
|
||||
// check transaction id
|
||||
if (utils::IsTransactionValid($sTransactionId, false)) {
|
||||
try {
|
||||
$oLinkedObject = MetaModel::GetObject($sLinkedObjectClass, $sLinkedObjectKey);
|
||||
$oLinkedObject->Set($sExternalKeyAttCode, null);
|
||||
$oLinkedObject->DBWrite();
|
||||
$bOperationSuccess = true;
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$sErrorMessage = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$sErrorMessage = 'invalid transaction id';
|
||||
}
|
||||
$oPage->SetData([
|
||||
'success' => $bOperationSuccess,
|
||||
'error_message' => $sErrorMessage,
|
||||
]);
|
||||
|
||||
return $oPage;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% apply spaceless %}
|
||||
oWidget{{ oUIBlock.oUILinksDirectWidget.GetInputId() }} = $('#{{ oUIBlock.oUILinksDirectWidget.GetInputId() }}').directlinks({
|
||||
class_name: '{{ oUIBlock.oUILinksDirectWidget.GetClass() }}',
|
||||
att_code: '{{ oUIBlock.oUILinksDirectWidget.GetAttCode() }}',
|
||||
input_name: '{{ oUIBlock.sInputName }}',
|
||||
submit_to: '{{ oUIBlock.sSubmitUrl }}',
|
||||
oWizardHelper: {{ oUIBlock.sWizHelper }},
|
||||
do_search: '{{ oUIBlock.sJSDoSearch }}'
|
||||
});
|
||||
{% endapply %}
|
||||
@@ -0,0 +1,18 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% apply spaceless %}
|
||||
oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }} = new LinksWidget(
|
||||
'{{ oUIBlock.oUILinksWidget.GetLinkedSetId() }}',
|
||||
'{{ oUIBlock.oUILinksWidget.GetClass() }}',
|
||||
'{{ oUIBlock.oUILinksWidget.GetAttCode() }}',
|
||||
'{{ oUIBlock.oUILinksWidget.GetInputId() }}',
|
||||
'{{ oUIBlock.oUILinksWidget.GetNameSuffix() }}',
|
||||
{{ oUIBlock.sDuplicates }},
|
||||
{{ oUIBlock.sWizHelper }},
|
||||
'{{ oUIBlock.oUILinksWidget.GetExternalKeyToRemote() }}',
|
||||
{{ oUIBlock.sJSDoSearch }},
|
||||
{{ oUIBlock.iMaxAddedId }},
|
||||
{{ oUIBlock.aRemoved | json_encode | raw }}
|
||||
);
|
||||
oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }}.Init();
|
||||
{% endapply %}
|
||||
@@ -1,18 +0,0 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% apply spaceless %}
|
||||
oWidget{{ oUIBlock.iInputId }} = new LinksWidget(
|
||||
'{{ oUIBlock.sLinkedSetId }}',
|
||||
'{{ oUIBlock.sClass }}',
|
||||
'{{ oUIBlock.sAttCode }}',
|
||||
'{{ oUIBlock.iInputId }}',
|
||||
'{{ oUIBlock.sNameSuffix }}',
|
||||
{{ oUIBlock.bDuplicates }},
|
||||
{{ oUIBlock.oWizHelper }},
|
||||
'{{ oUIBlock.sExtKeyToRemote }}',
|
||||
{{ oUIBlock.bJSDoSearch }},
|
||||
{{ oUIBlock.iMaxAddedId }},
|
||||
{{ oUIBlock.aRemoved | json_encode | raw }}
|
||||
);
|
||||
oWidget{{ oUIBlock.iInputId }}.Init();
|
||||
{% endapply %}
|
||||
@@ -2,13 +2,13 @@
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% apply spaceless %}
|
||||
|
||||
$('#dlg_{{ oUIBlock.sLinkedSetId }}').dialog({
|
||||
$('#dlg_{{ oUIBlock.oUILinksWidget.GetLinkedSetId() }}').dialog({
|
||||
width: $(window).width()*0.8,
|
||||
height: $(window).height()*0.8,
|
||||
title:"{{ 'UI:AddObjectsOf_Class_LinkedWith_Class'|dict_format(oUIBlock.sLinkedClassName, oUIBlock.sClassName) }}" ,
|
||||
title:"{{ 'UI:AddObjectsOf_Class_LinkedWith_Class'|dict_format(oUIBlock.oUILinksWidget.GetLinkedClass(), oUIBlock.oUILinksWidget.GetClass()) }}" ,
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
resizeStop: oWidget{{ oUIBlock.iInputId }}.UpdateSizes,
|
||||
resizeStop: oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }}.UpdateSizes,
|
||||
buttons: [
|
||||
{
|
||||
text: "{{ 'UI:Button:Cancel'| dict_s }}",
|
||||
@@ -20,16 +20,16 @@ $('#dlg_{{ oUIBlock.sLinkedSetId }}').dialog({
|
||||
{
|
||||
text: "{{ 'UI:Button:Add'| dict_s }}",
|
||||
class: "ibo-is-regular ibo-is-primary",
|
||||
id: "btn_ok_{{ oUIBlock.sLinkedSetId }}",
|
||||
id: "btn_ok_{{ oUIBlock.oUILinksWidget.GetLinkedSetId() }}",
|
||||
click: function() {
|
||||
return oWidget{{ oUIBlock.iInputId }}.DoAddObjects();
|
||||
return oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }}.DoAddObjects();
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
});
|
||||
|
||||
$('#SearchFormToAdd_{{ oUIBlock.sLinkedSetId }} form').bind('submit.uilinksWizard', oWidget{{ oUIBlock.iInputId }}.SearchObjectsToAdd);
|
||||
$('#SearchFormToAdd_{{ oUIBlock.sLinkedSetId }}').resize(oWidget{{ oUIBlock.iInputId }}.UpdateSizes);
|
||||
$('#SearchFormToAdd_{{ oUIBlock.oUILinksWidget.GetLinkedSetId() }} form').bind('submit.uilinksWizard', oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }}.SearchObjectsToAdd);
|
||||
$('#SearchFormToAdd_{{ oUIBlock.oUILinksWidget.GetLinkedSetId() }}').resize(oWidget{{ oUIBlock.oUILinksWidget.GetInputId() }}.UpdateSizes);
|
||||
|
||||
{% endapply %}
|
||||
@@ -21,11 +21,14 @@
|
||||
<th class="ibo-datatable-header" {% if aColumn["description"] is not empty %}title="{{ aColumn["description"] }}"{% endif %}>{{ aColumn["attribute_label"] }} </th>
|
||||
{% endfor %}
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
<th class="ibo-datatable-header">{{ 'UI:Datatables:Column:RowActions:Label'|dict_s }} </th>
|
||||
<th class="ibo-datatable-header" title="{{ 'UI:Datatables:Column:RowActions:Description'|dict_s }}">{{ 'UI:Datatables:Column:RowActions:Label'|dict_s }} </th>
|
||||
{% endif %}
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsTemplate()) }}
|
||||
{% if not oUIBlock.GetRowActionsConfirmDialogInitializedFlag() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsConfirmDialog()) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -423,4 +423,6 @@ if(window.ResizeObserver){
|
||||
oTable{{ sListIDForVarSuffix }}Resize.observe($('#{{ oUIBlock.GetId() }}')[0]);
|
||||
}
|
||||
|
||||
{% include 'base/components/datatable/row-actions/handler.js.twig' %}
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
{% include 'base/components/datatable/row-actions/handler.js.twig' %}
|
||||
{% endif %}
|
||||
@@ -1,15 +1,51 @@
|
||||
{# @copyright Copyright (C) 2010-2022 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
// for each row action
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
{% for aAction in oUIBlock.GetRowActions() %}
|
||||
$('#{{ oUIBlock.GetId() }} tbody').on('click', 'button[data-action-id="{{ loop.index0 }}"]', function() {
|
||||
let iActionId = $(this).data('action-id');
|
||||
let oDatatable = $('#{{ oUIBlock.GetId() }}').DataTable();
|
||||
let oTrElement = $(this).closest('tr');
|
||||
let aData = oDatatable.row(oTrElement).data();
|
||||
{{ aAction.js_row_action|raw }};
|
||||
});
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
// for each row action...
|
||||
{% for aAction in oUIBlock.GetRowActions() %}
|
||||
|
||||
// register action buttons click
|
||||
$('#{{ oUIBlock.GetId() }} tbody').on('click', 'button[data-action-id="{{ loop.index0 }}"]', function() {
|
||||
|
||||
// variables accessible from action row js
|
||||
let oDatatable = $('#{{ oUIBlock.GetId() }}').DataTable();
|
||||
let oTrElement = $(this).closest('tr');
|
||||
let iActionId = $(this).data('action-id');
|
||||
let aRowData = oDatatable.row(oTrElement).data();
|
||||
|
||||
{% if aAction.confirmation is defined %}
|
||||
|
||||
// Handle action row with confirmation
|
||||
let sTitle = '{{ 'UI:Datatables:RowActions:ConfirmationDialog'|dict_s }}';
|
||||
let sMessage = '{{ 'UI:Datatables:RowActions:ConfirmationMessage'|dict_s }}';
|
||||
{% if aAction.confirmation.message is defined %}
|
||||
sMessage = '{{ aAction.confirmation.message|dict_s|raw }}';
|
||||
sMessage = sMessage.replaceAll('{item}', aRowData['{{ aAction.confirmation.message_row_data }}']);
|
||||
{% endif %}
|
||||
let sPrefKey = null;
|
||||
{% if aAction.confirmation.remember_choice_pref_key is defined %}
|
||||
sPrefKey = '{{ aAction.confirmation.remember_choice_pref_key }}';
|
||||
{% endif %}
|
||||
HandleActionRowConfirmation (sTitle, sMessage, sPrefKey, ActionRowFunction{{ oUIBlock.GetId() }}{{ loop.index0 }}, {
|
||||
action_id: iActionId,
|
||||
datatable: oDatatable,
|
||||
tr_element: oTrElement,
|
||||
row_data: aRowData
|
||||
});
|
||||
|
||||
{% else %}
|
||||
|
||||
// Handle action row without confirmation
|
||||
ActionRowFunction{{ oUIBlock.GetId() }}{{ loop.index0 }}(oDatatable, oTrElement, iActionId, aRowData);
|
||||
|
||||
{% endif %}
|
||||
|
||||
});
|
||||
|
||||
// action row function declaration
|
||||
function ActionRowFunction{{ oUIBlock.GetId() }}{{ loop.index0 }}(oDatatable, oTrElement, iActionId, aRowData){
|
||||
{{ aAction.js_row_action|raw }};
|
||||
return true;
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -21,4 +21,7 @@
|
||||
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsTemplate()) }}
|
||||
{% if not oUIBlock.GetRowActionsConfirmDialogInitializedFlag() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsConfirmDialog()) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -48,4 +48,7 @@
|
||||
|
||||
{% if oUIBlock.HasRowActions() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsTemplate()) }}
|
||||
{% if not oUIBlock.GetRowActionsConfirmDialogInitializedFlag() %}
|
||||
{{ render_block(oUIBlock.GetRowActionsConfirmDialog()) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
5
templates/base/components/dialog/layout.html.twig
Normal file
5
templates/base/components/dialog/layout.html.twig
Normal file
@@ -0,0 +1,5 @@
|
||||
<div id="{{ oUIBlock.GetId() }}" class="{{ oUIBlock.GetBlocksInheritanceCSSClassesAsString() }} {{ oUIBlock.GetAdditionalCSSClassesAsString() }}" data-role="ibo-dialog" title="" style="display: none">
|
||||
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
|
||||
{{ render_block(oSubBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
4
templates/base/components/dialog/layout.ready.js.twig
Normal file
4
templates/base/components/dialog/layout.ready.js.twig
Normal file
@@ -0,0 +1,4 @@
|
||||
$('#{{ oUIBlock.GetId() }}').alert({
|
||||
bOpenedByDefault: {{ oUIBlock.IsOpenedByDefault()|var_export }}
|
||||
{% if oUIBlock.IsSaveCollapsibleStateEnabled() %}, collapsibleStateStorageKey: '{{ oUIBlock.GetSessionCollapsibleStateStorageKey() }}'{% endif %}
|
||||
});
|
||||
Reference in New Issue
Block a user