public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj) { $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); 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); 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); } }
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { $sOwnershipToken = null; $iKey = $this->GetKey(); $sClass = get_class($this); if ($iKey > 0) { // The concurrent access lock makes sense only for already existing objects $LockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled'); if ($LockEnabled) { $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data'); if ($sOwnershipToken !== null) { // We're probably inside something like "apply_modify" where the validation failed and we must prompt the user again to edit the object // let's extend our lock $aLockInfo = iTopOwnershipLock::ExtendLock($sClass, $iKey, $sOwnershipToken); $sOwnershipDate = $aLockInfo['acquired']; } else { $aLockInfo = iTopOwnershipLock::AcquireLock($sClass, $iKey); if ($aLockInfo['success']) { $sOwnershipToken = $aLockInfo['token']; $sOwnershipDate = $aLockInfo['acquired']; } else { $oOwner = $aLockInfo['lock']->GetOwner(); // If the object is locked by the current user, it's worth trying again, since // the lock may be released by 'onunload' which is called AFTER loading the current page. //$bTryAgain = $oOwner->GetKey() == UserRights::GetUserId(); self::ReloadAndDisplay($oPage, $this, array('operation' => 'modify')); return; } } } } if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) { $sClassLabel = MetaModel::GetName($sClass); $oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $this->GetRawName(), $sClassLabel)); // Set title will take care of the encoding $oPage->add("<div class=\"page_header\">\n"); $oPage->add("<h1>" . $this->GetIcon() . " " . Dict::Format('UI:ModificationTitle_Class_Object', $sClassLabel, $this->GetName()) . "</h1>\n"); $oPage->add("</div>\n"); $oPage->add("<div class=\"wizContainer\">\n"); } self::$iGlobalFormId++; $this->aFieldsMap = array(); $sPrefix = ''; if (isset($aExtraParams['formPrefix'])) { $sPrefix = $aExtraParams['formPrefix']; } $aFieldsComments = isset($aExtraParams['fieldsComments']) ? $aExtraParams['fieldsComments'] : array(); $this->m_iFormId = $sPrefix . self::$iGlobalFormId; $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $aDetails = array(); $aFieldsMap = array(); 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 { $sFormAction = $aExtraParams['action']; } // Custom label for the apply button ? if (isset($aExtraParams['custom_button'])) { $sApplyButton = $aExtraParams['custom_button']; } else { if ($iKey > 0) { $sApplyButton = Dict::S('UI:Button:Apply'); } else { $sApplyButton = Dict::S('UI:Button:Create'); } } // Custom operation for the form ? if (isset($aExtraParams['custom_operation'])) { $sOperation = $aExtraParams['custom_operation']; } else { if ($iKey > 0) { $sOperation = 'apply_modify'; } else { $sOperation = 'apply_new'; } } if ($iKey > 0) { // The object already exists in the database, it's a modification $sButtons = "<input id=\"{$sPrefix}_id\" type=\"hidden\" name=\"id\" value=\"{$iKey}\">\n"; $sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\"><span>" . Dict::S('UI:Button:Cancel') . "</span></button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } else { // The object does not exist in the database it's a creation $sButtons = "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\">" . Dict::S('UI:Button:Cancel') . "</button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } $aTransitions = $this->EnumTransitions(); 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) { $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: $sButtons .= "<button type=\"submit\" name=\"next_action\" value=\"{$sStimulusCode}\" class=\"action\"><span>" . $aStimuli[$sStimulusCode]->GetLabel() . "</span></button>\n"; break; default: // Do nothing } } } $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position'); $iTransactionId = isset($aExtraParams['transaction_id']) ? $aExtraParams['transaction_id'] : utils::GetNewTransactionId(); $oPage->SetTransactionId($iTransactionId); $oPage->add("<form action=\"{$sFormAction}\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n"); $sStatesSelection = ''; if (!isset($aExtraParams['custom_operation']) && $this->IsNew()) { $aInitialStates = MetaModel::EnumInitialStates($sClass); //$aInitialStates = array('new' => 'foo', 'closed' => 'bar'); if (count($aInitialStates) > 1) { $sStatesSelection = Dict::Format('UI:Create_Class_InState', MetaModel::GetName($sClass)) . '<select name="obj_state" class="state_select_' . $this->m_iFormId . '">'; foreach ($aInitialStates as $sStateCode => $sStateData) { $sSelected = ''; if ($sStateCode == $this->GetState()) { $sSelected = ' selected'; } $sStatesSelection .= '<option value="' . $sStateCode . '"' . $sSelected . '>' . MetaModel::GetStateLabel($sClass, $sStateCode) . '</option>'; } $sStatesSelection .= '</select>'; $oPage->add_ready_script("\$('.state_select_{$this->m_iFormId}').change( function() { oWizardHelper{$sPrefix}.ReloadObjectCreationForm('form_{$this->m_iFormId}', \$(this).val()); } );"); } } $sConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $sJSToken = json_encode($sOwnershipToken); $oPage->add_ready_script(<<<EOF \t\$(window).unload(function() { return OnUnload('{$iTransactionId}', '{$sClass}', {$iKey}, {$sJSToken}) } ); \twindow.onbeforeunload = function() { \t\tif (!window.bInSubmit && !window.bInCancel) \t\t{ \t\t\treturn '{$sConfirmationMessage}';\t \t\t} \t\t// return nothing ! safer for IE \t}; EOF ); if ($sButtonsPosition != 'bottom') { // top or both, display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams); if ($iKey > 0) { $aFieldsMap['id'] = $sPrefix . '_id'; } // Now display the relations, one tab per relation if (!isset($aExtraParams['noRelations'])) { $this->DisplayBareRelations($oPage, true); // Edit mode, will fill $this->aFieldsMap $aFieldsMap = array_merge($aFieldsMap, $this->aFieldsMap); } $oPage->SetCurrentTab(''); $oPage->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n"); $oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"{$iTransactionId}\">\n"); foreach ($aExtraParams as $sName => $value) { if (is_scalar($value)) { $oPage->add("<input type=\"hidden\" name=\"{$sName}\" value=\"{$value}\">\n"); } } if ($sOwnershipToken !== null) { $oPage->add("<input type=\"hidden\" name=\"ownership_token\" value=\"" . htmlentities($sOwnershipToken, ENT_QUOTES, 'UTF-8') . "\">\n"); } $oPage->add($oAppContext->GetForForm()); if ($sButtonsPosition != 'top') { // bottom or both: display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } // 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("</form>\n"); if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) { $oPage->add("</div>\n"); } $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); $sState = $this->GetState(); $sSessionStorageKey = $sClass . '_' . $iKey; $oPage->add_script(<<<EOF \t\tsessionStorage.removeItem('{$sSessionStorageKey}'); \t\t \t\t// Create the object once at the beginning of the page... \t\tvar oWizardHelper{$sPrefix} = new WizardHelper('{$sClass}', '{$sPrefix}', '{$sState}'); \t\toWizardHelper{$sPrefix}.SetFieldsMap({$sJsonFieldsMap}); \t\toWizardHelper{$sPrefix}.SetFieldsCount({$iFieldsCount}); EOF ); $oPage->add_ready_script(<<<EOF \t\toWizardHelper{$sPrefix}.UpdateWizard(); \t\t// Starts the validation when the page is ready \t\tCheckFields('form_{$this->m_iFormId}', false); EOF ); if ($sOwnershipToken !== null) { $this->GetOwnershipJSHandler($oPage, $sOwnershipToken); } else { // Probably a new object (or no concurrent lock), let's add a watchdog so that the session is kept open while editing $iInterval = MetaModel::GetConfig()->Get('concurrent_lock_expiration_delay') * 1000 / 2; if ($iInterval > 0) { $iInterval = max(MIN_WATCHDOG_INTERVAL * 1000, $iInterval); // Minimum interval for the watchdog is MIN_WATCHDOG_INTERVAL $oPage->add_ready_script(<<<EOF \t\t\t\twindow.setInterval(function() { \t\t\t\t\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'watchdog'}); \t\t\t\t}, {$iInterval}); EOF ); } } }
$sClass = trim(utils::ReadParam('class', '')); $iTune = utils::ReadParam('tune', 0); if (preg_match('/^"(.*)"$/', $sFullText, $aMatches)) { // The text is surrounded by double-quotes, remove the quotes and treat it as one single expression $aFullTextNeedles = array($aMatches[1]); } else { // Split the text on the blanks and treat this as a search for <word1> AND <word2> AND <word3> $aFullTextNeedles = explode(' ', $sFullText); } $oFilter = new DBObjectSearch($sClass); foreach ($aFullTextNeedles as $sSearchText) { $oFilter->AddCondition_FullText($sSearchText); } $oSet = new DBObjectSet($oFilter); $oPage->add("<div class=\"page_header\">\n"); $oPage->add("<h2>" . MetaModel::GetClassIcon($sClass) . " <span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sClass)) . "</h2>\n"); $oPage->add("</div>\n"); if ($oSet->Count() > 0) { $aLeafs = array(); while ($oObj = $oSet->Fetch()) { if (get_class($oObj) == $sClass) { $aLeafs[] = $oObj->GetKey(); } } $oLeafsFilter = new DBObjectSearch($sClass); if (count($aLeafs) > 0) { $oLeafsFilter->AddCondition('id', $aLeafs, 'IN'); $oBlock = new DisplayBlock($oLeafsFilter, 'list', false); $sBlockId = 'global_search_' . $sClass; $oPage->add('<div id="' . $sBlockId . '">'); $oBlock->RenderContent($oPage, array('table_id' => $sBlockId, 'currentId' => $sBlockId));
/** * 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'); 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(); $id = $oObj->GetKey(); $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 (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); static $bPopupScript = false; if (!$bPopupScript) { // Output this once per page... $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n"); $bPopupScript = true; } return $sHtml; }
public static function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists) { $oSettings = new DataTableSettings($aClassAliases); // Retrieve the class specific settings for each class/alias based on the 'list' ZList //TODO let the caller pass some other default settings (another Zlist, extre fields...) $aColumns = array(); foreach ($aClassAliases as $sAlias => $sClass) { if ($aDefaultLists == null) { $aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list')); } else { $aList = $aDefaultLists[$sAlias]; } $aSortOrder = MetaModel::GetOrderByDefault($sClass); if ($bViewLink) { $sSort = 'none'; if (array_key_exists('friendlyname', $aSortOrder)) { $sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc'; } $aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true, $sSort); } foreach ($aList as $sAttCode) { $sSort = 'none'; if (array_key_exists($sAttCode, $aSortOrder)) { $sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc'; } $oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode); $aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true, $sSort); if ($aFieldData) { $aColumns[$sAlias][$sAttCode] = $aFieldData; } } } $iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns); return $oSettings; }
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { self::$iGlobalFormId++; $this->aFieldsMap = array(); $sPrefix = ''; if (isset($aExtraParams['formPrefix'])) { $sPrefix = $aExtraParams['formPrefix']; } $aFieldsComments = isset($aExtraParams['fieldsComments']) ? $aExtraParams['fieldsComments'] : array(); $this->m_iFormId = $sPrefix . self::$iGlobalFormId; $sClass = get_class($this); $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $iKey = $this->GetKey(); $aDetails = array(); $aFieldsMap = array(); if (!isset($aExtraParams['action'])) { $sFormAction = $_SERVER['SCRIPT_NAME']; // No parameter in the URL, the only parameter will be the ones passed through the form } else { $sFormAction = $aExtraParams['action']; } // Custom label for the apply button ? if (isset($aExtraParams['custom_button'])) { $sApplyButton = $aExtraParams['custom_button']; } else { if ($iKey > 0) { $sApplyButton = Dict::S('UI:Button:Apply'); } else { $sApplyButton = Dict::S('UI:Button:Create'); } } // Custom operation for the form ? if (isset($aExtraParams['custom_operation'])) { $sOperation = $aExtraParams['custom_operation']; } else { if ($iKey > 0) { $sOperation = 'apply_modify'; } else { $sOperation = 'apply_new'; } } if ($iKey > 0) { // The object already exists in the database, it's a modification $sButtons = "<input id=\"{$sPrefix}_id\" type=\"hidden\" name=\"id\" value=\"{$iKey}\">\n"; $sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\"><span>" . Dict::S('UI:Button:Cancel') . "</span></button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } else { // The object does not exist in the database it's a creation $sButtons = "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\">" . Dict::S('UI:Button:Cancel') . "</button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } $aTransitions = $this->EnumTransitions(); 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) { $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: $sButtons .= "<button type=\"submit\" name=\"next_action\" value=\"{$sStimulusCode}\" class=\"action\"><span>" . $aStimuli[$sStimulusCode]->GetLabel() . "</span></button>\n"; break; default: // Do nothing } } } $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position'); $iTransactionId = isset($aExtraParams['transaction_id']) ? $aExtraParams['transaction_id'] : utils::GetNewTransactionId(); $oPage->SetTransactionId($iTransactionId); $oPage->add("<form action=\"{$sFormAction}\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n"); $sStatesSelection = ''; if (!isset($aExtraParams['custom_operation']) && $this->IsNew()) { $aInitialStates = MetaModel::EnumInitialStates($sClass); //$aInitialStates = array('new' => 'foo', 'closed' => 'bar'); if (count($aInitialStates) > 1) { $sStatesSelection = Dict::Format('UI:Create_Class_InState', MetaModel::GetName($sClass)) . '<select name="obj_state" class="state_select_' . $this->m_iFormId . '">'; foreach ($aInitialStates as $sStateCode => $sStateData) { $sSelected = ''; if ($sStateCode == $this->GetState()) { $sSelected = ' selected'; } $sStatesSelection .= '<option value="' . $sStateCode . '"' . $sSelected . '>' . MetaModel::GetStateLabel($sClass, $sStateCode) . '</option>'; } $sStatesSelection .= '</select>'; $oPage->add_ready_script("\$('.state_select_{$this->m_iFormId}').change( function() { oWizardHelper{$sPrefix}.ReloadObjectCreationForm('form_{$this->m_iFormId}', \$(this).val()); } );"); } } $sConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $oPage->add_ready_script(<<<EOF \t\$(window).unload(function() { return OnUnload('{$iTransactionId}') } ); \twindow.onbeforeunload = function() { \t\tif (!window.bInSubmit && !window.bInCancel) \t\t{ \t\t\treturn '{$sConfirmationMessage}';\t \t\t} \t\t// return nothing ! safer for IE \t}; EOF ); if ($sButtonsPosition != 'bottom') { // top or both, display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams); if ($iKey > 0) { $aFieldsMap['id'] = $sPrefix . '_id'; } // Now display the relations, one tab per relation if (!isset($aExtraParams['noRelations'])) { $this->DisplayBareRelations($oPage, true); // Edit mode, will fill $this->aFieldsMap $aFieldsMap = array_merge($aFieldsMap, $this->aFieldsMap); } $oPage->SetCurrentTab(''); $oPage->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n"); $oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"{$iTransactionId}\">\n"); foreach ($aExtraParams as $sName => $value) { if (is_scalar($value)) { $oPage->add("<input type=\"hidden\" name=\"{$sName}\" value=\"{$value}\">\n"); } } $oPage->add($oAppContext->GetForForm()); if ($sButtonsPosition != 'top') { // bottom or both: display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } // 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}')} );"); $oPage->add("</form>\n"); $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); $sState = $this->GetState(); $oPage->add_script(<<<EOF \t\t// Create the object once at the beginning of the page... \t\tvar oWizardHelper{$sPrefix} = new WizardHelper('{$sClass}', '{$sPrefix}', '{$sState}'); \t\toWizardHelper{$sPrefix}.SetFieldsMap({$sJsonFieldsMap}); \t\toWizardHelper{$sPrefix}.SetFieldsCount({$iFieldsCount}); EOF ); $oPage->add_ready_script(<<<EOF \t\toWizardHelper{$sPrefix}.UpdateWizard(); \t\t// Starts the validation when the page is ready \t\tCheckFields('form_{$this->m_iFormId}', false); EOF ); }
function DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj) { $oP->SetCurrentTab(Dict::S('UI:RelationshipList')); $oP->add("<div id=\"impacted_objects\" style=\"width:100%;background-color:#fff;padding:10px;\">"); $iBlock = 1; // Zero is not a valid blockid foreach ($aResults as $sListClass => $aObjects) { $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects); $oP->add("<h1>" . MetaModel::GetRelationDescription($sRelation) . ' ' . $oObj->GetName() . "</h1>\n"); $oP->add("<div class=\"page_header\">\n"); $oP->add("<h2>" . MetaModel::GetClassIcon($sListClass) . " <span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sListClass)) . "</h2>\n"); $oP->add("</div>\n"); $oBlock = DisplayBlock::FromObjectSet($oSet, 'list'); $oBlock->Display($oP, $iBlock++); $oP->P(' '); // Some space ? } $oP->add("</div>"); }
$oGraph->UpdatePositions($aPositions); } $oPage->add($oGraph->GetAsJSON($sContextKey)); $oPage->SetContentType('application/json'); break; case 'relation_groups': $aGroups = utils::ReadParam('groups'); $iBlock = 1; // Zero is not a valid blockid foreach ($aGroups as $idx => $aDefinition) { $sListClass = $aDefinition['class']; $oSearch = new DBObjectSearch($sListClass); $oSearch->AddCondition('id', $aDefinition['keys'], 'IN'); $oPage->add("<h1>" . Dict::Format('UI:RelationGroupNumber_N', 1 + $idx) . "</h1>\n"); $oPage->add("<div id=\"relation_group_{$idx}\" class=\"page_header\">\n"); $oPage->add("<h2>" . MetaModel::GetClassIcon($sListClass) . " <span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aDefinition['keys']), Metamodel::GetName($sListClass)) . "</h2>\n"); $oPage->add("</div>\n"); $oBlock = new DisplayBlock($oSearch, 'list'); $oBlock->Display($oPage, 'group_' . $iBlock++); $oPage->p(' '); // Some space ? } break; case 'ticket_impact': require_once APPROOT . 'core/simplegraph.class.inc.php'; require_once APPROOT . 'core/relationgraph.class.inc.php'; require_once APPROOT . 'core/displayablegraph.class.inc.php'; $sRelation = utils::ReadParam('relation', 'impacts'); $sDirection = utils::ReadParam('direction', 'down'); $iGroupingThreshold = utils::ReadParam('g', 5); $sClass = utils::ReadParam('class', '', false, 'class');
function DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj) { if (count($aGroups) > 0) { $oP->SetCurrentTab(Dict::S('UI:RelationGroups')); $oP->add("<div id=\"impacted_groupss\" style=\"width:100%;background-color:#fff;padding:10px;\">"); $iBlock = 1; // Zero is not a valid blockid foreach ($aGroups as $idx => $aObjects) { $sListClass = get_class(current($aObjects)); $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects); $oP->add("<h1>" . Dict::Format('UI:RelationGroupNumber_N', 1 + $idx) . "</h1>\n"); $oP->add("<div id=\"relation_group_{$idx}\" class=\"page_header\">\n"); $oP->add("<h2>" . MetaModel::GetClassIcon($sListClass) . " <span class=\"hilite\">" . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sListClass)) . "</h2>\n"); $oP->add("</div>\n"); $oBlock = DisplayBlock::FromObjectSet($oSet, 'list'); $oBlock->Display($oP, 'group_' . $iBlock++); $oP->p(' '); // Some space ? } $oP->add("</div>"); } }
if (!array_key_exists($sObjClass, $aResults)) { $aResults[$sObjClass] = array(); } $aResults[$sObjClass][] = $oObj; } } $oPage->get_tcpdf()->AddPage(); $oPage->get_tcpdf()->SetFont('dejavusans', '', 10, '', true); // Reset the font size to its default $oPage->add('<div class="page_header"><h1>' . Dict::S('UI:RelationshipList') . '</h1></div>'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); foreach ($aResults as $sListClass => $aObjects) { set_time_limit($iLoopTimeLimit); $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects); $sHtml = "<div class=\"page_header\">\n"; $sHtml .= "<table class=\"section\"><tr><td>" . MetaModel::GetClassIcon($sListClass, true, 'width: 24px; height: 24px;') . " " . Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', $oSet->Count(), Metamodel::GetName($sListClass)) . "</td></tr></table>\n"; $sHtml .= "</div>\n"; $oPage->add($sHtml); cmdbAbstractObject::DisplaySet($oPage, $oSet); $oPage->p(''); // Some space } // Then the content of the groups (one table per group) if (count($aGroups) > 0) { $oPage->get_tcpdf()->AddPage(); $oPage->add('<div class="page_header"><h1>' . Dict::S('UI:RelationGroups') . '</h1></div>'); foreach ($aGroups as $idx => $aObjects) { set_time_limit($iLoopTimeLimit); $sListClass = get_class(current($aObjects)); $oSet = CMDBObjectSet::FromArray($sListClass, $aObjects); $sHtml = "<div class=\"page_header\">\n";