diff --git a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php index 27e1353f9..98030eb9c 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php @@ -30,6 +30,7 @@ use \utils; use \Dict; use \IssueLog; use \MetaModel; +use \DBObject; use \DBSearch; use \DBObjectSearch; use \FalseExpression; @@ -42,6 +43,7 @@ use \DBObjectSet; use \cmdbAbstractObject; use \AttributeEnum; use \AttributeFinalClass; +use \AttributeFriendlyName; use \UserRights; use \iPopupMenuExtension; use \URLButtonItem; @@ -1050,40 +1052,7 @@ class ObjectController extends AbstractController $aItems = array(); while ($oItem = $oSet->Fetch()) { - $aItemProperties = array( - 'id' => $oItem->GetKey(), - 'name' => $oItem->GetName(), - 'attributes' => array() - ); - - foreach ($aAttCodes as $sAttCode) - { - if ($sAttCode !== 'id') - { - $aAttProperties = array( - 'att_code' => $sAttCode - ); - - $oAttDef = MetaModel::GetAttributeDef($sTargetObjectClass, $sAttCode); - if ($oAttDef->IsExternalKey()) - { - $aAttProperties['value'] = $oItem->Get($sAttCode . '_friendlyname'); - // Checking if we can view the object - if ((SecurityHelper::IsActionAllowed($oApp, UR_ACTION_READ, $oAttDef->GetTargetClass(), $oItem->Get($sAttCode)))) - { - $aAttProperties['url'] = $oApp['url_generator']->generate('p_object_view', array('sObjectClass' => $oAttDef->GetTargetClass(), 'sObjectId' => $oItem->Get($sAttCode))); - } - } - else - { - $aAttProperties['value'] = $oAttDef->GetValueLabel($oItem->Get($sAttCode)); - } - - $aItemProperties['attributes'][$sAttCode] = $aAttProperties; - } - } - - $aItems[] = $aItemProperties; + $aItems[] = $this->PrepareObjectInformations($oApp, $oItem, $aAttCodes); } // Preparing response @@ -1556,16 +1525,6 @@ class ObjectController extends AbstractController $aObjectAttCodes = array_merge(array('id'), $aObjectAttCodes); } - // Retrieving attributes definitions - $aAttDefs = array(); - foreach ($aObjectAttCodes as $sObjectAttCode) - { - if ($sObjectAttCode === 'id') - continue; - - $aAttDefs[$sObjectAttCode] = MetaModel::GetAttributeDef($sObjectClass, $sObjectAttCode); - } - // Building the search $bIgnoreSilos = $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass); $oSearch = DBObjectSearch::FromOQL("SELECT " . $sObjectClass . " WHERE id IN ('" . implode("','", $aObjectIds) . "')"); @@ -1579,42 +1538,80 @@ class ObjectController extends AbstractController // Retrieving objects while ($oObject = $oSet->Fetch()) { - $aObjectData = array( - 'id' => $oObject->GetKey(), - 'attributes' => array() - ); - - foreach ($aAttDefs as $oAttDef) - { - $aAttData = array( - 'att_code' => $oAttDef->GetCode() - ); - - if ($oAttDef->IsExternalKey()) - { - $aAttData['value'] = $oObject->Get($oAttDef->GetCode() . '_friendlyname'); - if (SecurityHelper::IsActionAllowed($oApp, UR_ACTION_READ, $oAttDef->GetTargetClass())) - { - $aAttData['url'] = $oApp['url_generator']->generate('p_object_view', array('sObjectClass' => $oAttDef->GetTargetClass(), 'sObjectId' => $oObject->Get($oAttDef->GetCode()))); - } - } - elseif ($oAttDef->IsLinkSet()) - { - // We skip it - continue; - } - else - { - $aAttData['value'] = $oAttDef->GetValueLabel($oObject->Get($oAttDef->GetCode())); - } - - $aObjectData['attributes'][$oAttDef->GetCode()] = $aAttData; - } - - $aData['items'][] = $aObjectData; + $aData['items'][] = $this->PrepareObjectInformations($oApp, $oObject, $aObjectAttCodes); } return $oApp->json($aData); } + /** + * Prepare a DBObject informations as an array for a client side usage (typically, add a row in a table) + * + * @param \Silex\Application $oApp + * @param \Combodo\iTop\Portal\Controller\DBObject $oObject + * @param array $aAttCodes + * + * @return array + */ + protected function PrepareObjectInformations(Application $oApp, DBObject $oObject, $aAttCodes = array()) + { + $sObjectClass = get_class($oObject); + $aObjectData = array( + 'id' => $oObject->GetKey(), + 'name' => $oObject->GetName(), + 'attributes' => array(), + ); + + // Retrieving attributes definitions + $aAttDefs = array(); + foreach ($aAttCodes as $sAttCode) + { + if ($sAttCode === 'id') + continue; + + $aAttDefs[$sAttCode] = MetaModel::GetAttributeDef($sObjectClass, $sAttCode); + } + + // Preparing attribute data + foreach ($aAttDefs as $oAttDef) + { + $aAttData = array( + 'att_code' => $oAttDef->GetCode() + ); + + if ($oAttDef->IsExternalKey()) + { + $aAttData['value'] = $oObject->Get($oAttDef->GetCode() . '_friendlyname'); + + // Checking if user can access object's external key + if (SecurityHelper::IsActionAllowed($oApp, UR_ACTION_READ, $oAttDef->GetTargetClass())) + { + $aAttData['url'] = $oApp['url_generator']->generate('p_object_view', array('sObjectClass' => $oAttDef->GetTargetClass(), 'sObjectId' => $oObject->Get($oAttDef->GetCode()))); + } + } + elseif ($oAttDef->IsLinkSet()) + { + // We skip it + continue; + } + else + { + $aAttData['value'] = $oAttDef->GetValueLabel($oObject->Get($oAttDef->GetCode())); + + if ($oAttDef instanceof AttributeFriendlyName) + { + // Checking if user can access object + if(SecurityHelper::IsActionAllowed($oApp, UR_ACTION_READ, $sObjectClass)) + { + $aAttData['url'] = $oApp['url_generator']->generate('p_object_view', array('sObjectClass' => $sObjectClass, 'sObjectId' => $oObject->GetKey())); + } + } + } + + $aObjectData['attributes'][$oAttDef->GetCode()] = $aAttData; + } + + return $aObjectData; + } + } diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig index 4c1bf3141..cffc20cbd 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig @@ -134,6 +134,32 @@ $(oRow).addClass('selected'); $(oRow).find('td:first-child input').prop('checked', true); } + + // Opening in a new modal on click + $(oRow).find('a').off('click').on('click', function(oEvent){ + // Prevents link opening. + oEvent.preventDefault(); + // Prevents row selection + oEvent.stopPropagation(); + + // Note : This could be better if we check for an existing modal first instead of always creating a new one + var oModalElem = $('#modal-for-all').clone(); + oModalElem.attr('id', '').appendTo('body'); + // Loading content + oModalElem.find('.modal-content').html($('#page_overlay .overlay_content').html()); + oModalElem.find('.modal-content').load( + $(this).attr('href'), + {}, + function(sResponseText, sStatus, oXHR){ + // Hiding modal in case of error as the general AJAX error handler will display a message + if(sStatus === 'error') + { + oModalElem.modal('hide'); + } + } + ); + oModalElem.modal('show'); + }); }, "drawCallback": function(settings){ // Hiding pagination if only one page diff --git a/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php index 5397f50ba..67e9ddbd2 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php @@ -190,7 +190,7 @@ EOF if(row.attributes[data].url !== undefined) { cellElem = $(''); - cellElem.attr('target', '_blank').attr('href', row.attributes[data].url); + cellElem.attr('href', row.attributes[data].url); } else { @@ -228,6 +228,33 @@ EOF "select": {$sSelectionOptionHtml}, "rowId": "id", "data": oRawDatas_{$this->oField->GetGlobalId()}, + "rowCallback": function(oRow, oData){ + // Opening in a new modal on click + $(oRow).find('a').off('click').on('click', function(oEvent){ + // Prevents link opening. + oEvent.preventDefault(); + // Prevents row selection + oEvent.stopPropagation(); + + // Note : This could be better if we check for an existing modal first instead of always creating a new one + var oModalElem = $('#modal-for-all').clone(); + oModalElem.attr('id', '').appendTo('body'); + // Loading content + oModalElem.find('.modal-content').html($('#page_overlay .overlay_content').html()); + oModalElem.find('.modal-content').load( + $(this).attr('href'), + {}, + function(sResponseText, sStatus, oXHR){ + // Hiding modal in case of error as the general AJAX error handler will display a message + if(sStatus === 'error') + { + oModalElem.modal('hide'); + } + } + ); + oModalElem.modal('show'); + }); + }, }); // Handles items selection/deselection