/** * 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 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 ); } } }
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 ); }