diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 2f07da57f..ff2a4c765 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -18,11 +18,17 @@ */ use Combodo\iTop\Application\UI\Component\Alert\AlertFactory; +use Combodo\iTop\Application\UI\Component\Button\Button; +use Combodo\iTop\Application\UI\Component\Button\ButtonFactory; use Combodo\iTop\Application\UI\Component\Field\Field; use Combodo\iTop\Application\UI\Component\FieldSet\FieldSet; +use Combodo\iTop\Application\UI\Component\Form\Form; +use Combodo\iTop\Application\UI\Component\Input\InputFactory; use Combodo\iTop\Application\UI\Component\Title\TitleFactory; +use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar; use Combodo\iTop\Application\UI\Layout\Column\Column; use Combodo\iTop\Application\UI\Layout\MultiColumn\MultiColumn; +use Combodo\iTop\Application\UI\Layout\UIContentBlock; define('OBJECT_PROPERTIES_TAB', 'ObjectProperties'); @@ -2511,8 +2517,14 @@ JS } } - if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) - { + $oContentBlock = new UIContentBlock(); + $oContentBlock->SetCSSClasses("object-details") + ->AddDataAttributes('object-class', $sClass) + ->AddDataAttributes('object-id', $iKey) + ->AddDataAttributes('object-mode', $sMode); + $oPage->AddUiBlock($oContentBlock); + + if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) { $sClassLabel = MetaModel::GetName($sClass); $sHeaderTitle = Dict::Format('UI:ModificationTitle_Class_Object', $sClassLabel, $this->GetName()); @@ -2520,97 +2532,87 @@ JS $oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $this->GetRawName(), $sClassLabel)); // Set title will take care of the encoding - $oPage->add(<< -
- - -
-HTML - ); + $oContentBlock->AddSubBlock(TitleFactory::MakeForObjectDetails('', $sHeaderTitle, $this->GetIcon())); + +// $oPage->add(<< +//
+// +// +//
+//HTML +// ); } self::$iGlobalFormId++; $this->aFieldsMap = array(); $sPrefix = ''; - if (isset($aExtraParams['formPrefix'])) - { + if (isset($aExtraParams['formPrefix'])) { $sPrefix = $aExtraParams['formPrefix']; } $this->m_iFormId = $sPrefix.self::$iGlobalFormId; $oAppContext = new ApplicationContext(); - if (!isset($aExtraParams['action'])) - { + if (!isset($aExtraParams['action'])) { $sFormAction = utils::GetAbsoluteUrlAppRoot().'pages/'.$this->GetUIPage(); // No parameter in the URL, the only parameter will be the ones passed through the form - } - else - { + } else { $sFormAction = $aExtraParams['action']; } // Custom label for the apply button ? - if (isset($aExtraParams['custom_button'])) - { + if (isset($aExtraParams['custom_button'])) { $sApplyButton = $aExtraParams['custom_button']; - } - else - { - if ($sMode === static::ENUM_OBJECT_MODE_EDIT) - { + } else { + if ($sMode === static::ENUM_OBJECT_MODE_EDIT) { $sApplyButton = Dict::S('UI:Button:Apply'); - } - else - { + } else { $sApplyButton = Dict::S('UI:Button:Create'); } } // Custom operation for the form ? - if (isset($aExtraParams['custom_operation'])) - { + if (isset($aExtraParams['custom_operation'])) { $sOperation = $aExtraParams['custom_operation']; - } - else - { - if ($sMode === static::ENUM_OBJECT_MODE_EDIT) - { + } else { + if ($sMode === static::ENUM_OBJECT_MODE_EDIT) { $sOperation = 'apply_modify'; - } - else - { + } else { $sOperation = 'apply_new'; } } - if ($sMode === static::ENUM_OBJECT_MODE_EDIT) - { + + $oForm = new Form("form_{$this->m_iFormId}"); + $oForm->SetAction($sFormAction) + ->SetOnSubmitJsCode("return OnSubmit('form_{$this->m_iFormId}');"); + $oContentBlock->AddSubBlock($oForm); + + $oToolbarTop = new Toolbar(); + + if ($sMode === static::ENUM_OBJECT_MODE_EDIT) { // The object already exists in the database, it's a modification - $sButtons = "\n"; - $sButtons .= "\n"; - $sButtons .= "    \n"; - $sButtons .= "\n"; - } - else - { - // The object does not exist in the database it's a creation - $sButtons = "\n"; - $sButtons .= "    \n"; - $sButtons .= "\n"; + $oForm->AddSubBlock(InputFactory::MakeForHidden('id', $iKey, "{$sPrefix}_id")); } + $oForm->AddSubBlock(InputFactory::MakeForHidden('operation', $sOperation)); + $oCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('UI:Button:Cancel')); + $oCancelButton->AddCSSClasses('action cancel'); + $oToolbarTop->AddSubBlock($oCancelButton); + $oApplyButton = ButtonFactory::MakeForValidationAction($sApplyButton, null, null, true); + $oApplyButton->AddCSSClasses('action'); + $oToolbarTop->AddSubBlock($oApplyButton); $aTransitions = $this->EnumTransitions(); - if (!isset($aExtraParams['custom_operation']) && count($aTransitions)) - { + if (!isset($aExtraParams['custom_operation']) && count($aTransitions)) { // transitions are displayed only for the standard new/modify actions, not for modify_all or any other case... $oSetToCheckRights = DBObjectSet::FromObject($this); $aStimuli = Metamodel::EnumStimuli($sClass); - foreach($aTransitions as $sStimulusCode => $aTransitionDef) - { + foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO; - switch ($iActionAllowed) - { + switch ($iActionAllowed) { case UR_ALLOWED_YES: - $sButtons .= "\n"; + $oButton = ButtonFactory::MakeForValidationAction($aStimuli[$sStimulusCode]->GetLabel(), 'next_action', $sStimulusCode, true); + $oButton->AddCSSClasses('action'); + $oButton->SetColor(Button::ENUM_COLOR_NEUTRAL); + $oToolbarTop->AddSubBlock($oButton); break; default: @@ -2622,7 +2624,6 @@ HTML $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position'); $iTransactionId = isset($aExtraParams['transaction_id']) ? $aExtraParams['transaction_id'] : utils::GetNewTransactionId(); $oPage->SetTransactionId($iTransactionId); - $oPage->add("
m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n"); $sStatesSelection = ''; if (!isset($aExtraParams['custom_operation']) && $this->IsNew()) { @@ -2672,70 +2673,54 @@ JAVASCRIPT EOF ); - if ($sButtonsPosition != 'bottom') - { + if ($sButtonsPosition != 'bottom') { // top or both, display the buttons here $oPage->p($sStatesSelection); - $oPage->add($sButtons); + $oForm->AddSubBlock($oToolbarTop); } - $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); + $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix, $oForm); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab('UI:PropertiesTab'); $aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams); - if (!is_array($aFieldsMap)) - { + if (!is_array($aFieldsMap)) { $aFieldsMap = array(); } - if ($sMode === static::ENUM_OBJECT_MODE_EDIT) - { + if ($sMode === static::ENUM_OBJECT_MODE_EDIT) { $aFieldsMap['id'] = $sPrefix.'_id'; } // Now display the relations, one tab per relation - if (!isset($aExtraParams['noRelations'])) - { + if (!isset($aExtraParams['noRelations'])) { $this->DisplayBareRelations($oPage, true); // Edit mode, will fill $this->aFieldsMap $aFieldsMap = array_merge($aFieldsMap, $this->aFieldsMap); } $oPage->SetCurrentTab(''); - $oPage->add("\n"); - $oPage->add("\n"); - foreach($aExtraParams as $sName => $value) - { - if (is_scalar($value)) - { - $oPage->add("\n"); + $oForm->AddSubBlock(InputFactory::MakeForHidden('class', $sClass)); + $oForm->AddSubBlock(InputFactory::MakeForHidden('transaction_id', $iTransactionId)); + foreach ($aExtraParams as $sName => $value) { + if (is_scalar($value)) { + $oForm->AddSubBlock(InputFactory::MakeForHidden($sName, $value)); } } - if ($sOwnershipToken !== null) - { - $oPage->add("\n"); + if ($sOwnershipToken !== null) { + $oForm->AddSubBlock(InputFactory::MakeForHidden('ownership_token', utils::HtmlEntities($sOwnershipToken))); } $oPage->add($oAppContext->GetForForm()); - if ($sButtonsPosition != 'top') - { + if ($sButtonsPosition != 'top') { // bottom or both: display the buttons here $oPage->p($sStatesSelection); - $oPage->add($sButtons); + $oToolbarBottom = new Toolbar(); + foreach ($oToolbarTop->GetSubBlocks() as $oButton) { + $oToolbarBottom->AddSubBlock($oButton); + } + $oForm->AddSubBlock($oToolbarBottom); } // Hook the cancel button via jQuery so that it can be unhooked easily as well if needed $sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=cancel&'.$oAppContext->GetForLink(); $oPage->add_ready_script("$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('$sClass', $iKey, '$sDefaultUrl', $sJSToken)} );"); - $oPage->add("
\n"); - - if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) - { - // Close wizContainer and object-details - $oPage->add(<< -
-HTML - ); - } $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); diff --git a/datamodels/2.x/combodo-db-tools/dbtools.php b/datamodels/2.x/combodo-db-tools/dbtools.php index 869c4d337..bf6eef9fd 100644 --- a/datamodels/2.x/combodo-db-tools/dbtools.php +++ b/datamodels/2.x/combodo-db-tools/dbtools.php @@ -461,7 +461,7 @@ try $oP->add_saas('env-'.utils::GetCurrentEnvironment().'/combodo-db-tools/default.scss'); $oP->add( -<<

$sPageTitle

diff --git a/pages/UI.php b/pages/UI.php index dc92cd7c6..9e1e23c3c 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -1906,45 +1906,38 @@ EOF $sDescription = MetaModel::GetRelationDescription($sRelation, $bDirDown).' '.$oObj->GetName(); $oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription); - if ($sRelation == 'depends on') - { - $sRelation = 'impacts'; - $sDirection = 'up'; - } - if ($sDirection == 'up') - { - $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth); - } - else - { - $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth); - } - + if ($sRelation == 'depends on') { + $sRelation = 'impacts'; + $sDirection = 'up'; + } + if ($sDirection == 'up') { + $oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth); + } else { + $oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth); + } - $aResults = $oRelGraph->GetObjectsByClass(); - $oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down')); - - $oP->AddTabContainer('Navigator'); - $oP->SetCurrentTabContainer('Navigator'); - - $sFirstTab = MetaModel::GetConfig()->Get('impact_analysis_first_tab'); - $sContextKey = "itop-config-mgmt/relation_context/$sClass/$sRelation/$sDirection"; - - // Check if the current object supports Attachments, similar to AttachmentPlugin::IsTargetObject - $sClassForAttachment = null; - $iIdForAttachment = null; - if (class_exists('Attachment')) - { - $aAllowedClasses = MetaModel::GetModuleSetting('itop-attachments', 'allowed_classes', array('Ticket')); - foreach($aAllowedClasses as $sAllowedClass) - { - if ($oObj instanceof $sAllowedClass) - { - $iIdForAttachment = $id; - $sClassForAttachment = $sClass; + + $aResults = $oRelGraph->GetObjectsByClass(); + $oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down')); + + $oP->AddTabContainer('Navigator'); + $oP->SetCurrentTabContainer('Navigator'); + + $sFirstTab = MetaModel::GetConfig()->Get('impact_analysis_first_tab'); + $sContextKey = "itop-config-mgmt/relation_context/$sClass/$sRelation/$sDirection"; + + // Check if the current object supports Attachments, similar to AttachmentPlugin::IsTargetObject + $sClassForAttachment = null; + $iIdForAttachment = null; + if (class_exists('Attachment')) { + $aAllowedClasses = MetaModel::GetModuleSetting('itop-attachments', 'allowed_classes', array('Ticket')); + foreach ($aAllowedClasses as $sAllowedClass) { + if ($oObj instanceof $sAllowedClass) { + $iIdForAttachment = $id; + $sClassForAttachment = $sClass; + } } } - } // Display the tabs if ($sFirstTab == 'list') diff --git a/pages/csvimport.php b/pages/csvimport.php index 68848066f..d4b95e616 100644 --- a/pages/csvimport.php +++ b/pages/csvimport.php @@ -1278,23 +1278,20 @@ EOF function Welcome(iTopWebPage $oPage) { $sSynchroScope = utils::ReadParam('synchro_scope', '', false, 'raw_data'); - if (!empty($sSynchroScope)) - { + if (!empty($sSynchroScope)) { $oSearch = DBObjectSearch::FromOQL($sSynchroScope); $sClassName = $oSearch->GetClass(); $oSet = new DBObjectSet($oSearch); $iCount = $oSet->Count(); DisplaySynchroBanner($oPage, $sClassName, $iCount); $aSynchroUpdate = utils::ReadParam('synchro_update', array()); - } - else - { + } else { $aSynchroUpdate = null; } - + $oPage->add("

".Dict::S('UI:Title:BulkImport+')."

\n"); - $oPage->AddTabContainer('tabs1'); - + $oPage->AddTabContainer('tabs1'); + $sSeparator = utils::ReadParam('separator', '', false, 'raw_data'); $sTextQualifier = utils::ReadParam('text_qualifier', '', false, 'raw_data'); $bHeaderLine = utils::ReadParam('header_line', true); @@ -1303,7 +1300,7 @@ EOF $sEncoding = utils::ReadParam('encoding', ''); $sDateTimeFormat = utils::ReadParam('date_time_format', 'default'); $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', (string)AttributeDateTime::GetFormat(), false, 'raw_data'); - + if ($sEncoding == '') { $sEncoding = MetaModel::GetConfig()->Get('csv_file_default_charset'); diff --git a/pages/schema.php b/pages/schema.php index d869dee11..bd5c3fe4e 100644 --- a/pages/schema.php +++ b/pages/schema.php @@ -851,20 +851,15 @@ function DisplayClassDetails($oPage, $sClass, $sContext) $aDetails = array(); $aOrigins = array(); - foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) - { - if ($oAttDef->IsExternalKey()) - { + foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { + if ($oAttDef->IsExternalKey()) { $sValue = Dict::Format('UI:Schema:ExternalKey_To', MakeClassHLink($oAttDef->GetTargetClass(), $sContext)); - if (array_key_exists($sAttCode, $aForwardChangeTracking)) - { + if (array_key_exists($sAttCode, $aForwardChangeTracking)) { $oLinkSet = $aForwardChangeTracking[$sAttCode]; $sRemoteClass = $oLinkSet->GetHostClass(); $sValue = $sValue."*"; } - } - elseif ($oAttDef->IsLinkSet()) - { + } elseif ($oAttDef->IsLinkSet()) { $sValue = MakeClassHLink($oAttDef->GetLinkedClass(), $sContext); } else diff --git a/sources/application/UI/Component/Form/Form.php b/sources/application/UI/Component/Form/Form.php index 750e3f4ec..56dedd331 100644 --- a/sources/application/UI/Component/Form/Form.php +++ b/sources/application/UI/Component/Form/Form.php @@ -22,16 +22,20 @@ class Form extends UIContentBlock /** @var string */ protected $sOnSubmitJsCode; + /** @var string */ + protected $sAction; public function __construct(string $sName = null) { parent::__construct($sName); $this->sOnSubmitJsCode = null; + $this->sAction = null; } - public function SetOnSubmitJsCode(string $sJsCode): void + public function SetOnSubmitJsCode(string $sJsCode): Form { $this->sOnSubmitJsCode = $sJsCode; + return $this; } /** @@ -42,5 +46,23 @@ class Form extends UIContentBlock return $this->sOnSubmitJsCode; } + /** + * @return string + */ + public function GetAction(): string + { + return $this->sAction; + } + + /** + * @param string $sAction + * + * @return Form + */ + public function SetAction(string $sAction): Form + { + $this->sAction = $sAction; + return $this; + } } \ No newline at end of file diff --git a/sources/application/UI/Layout/UIContentBlock.php b/sources/application/UI/Layout/UIContentBlock.php index 70de264ea..6db1e34a6 100644 --- a/sources/application/UI/Layout/UIContentBlock.php +++ b/sources/application/UI/Layout/UIContentBlock.php @@ -22,6 +22,8 @@ class UIContentBlock extends UIBlock implements iUIContentBlock protected $aCSSClasses; /** @var array */ protected $aSubBlocks; + /** @var array */ + protected $aDataAttributes; /** * UIContentBlock constructor. @@ -34,6 +36,7 @@ class UIContentBlock extends UIBlock implements iUIContentBlock parent::__construct($sName); $this->aSubBlocks = []; + $this->aDataAttributes = []; $this->SetCSSClasses($sContainerClass); } @@ -150,4 +153,36 @@ class UIContentBlock extends UIBlock implements iUIContentBlock return $this; } + /** + * @return array + */ + public function GetDataAttributes(): array + { + return $this->aDataAttributes; + } + + /** + * @param array $aDataAttributes + * + * @return UIContentBlock + */ + public function SetDataAttributes(array $aDataAttributes): UIContentBlock + { + $this->aDataAttributes = $aDataAttributes; + return $this; + } + + + /** + * @param string $sName + * @param string $sValue + * + * @return UIContentBlock + */ + public function AddDataAttributes(string $sName, string $sValue): UIContentBlock + { + $this->aDataAttributes[$sName] = $sValue; + return $this; + } + } diff --git a/sources/application/WebPage/AjaxPage.php b/sources/application/WebPage/AjaxPage.php index 402c87c46..2dbaf70de 100644 --- a/sources/application/WebPage/AjaxPage.php +++ b/sources/application/WebPage/AjaxPage.php @@ -6,6 +6,7 @@ use Combodo\iTop\Application\TwigBase\Twig\TwigHelper; use Combodo\iTop\Application\UI\iUIBlock; +use Combodo\iTop\Application\UI\Layout\iUIContentBlock; use Combodo\iTop\Renderer\BlockRenderer; class AjaxPage extends WebPage implements iTabbedPage @@ -46,7 +47,7 @@ class AjaxPage extends WebPage implements iTabbedPage * @inheritDoc * @throws \Exception */ - public function AddTabContainer($sTabContainer, $sPrefix = '') + public function AddTabContainer($sTabContainer, $sPrefix = '', iUIContentBlock $oParentBlock = null) { $this->AddUiBlock($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix)); } diff --git a/sources/application/WebPage/iTabbedPage.php b/sources/application/WebPage/iTabbedPage.php index 672e87a4d..ecd7ce9b0 100644 --- a/sources/application/WebPage/iTabbedPage.php +++ b/sources/application/WebPage/iTabbedPage.php @@ -1,19 +1,22 @@ SetColor(Panel::ENUM_COLOR_BLUE); $oPanel->AddSubBlock($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix)); - $this->AddUiBlock($oPanel); + if (!is_null($oParentBlock)) { + $oParentBlock->AddSubBlock($oPanel); + } else { + $this->AddUiBlock($oPanel); + } } /** diff --git a/templates/components/form/layout.html.twig b/templates/components/form/layout.html.twig index b5a1e546e..ac2ab090e 100644 --- a/templates/components/form/layout.html.twig +++ b/templates/components/form/layout.html.twig @@ -1,4 +1,6 @@ -
+ {% apply spaceless %} {% block iboContentBlockContainer %} {% for oSubBlock in oUIBlock.GetSubBlocks() %} diff --git a/templates/layouts/contentblock/layout.html.twig b/templates/layouts/contentblock/layout.html.twig index 52b2a215e..99224068f 100644 --- a/templates/layouts/contentblock/layout.html.twig +++ b/templates/layouts/contentblock/layout.html.twig @@ -1,8 +1,15 @@ {% apply spaceless %} {% block iboContentBlockContainer %} - {% if oUIBlock.GetCSSClasses() %} -
+ {% if oUIBlock.GetCSSClasses() or oUIBlock.GetDataAttributes() %} +
{% endif %} {% for oSubBlock in oUIBlock.GetSubBlocks() %}