/**
  * Add result details - object reference
  *
  * @param string sLabel
  * @param object oObject
  */
 public function AddResultObject($sLabel, $oObject)
 {
     $oAppContext = new ApplicationContext();
     $this->m_aResult[$sLabel] = array('id' => $oObject->GetKey(), 'name' => $oObject->GetRawName(), 'url' => $oAppContext->MakeObjectUrl(get_class($oObject), $oObject->GetKey(), null, false));
 }
示例#2
0
 public static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
 {
     if ($sObjKey <= 0) {
         return '<em>' . Dict::S('UI:UndefinedObject') . '</em>';
     }
     // Objects built in memory have negative IDs
     // Safety net
     //
     if (empty($sLabel)) {
         // If the object if not issued from a query but constructed programmatically
         // the label may be empty. In this case run a query to get the object's friendly name
         $oTmpObj = MetaModel::GetObject($sObjClass, $sObjKey, false);
         if (is_object($oTmpObj)) {
             $sLabel = $oTmpObj->GetName();
         } else {
             // May happen in case the target object is not in the list of allowed values for this attribute
             $sLabel = "<em>{$sObjClass}::{$sObjKey}</em>";
         }
         //$sLabel = MetaModel::GetName($sObjClass)." #$sObjKey";
     }
     $sHint = MetaModel::GetName($sObjClass) . "::{$sObjKey}";
     $sUrl = ApplicationContext::MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass, $bWithNavigationContext);
     if (strlen($sUrl) > 0) {
         return "<a href=\"{$sUrl}\" title=\"{$sHint}\">{$sLabel}</a>";
     } else {
         return $sLabel;
     }
 }
 /**
  * Renders the "Actions" popup menu for the given set of objects
  * 
  * Note that the menu links containing (or ending) with a hash (#) will have their fragment
  * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is
  * displayed, to correspond to the current hash/fragment in the page. This allows modifying
  * an object in with the same tab active by default as the tab that was active when selecting
  * the "Modify..." action.
  */
 public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
 {
     if ($this->m_sStyle == 'popup') {
         $this->m_sStyle = 'list';
     }
     $sHtml = '';
     $oAppContext = new ApplicationContext();
     $sContext = $oAppContext->GetForLink();
     if (!empty($sContext)) {
         $sContext = '&' . $sContext;
     }
     $sClass = $this->m_oFilter->GetClass();
     $oReflectionClass = new ReflectionClass($sClass);
     $oSet = new CMDBObjectSet($this->m_oFilter);
     $sFilter = $this->m_oFilter->serialize();
     $sFilterDesc = $this->m_oFilter->ToOql(true);
     $aActions = array();
     $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
     $sRootUrl = utils::GetAbsoluteUrlAppRoot();
     // 1:n links, populate the target object as a default value when creating a new linked object
     if (isset($aExtraParams['target_attr'])) {
         $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id'];
     }
     $sDefault = '';
     if (!empty($aExtraParams['default'])) {
         foreach ($aExtraParams['default'] as $sKey => $sValue) {
             $sDefault .= "&default[{$sKey}]={$sValue}";
         }
     }
     $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
     $sRefreshAction = '';
     switch ($oSet->Count()) {
         case 0:
             // No object in the set, the only possible action is "new"
             if ($bIsCreationAllowed) {
                 $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
             }
             break;
         case 1:
             $oObj = $oSet->Fetch();
             if (is_null($oObj)) {
                 if (!isset($aExtraParams['link_attr'])) {
                     if ($bIsCreationAllowed) {
                         $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                     }
                 }
             } else {
                 $id = $oObj->GetKey();
                 if (utils::ReadParam('operation') == 'details') {
                     if ($_SERVER['REQUEST_METHOD'] == 'GET') {
                         $sRefreshAction = "window.location.reload();";
                     } else {
                         $sRefreshAction = "window.location.href='" . ApplicationContext::MakeObjectUrl(get_class($oObj), $id) . "';";
                     }
                 }
                 $bLocked = false;
                 if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) {
                     $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id);
                     if ($aLockInfo['locked']) {
                         $bLocked = true;
                         //$this->AddMenuSeparator($aActions);
                         //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}");
                     }
                 }
                 $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
                 $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed;
                 $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
                 // Just one object in the set, possible actions are "new / clone / modify and delete"
                 if (!isset($aExtraParams['link_attr'])) {
                     if ($bIsModifyAllowed) {
                         $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#");
                     }
                     if ($bIsCreationAllowed) {
                         $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                     }
                     if ($bIsDeleteAllowed) {
                         $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}");
                     }
                     // Transitions / Stimuli
                     if (!$bLocked) {
                         $aTransitions = $oObj->EnumTransitions();
                         if (count($aTransitions)) {
                             $this->AddMenuSeparator($aActions);
                             $aStimuli = Metamodel::EnumStimuli(get_class($oObj));
                             foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                                 $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
                                 switch ($iActionAllowed) {
                                     case UR_ALLOWED_YES:
                                         $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}");
                                         break;
                                     default:
                                         // Do nothing
                                 }
                             }
                         }
                     }
                     // Relations...
                     $aRelations = MetaModel::EnumRelationsEx($sClass);
                     if (count($aRelations)) {
                         $this->AddMenuSeparator($aActions);
                         foreach ($aRelations as $sRelationCode => $aRelationInfo) {
                             if (array_key_exists('down', $aRelationInfo)) {
                                 $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}");
                             }
                             if (array_key_exists('up', $aRelationInfo)) {
                                 $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}");
                             }
                         }
                     }
                     if ($bLocked && $bRawModifiedAllowed) {
                         // Add a special menu to kill the lock, but only to allowed users who can also modify this object
                         $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
                         $bCanKill = false;
                         $oUser = UserRights::GetUserObject();
                         $aUserProfiles = array();
                         if (!is_null($oUser)) {
                             $oProfileSet = $oUser->Get('profile_list');
                             while ($oProfile = $oProfileSet->Fetch()) {
                                 $aUserProfiles[$oProfile->Get('profile')] = true;
                             }
                         }
                         foreach ($aAllowedProfiles as $sProfile) {
                             if (array_key_exists($sProfile, $aUserProfiles)) {
                                 $bCanKill = true;
                                 break;
                             }
                         }
                         if ($bCanKill) {
                             $this->AddMenuSeparator($aActions);
                             $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}");
                         }
                     }
                     /*
                     $this->AddMenuSeparator($aActions);
                     // Static menus: Email this page & CSV Export
                     $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
                     $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
                     $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                     // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object 
                     if ($this->m_sStyle == 'list')
                     {
                     	// Actions specific to the list
                     	$sOQL = addslashes($sFilterDesc);
                     	$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                     }
                     */
                 }
                 $this->AddMenuSeparator($aActions);
                 foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
                     $oSet->Rewind();
                     foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) {
                         $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl);
                     }
                 }
             }
             break;
         default:
             // Check rights
             // New / Modify
             $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet);
             if (isset($aExtraParams['link_attr'])) {
                 $id = $aExtraParams['object_id'];
                 $sTargetAttr = $aExtraParams['target_attr'];
                 $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
                 $sTargetClass = $oAttDef->GetTargetClass();
                 $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}");
                 }
                 //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
             } else {
                 // many objects in the set, possible actions are: new / modify all / delete all
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 if ($bIsBulkDeleteAllowed) {
                     $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 // Stimuli
                 $aStates = MetaModel::EnumStates($sClass);
                 // Do not perform time consuming computations if there are too may objects in the list
                 $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
                 if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) {
                     // Life cycle actions may be available... if all objects are in the same state
                     //
                     // Group by <state>
                     $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
                     $aGroupBy = array('__state__' => $oGroupByExp);
                     $aQueryParams = array();
                     if (isset($aExtraParams['query_params'])) {
                         $aQueryParams = $aExtraParams['query_params'];
                     }
                     $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy);
                     $aRes = CMDBSource::QueryToArray($sSql);
                     if (count($aRes) == 1) {
                         // All objects are in the same state...
                         $sState = $aRes[0]['__state__'];
                         $aTransitions = Metamodel::EnumTransitions($sClass, $sState);
                         if (count($aTransitions)) {
                             $this->AddMenuSeparator($aActions);
                             $aStimuli = Metamodel::EnumStimuli($sClass);
                             foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                                 $oSet->Rewind();
                                 // As soon as the user rights implementation will browse the object set,
                                 // then we might consider using OptimizeColumnLoad() here
                                 $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet);
                                 $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO;
                                 switch ($iActionAllowed) {
                                     case UR_ALLOWED_YES:
                                     case UR_ALLOWED_DEPENDS:
                                         $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                                         break;
                                     default:
                                         // Do nothing
                                 }
                             }
                         }
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 $sUrl = utils::GetAbsoluteUrlAppRoot();
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 $sOQL = addslashes($sFilterDesc);
                 $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 */
             }
     }
     $this->AddMenuSeparator($aActions);
     foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
         $oSet->Rewind();
         foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) {
             if (is_array($data)) {
                 // New plugins can provide javascript handlers via the 'onclick' property
                 //TODO: enable extension of different menus by checking the 'target' property ??
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
             } else {
                 // Backward compatibility with old plugins
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data);
             }
         }
     }
     // New extensions based on iPopupMenuItem interface
     switch ($this->m_sStyle) {
         case 'list':
             $oSet->Rewind();
             $param = $oSet;
             $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
             break;
         case 'details':
             $oSet->Rewind();
             $param = $oSet->Fetch();
             $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
             break;
     }
     utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
     $aFavoriteActions = array();
     $aCallSpec = array($sClass, 'GetShortcutActions');
     if (is_callable($aCallSpec)) {
         $aShortcutActions = call_user_func($aCallSpec, $sClass);
         foreach ($aActions as $key => $aAction) {
             if (in_array($key, $aShortcutActions)) {
                 $aFavoriteActions[] = $aAction;
                 unset($aActions[$key]);
             }
         }
     } else {
         $aShortcutActions = array();
     }
     if (!$oPage->IsPrintableVersion()) {
         if (count($aFavoriteActions) > 0) {
             $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n";
         } else {
             $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n";
         }
         $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
         if (!$oPage->IsPrintableVersion() && $sRefreshAction != '') {
             $sHtml .= "<div class=\"actions_button\" title=\"" . htmlentities(Dict::S('UI:Button:Refresh'), ENT_QUOTES, 'UTF-8') . "\"><span class=\"refresh-button\" onclick=\"{$sRefreshAction}\"></span></div>";
         }
     }
     static $bPopupScript = false;
     if (!$bPopupScript) {
         // Output this once per page...
         $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n");
         $bPopupScript = true;
     }
     return $sHtml;
 }
示例#4
0
 /**
  * Merge standard menu items with plugin provided menus items
  */
 public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions, $sTableId = null, $sDataTableId = null)
 {
     // 1st - add standard built-in menu items
     //
     switch ($iMenuId) {
         case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
             // $param is a DBObjectSet
             $oAppContext = new ApplicationContext();
             $sContext = $oAppContext->GetForLink();
             $sDataTableId = is_null($sDataTableId) ? '' : $sDataTableId;
             $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
             $sOQL = addslashes($param->GetFilter()->ToOQL(true));
             $sFilter = urlencode($param->GetFilter()->serialize());
             $sUrl = utils::GetAbsoluteUrlAppRoot() . "pages/{$sUIPage}?operation=search&filter=" . $sFilter . "&{$sContext}";
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/tabularfieldsselector.js');
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.dragtable.js');
             $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/dragtable.css');
             $aResult = array(new SeparatorPopupMenuItem(), new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?body=" . urlencode($sUrl) . ' '));
             if (UserRights::IsActionAllowed($param->GetFilter()->GetClass(), UR_ACTION_BULK_READ, $param) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS)) {
                 // Bulk export actions
                 $aResult[] = new JSPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), "ExportListDlg('{$sOQL}', '{$sDataTableId}', 'csv', " . json_encode(Dict::S('UI:Menu:CSVExport')) . ")");
                 $aResult[] = new JSPopupMenuItem('UI:Menu:ExportXLSX', Dict::S('ExcelExporter:ExportMenu'), "ExportListDlg('{$sOQL}', '{$sDataTableId}', 'xlsx', " . json_encode(Dict::S('ExcelExporter:ExportMenu')) . ")");
                 $aResult[] = new JSPopupMenuItem('UI:Menu:ExportPDF', Dict::S('UI:Menu:ExportPDF'), "ExportListDlg('{$sOQL}', '{$sDataTableId}', 'pdf', " . json_encode(Dict::S('UI:Menu:ExportPDF')) . ")");
             }
             $aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('{$sOQL}')");
             $aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('{$sOQL}', '{$sDataTableId}', '{$sContext}')");
             break;
         case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
             // $param is a DBObject
             $oObj = $param;
             $sOQL = "SELECT " . get_class($oObj) . " WHERE id=" . $oObj->GetKey();
             $oFilter = DBObjectSearch::FromOQL($sOQL);
             $sFilter = $oFilter->serialize();
             $sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
             $sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
             $oAppContext = new ApplicationContext();
             $sContext = $oAppContext->GetForLink();
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/tabularfieldsselector.js');
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.dragtable.js');
             $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/dragtable.css');
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/tabularfieldsselector.js');
             $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.dragtable.js');
             $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/dragtable.css');
             $aResult = array(new SeparatorPopupMenuItem(), new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?subject=" . urlencode($oObj->GetRawName()) . "&body=" . urlencode($sUrl) . ' '), new JSPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), "ExportListDlg('{$sOQL}', '', 'csv', " . json_encode(Dict::S('UI:Menu:CSVExport')) . ")"), new JSPopupMenuItem('UI:Menu:ExportXLSX', Dict::S('ExcelExporter:ExportMenu'), "ExportListDlg('{$sOQL}', '', 'xlsx', " . json_encode(Dict::S('ExcelExporter:ExportMenu')) . ")"));
             break;
         case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
             // $param is a Dashboard
             $oAppContext = new ApplicationContext();
             $aParams = $oAppContext->GetAsHash();
             $sMenuId = ApplicationMenu::GetActiveNodeId();
             $sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
             $sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
             $sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
             $aResult = array(new SeparatorPopupMenuItem(), new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=export_dashboard&id=' . $sMenuId), new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '{$sMenuId}', title: '{$sDlgTitle}', text: '{$sDlgText}', close_btn: '{$sCloseBtn}' })"));
             break;
         default:
             // Unknown type of menu, do nothing
             $aResult = array();
     }
     foreach ($aResult as $oMenuItem) {
         $aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
     }
     // Invoke the plugins
     //
     foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance) {
         if (is_object($param) && !$param instanceof DBObject) {
             $tmpParam = clone $param;
             // In case the parameter is an DBObjectSet, clone it to prevent alterations
         } else {
             $tmpParam = $param;
         }
         foreach ($oExtensionInstance->EnumItems($iMenuId, $tmpParam) as $oMenuItem) {
             if (is_object($oMenuItem)) {
                 $aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
                 foreach ($oMenuItem->GetLinkedScripts() as $sLinkedScript) {
                     $oPage->add_linked_script($sLinkedScript);
                 }
             }
         }
     }
 }