diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php index 92a2dd901..8b0302723 100644 --- a/application/ajaxwebpage.class.inc.php +++ b/application/ajaxwebpage.class.inc.php @@ -33,6 +33,9 @@ class ajax_page extends WebPage * @var Hash */ protected $m_sReadyScript; + protected $m_sCurrentTab; + protected $m_sCurrentTabContainer; + protected $m_aTabs; /** * constructor for the web page @@ -44,8 +47,44 @@ class ajax_page extends WebPage $this->m_sReadyScript = ""; $this->add_header("Content-type: text/html; charset=utf-8"); $this->add_header("Cache-control: no-cache"); + $this->m_sCurrentTabContainer = ''; + $this->m_sCurrentTab = ''; + $this->m_aTabs = array(); } + public function AddTabContainer($sTabContainer, $sPrefix = '') + { + $this->m_aTabs[$sTabContainer] = array('content' =>'', 'prefix' => $sPrefix); + $this->add("\$Tabs:$sTabContainer\$"); + } + + public function AddToTab($sTabContainer, $sTabLabel, $sHtml) + { + if (!isset($this->m_aTabs[$sTabContainer]['content'][$sTabLabel])) + { + // Set the content of the tab + $this->m_aTabs[$sTabContainer]['content'][$sTabLabel] = $sHtml; + } + else + { + // Append to the content of the tab + $this->m_aTabs[$sTabContainer]['content'][$sTabLabel] .= $sHtml; + } + } + + public function SetCurrentTabContainer($sTabContainer = '') + { + $sPreviousTabContainer = $this->m_sCurrentTabContainer; + $this->m_sCurrentTabContainer = $sTabContainer; + return $sPreviousTabContainer; + } + + public function SetCurrentTab($sTabLabel = '') + { + $sPreviousTab = $this->m_sCurrentTab; + $this->m_sCurrentTab = $sTabLabel; + return $sPreviousTab; + } /** * Echoes the content of the whole page @@ -57,15 +96,88 @@ class ajax_page extends WebPage { header($s_header); } + + if (count($this->m_aTabs) > 0) + { + $this->add_ready_script( +<<m_aTabs as $sTabContainerName => $aTabContainer) + { + $sTabs = ''; + $m_aTabs = $aTabContainer['content']; + $sPrefix = $aTabContainer['prefix']; + $container_index = 0; + if (count($m_aTabs) > 0) + { + $sTabs = "\n
\n"; + $sTabs .= "\n"; + // Now add the content of the tabs themselves + $i = 0; + foreach($m_aTabs as $sTabName => $sTabContent) + { + $sTabs .= "
".$sTabContent."
\n"; + $i++; + } + $sTabs .= "
\n\n"; + } + $this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content); + $container_index++; + } + $s_captured_output = ob_get_contents(); ob_end_clean(); echo $this->s_content; echo $this->s_deferred_content; + if (count($this->a_scripts) > 0) + { + echo "\n"; + } if (!empty($this->m_sReadyScript)) { - echo "\n"; + echo "\n\n"; } if (trim($s_captured_output) != "") { @@ -82,6 +194,18 @@ class ajax_page extends WebPage public function small_p($sText) { } + + public function add($sHtml) + { + if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab)) + { + $this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml); + } + else + { + parent::add($sHtml); + } + } /** * Adds a script to be executed when the DOM is ready (typical JQuery use) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index ad214ec84..21676f21f 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1032,10 +1032,9 @@ EOF { static $iInputId = 0; $sFieldPrefix = ''; - if (isset($aArgs['prefix'])) - { - $sFieldPrefix = $aArgs['prefix']; - } + $sFormPrefix = isset($aArgs['formPrefix']) ? $aArgs['formPrefix'] : ''; + $sFieldPrefix = isset($aArgs['prefix']) ? $sFormPrefix.$aArgs['prefix'] : $sFormPrefix; + if (isset($aArgs[$sAttCode]) && empty($value)) { // default value passed by the context (either the app context of the operation) @@ -1136,7 +1135,7 @@ EOF if (count($aAllowedValues) >= $iMaxComboLength) { // too many choices, use an autocomplete - $oWidget = new UIAutoCompleteWidget($sAttCode, $sClass, $oAttDef->GetLabel(), $aAllowedValues, $value, $iId, $sNameSuffix, $sFieldPrefix); + $oWidget = new UIAutoCompleteWidget($sAttCode, $sClass, $oAttDef->GetLabel(), $aAllowedValues, $value, $iId, $sNameSuffix, $sFieldPrefix, $sFormPrefix); $sHTMLValue = $oWidget->Display($oPage, $aArgs); } @@ -1206,12 +1205,12 @@ EOF { $sNullValue = "'$sNullValue'"; // Add quotes to turn this into a JS string if it's not a number } - $oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $sMandatory, sFormId, $sNullValue) } );"); // Bind to a custom event: validate + $oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $sMandatory, sFormId, $sNullValue) } );\n"); // Bind to a custom event: validate } $aDependencies = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that depend on the current one if (count($aDependencies) > 0) { - $oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return UpdateDependentFields(['".implode("','", $aDependencies)."']) } );"); // Bind to a custom event: validate + $oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return oWizardHelper{$sFormPrefix}.UpdateDependentFields(['".implode("','", $aDependencies)."']) } );\n"); // Bind to a custom event: validate } } return "
{$sHTMLValue}
"; @@ -1219,9 +1218,14 @@ EOF public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { - static $iGlobalFormId = 0; + static $iGlobalFormId = 1; $iGlobalFormId++; - $this->m_iFormId = $iGlobalFormId; + $sPrefix = ''; + if (isset($aExtraParams['formPrefix'])) + { + $sPrefix = $aExtraParams['formPrefix']; + } + $this->m_iFormId = $sPrefix.$iGlobalFormId; $sClass = get_class($this); $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); @@ -1238,7 +1242,7 @@ EOF } $oPage->add("
m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return CheckFields('form_{$this->m_iFormId}', true)\">\n"); - $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB); + $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); // $aDetailsList = $this->FLattenZList(MetaModel::GetZListItems($sClass, 'details')); @@ -1310,7 +1314,7 @@ EOF { $sValue = $this->Get($sAttCode); $sDisplayValue = $this->GetEditValue($sAttCode); - $aArgs = array('this' => $this); + $aArgs = array('this' => $this, 'formPrefix' => $sPrefix); $sInputId = $this->m_iFormId.'_'.$sAttCode; $sHTMLValue = "".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).''; $aFieldsMap[$sAttCode] = $sInputId; @@ -1343,8 +1347,10 @@ EOF } // Now display the relations, one tab per relation - - $this->DisplayBareRelations($oPage, true); // Edit mode + if (!isset($aExtraParams['noRelations'])) + { + $this->DisplayBareRelations($oPage, true); // Edit mode + } $oPage->SetCurrentTab(''); $oPage->add("\n"); @@ -1359,16 +1365,20 @@ EOF // The object already exists in the database, it's modification $oPage->add("\n"); $oPage->add("\n"); - $oPage->add("    \n"); +// $oPage->add("    \n"); + $oPage->add("    \n"); $oPage->add("\n"); } else { // The object does not exist in the database it's a creation $oPage->add("\n"); - $oPage->add("    \n"); +// $oPage->add("    \n"); + $oPage->add("    \n"); $oPage->add("\n"); } + // Hook the cancel button via jQuery so that it can be unhooked easily as well if needed + $oPage->add_ready_script("$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('$sClass', $iKey)} );"); $oPage->add("
\n"); $iFieldsCount = count($aFieldsMap); @@ -1377,15 +1387,16 @@ EOF $oPage->add_script( <<add_ready_script( <<m_iFormId}', false); + EOF ); } @@ -1399,9 +1410,12 @@ EOF if ($oObjectToClone == null) { - $sTargetState = MetaModel::GetDefaultState($sClass); $oObj = MetaModel::NewObject($sClass); - $oObj->Set($sStateAttCode, $sTargetState); + if (!empty($sStateAttCode)) + { + $sTargetState = MetaModel::GetDefaultState($sClass); + $oObj->Set($sStateAttCode, $sTargetState); + } } else { @@ -1439,7 +1453,7 @@ EOF } } } - return $oObj->DisplayModifyForm( $oPage, $aExtraParams = array()); + return $oObj->DisplayModifyForm( $oPage, $aExtraParams); } protected static function ProcessZlist($aList, $aDetails, $sCurrentTab, $sCurrentCol, $sCurrentSet) @@ -1663,5 +1677,100 @@ EOF return $sContextParam; } } + + /** + * Updates the object from the POSTed parameters + */ + function UpdateObject($sFormPrefix = '') + { + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) + { + $aLinks = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", ''); + $sLinkedClass = $oAttDef->GetLinkedClass(); + $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); + $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); + $oLinkedSet = DBObjectSet::FromScratch($sLinkedClass); + if (is_array($aLinks)) + { + foreach($aLinks as $id => $aData) + { + if (is_numeric($id)) + { + if ($id < 0) + { + // New link to be created, the opposite of the id (-$id) is the ID of the remote object + $oLink = MetaModel::NewObject($sLinkedClass); + $oLink->Set($sExtKeyToRemote, -$id); + $oLink->Set($sExtKeyToMe, $this->GetKey()); + } + else + { + // Existing link, potentially to be updated... + $oLink = MetaModel::GetObject($sLinkedClass, $id); + } + // Now populate the attributes + foreach($aData as $sName => $value) + { + if (MetaModel::IsValidAttCode($sLinkedClass, $sName)) + { + $oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName); + if ($oLinkAttDef->IsWritable()) + { + $oLink->Set($sName, $value); + } + } + } + $oLinkedSet->AddObject($oLink); + } + } + } + $this->Set($sAttCode, $oLinkedSet); + } + else if ($oAttDef->IsWritable()) + { + $iFlags = $this->GetAttributeFlags($sAttCode); + if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) + { + // Non-visible, or read-only attribute, do nothing + } + elseif ($oAttDef->GetEditClass() == 'Document') + { + // There should be an uploaded file with the named attr_ + $oDocument = utils::ReadPostedDocument("file_{$sFormPrefix}{$sAttCode}"); + if (!$oDocument->IsEmpty()) + { + // A new file has been uploaded + $this->Set($sAttCode, $oDocument); + } + } + elseif ($oAttDef->GetEditClass() == 'One Way Password') + { + // Check if the password was typed/changed + $bChanged = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_changed", false); + if ($bChanged) + { + // The password has been changed or set + $rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); + $this->Set($sAttCode, $rawValue); + } + } + else + { + $rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); + if (!is_null($rawValue)) + { + $aAttributes[$sAttCode] = trim($rawValue); + $previousValue = $this->Get($sAttCode); + if ($previousValue !== $aAttributes[$sAttCode]) + { + $this->Set($sAttCode, $aAttributes[$sAttCode]); + } + } + } + } + } + } } ?> diff --git a/application/ui.autocompletewidget.class.inc.php b/application/ui.autocompletewidget.class.inc.php index b9cda145e..c5be47ed0 100644 --- a/application/ui.autocompletewidget.class.inc.php +++ b/application/ui.autocompletewidget.class.inc.php @@ -69,7 +69,7 @@ class UIAutoCompleteWidget protected $iId; protected $sTitle; - public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '') + public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '') { self::$iWidgetIndex++; $this->sAttCode = $sAttCode; @@ -82,6 +82,7 @@ class UIAutoCompleteWidget $this->sFieldPrefix = $sFieldPrefix; $this->sTargetClass = $this->oAttDef->GetTargetClass(); $this->sTitle = $sTitle; + $this->sFormPrefix = $sFormPrefix; } /** @@ -100,17 +101,25 @@ class UIAutoCompleteWidget { $sDisplayValue = $this->GetObjectName($this->value); } + $bCreate = UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY); $sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm'); + $sFormPrefix = $this->sFormPrefix; $oPage->add_ready_script( <<iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix'); + oACWidget_{$this->iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix', oWizardHelper$sFormPrefix); oACWidget_{$this->iId}.emptyHtml = "

$sMessage

"; EOF ); $iMinChars = $this->oAttDef->GetMinAutoCompleteChars(); // the input for the auto-complete - $sHTMLValue = "aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> iId}.Search();\"> iId}\">"; + $sHTMLValue = "aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> "; + $sHTMLValue .= "iId}.Search();\"> "; + if ($bCreate) + { + $sHTMLValue .= "iId}.CreateObject();\"> "; + } + $sHTMLValue .= "iId}\">"; // another hidden input to store & pass the object's Id $sHTMLValue .= "iId\" name=\"attr_{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n"; @@ -120,7 +129,12 @@ EOF $oPage->add_ready_script("\$('#label_$this->iId').blur(function() { $(this).search(); } );"); $oPage->add_ready_script("\$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('$this->iId', event, data, formatted); } );"); $oPage->add_ready_script("\$('#ac_dlg_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });\n"); + $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle'});\n"); $oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form + if ($bCreate) + { + $oPage->add_at_the_end($this->GetCreationDialog($oPage)); // To prevent adding forms inside the main form + } return $sHTMLValue; } @@ -143,12 +157,29 @@ EOF $sHTML .= "\n"; $sHTML .= ''; - $oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoSearchObjects);"); + $oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);"); $oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);"); return $sHTML; } + + protected function GetCreationDialog(WebPage $oPage) + { + $sHTML = '
'; + + //$sHTML .= "
iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoCreate();\">\n"; + //cmdbAbstractObject::DisplayCreationForm($oPage, 'Person', null, array()); + //$sHTML .= "iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_create_{$this->iId}').dialog('close');\">  "; + //$sHTML .= "iId}\" value=\"".Dict::S('UI:Button:New')."\" onClick=\"oACWidget_{$this->iId}.DoCreate();\">"; + //$sHTML .= "
\n"; + $sHTML .= '
'; + + //$oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);"); + + return $sHTML; + } + /** * Search for objects to be selected * @param WebPage $oP The page used for the output (usually an AjaxWebPage) @@ -181,5 +212,42 @@ EOF $oObj = MetaModel::GetObject($this->sTargetClass, $iObjId); return $oObj->GetName(); } + + /** + * Get the form to create a new object of the 'target' class + */ + public function GetObjectCreationForm(WebPage $oPage) + { + $oPage->add("

".MetaModel::GetClassIcon($this->sTargetClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."

\n"); + cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true)); + $oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');"); + $oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);"); + } + + /** + * Get the form to create a new object of the 'target' class + */ + public function DoCreateObject($oPage) + { + $oObj = MetaModel::NewObject($this->sTargetClass); + $oObj->UpdateObject($this->sFormPrefix.$this->iId); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::IsImpersonated()) + { + $sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUser(), UserRights::GetUser()); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBInsertTracked($oMyChange); + + return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey()); + + //return array('name' => 'test', 'id' => '42'); + } } ?> diff --git a/application/wizardhelper.class.inc.php b/application/wizardhelper.class.inc.php index 780b98cd7..958f19e07 100644 --- a/application/wizardhelper.class.inc.php +++ b/application/wizardhelper.class.inc.php @@ -227,6 +227,11 @@ class WizardHelper return $this->m_aData['m_sClass']; } + public function GetFormPrefix() + { + return $this->m_aData['m_sFormPrefix']; + } + public function GetIdForField($sFieldName) { $sResult = ''; diff --git a/images/mini_add.gif b/images/mini_add.gif new file mode 100644 index 000000000..b319dff5e Binary files /dev/null and b/images/mini_add.gif differ diff --git a/js/autocompletewidget.js b/js/autocompletewidget.js index 8137b3582..37c3326e8 100644 --- a/js/autocompletewidget.js +++ b/js/autocompletewidget.js @@ -13,7 +13,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -function AutocompleteWidget(id, sClass, sAttCode, sSuffix) +function AutocompleteWidget(id, sClass, sAttCode, sSuffix, oWizHelper) { this.id = id; this.sClass = sClass; @@ -21,7 +21,10 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) this.sSuffix = sSuffix; this.emptyHtml = ''; // content to be displayed when the search results are empty (when opening the dialog) this.emptyOnClose = true; // Workaround for the JQuery dialog being very slow when opening and closing if the content contains many INPUT tags + this.oWizardHelper = oWizHelper; + this.ajax_request = null; var me = this; + this.Init = function() { // make sure that the form is clean @@ -30,6 +33,15 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) $('#'+this.id+'_linksToRemove').val(''); } + this.StopPendingRequest = function() + { + if (this.ajax_request) + { + this.ajax_request.Abort(); + this.ajax_request = null; + } + } + this.Search = function() { $('#ac_dlg_'+me.id).dialog('open'); @@ -66,8 +78,6 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) } } - var ajax_request = null; - this.DoSearchObjects = function(id) { var theMap = { sAttCode: me.sAttCode, @@ -86,8 +96,8 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) } ); - oWizardHelper.UpdateWizard(); - theMap['json'] = oWizardHelper.ToJSON(); + me.oWizardHelper.UpdateWizard(); + theMap['json'] = me.oWizardHelper.ToJSON(); theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass' theMap['class'] = me.sClass; @@ -100,14 +110,10 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) // Make sure that we cancel any pending request before issuing another // since responses may arrive in arbitrary order - if (ajax_request != null) - { - ajax_request.abort(); - ajax_request = null; - } + this.StopPendingRequest(); // Run the query and display the results - ajax_request = $.post( 'ajax.render.php', theMap, + this.ajax_request = $.post( 'ajax.render.php', theMap, function(data) { $(sSearchAreaId).html(data); @@ -115,7 +121,7 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) $(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables $('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); }); me.UpdateButtons(); - ajax_request = null; + me.ajax_request = null; }, 'html' ); @@ -140,21 +146,18 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) // Make sure that we cancel any pending request before issuing another // since responses may arrive in arbitrary order - if (ajax_request != null) - { - ajax_request.abort(); - ajax_request = null; - } + this.StopPendingRequest(); // Run the query and get the result back directly in JSON - ajax_request = $.post( 'ajax.render.php', theMap, + this.ajax_request = $.post( 'ajax.render.php', theMap, function(data) { $('#label_'+me.id).val(data.name); $('#label_'+me.id).removeClass('ac_loading'); $('#'+me.id).val(iObjectId); $('#'+me.id).trigger('validate'); - ajax_request = null; + $('#label_'+me.id).focus(); + me.ajax_request = null; }, 'json' ); @@ -174,4 +177,96 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix) } $('#label_'+me.id).focus(); } + + this.CreateObject = function(oWizHelper) + { + // Query the server to get the form to create a target object + $('#label_'+me.id).addClass('ac_loading'); + me.oWizardHelper.UpdateWizard(); + var theMap = { sAttCode: me.sAttCode, + iInputId: me.id, + sSuffix: me.sSuffix, + 'class': me.sClass, + 'json': me.oWizardHelper.ToJSON(), + operation: 'objectCreationForm' + } + + // Make sure that we cancel any pending request before issuing another + // since responses may arrive in arbitrary order + this.StopPendingRequest(); + + // Run the query and get the result back directly in JSON + this.ajax_request = $.post( 'ajax.render.php', theMap, + function(data) + { + $('#dcr_'+me.id).html(data); + // Adjust the height of the dialog + $('#ac_create_'+me.id).dialog('open'); + var h = $('#ac_create_'+me.id+' .wizContainer').outerHeight(); + $('#ac_create_'+me.id).dialog( "option", "height", h+55 ); // space for dialog title and padding... + $('#ac_create_'+me.id).dialog( "option", "close", function() { $('#label_'+me.id).removeClass('ac_loading'); $('#label_'+me.id).focus(); } ); + // Modify the action of the cancel button + $('#ac_create_'+me.id+' button.cancel').unbind('click').click( me.CloseCreateObject ); + me.ajax_request = null; + }, + 'html' + ); + } + + this.CloseCreateObject = function() + { + $('#ac_create_'+me.id).dialog( "close" ); + $('#dcr_'+me.id).html(''); + } + + this.DoCreateObject = function() + { + var sFormId = $('#dcr_'+me.id+' form').attr('id'); + if (CheckFields(sFormId, true)) + { + $('#'+sFormId).block(); + var theMap = { sAttCode: me.sAttCode, + iInputId: me.id, + sSuffix: me.sSuffix, + 'class': me.sClass, + 'json': me.oWizardHelper.ToJSON() + } + + // Gather the values from the form + // Gather the parameters from the search form + $('#'+sFormId+' :input').each( + function(i) + { + if (this.name != '') + { + theMap[this.name] = this.value; + } + } + ); + // Override the 'operation' code + theMap['operation'] = 'doCreateObject'; + theMap['class'] = me.sClass; + + $('#ac_create_'+me.id).dialog('close'); + + // Make sure that we cancel any pending request before issuing another + // since responses may arrive in arbitrary order + this.StopPendingRequest(); + + // Run the query and get the result back directly in JSON + this.ajax_request = $.post( 'ajax.render.php', theMap, + function(data) + { + $('#label_'+me.id).val(data.name); + $('#'+me.id).val(data.id); + $('#'+me.id).trigger('validate'); + $('#label_'+me.id).removeClass('ac_loading'); + $('#label_'+me.id).focus(); + me.ajax_request = null; + }, + 'json' + ); + } + return false; // do NOT submit the form + } } \ No newline at end of file diff --git a/js/forms-json-utils.js b/js/forms-json-utils.js index 82268e8ab..c79112c57 100644 --- a/js/forms-json-utils.js +++ b/js/forms-json-utils.js @@ -231,6 +231,7 @@ function ValidateCKEditField(sFieldId, sPattern, bMandatory, sFormId, nullValue) setTimeout(function(){ValidateCKEditField(sFieldId, sPattern, bMandatory, sFormId, nullValue);}, 500); } +/* function UpdateDependentFields(aFieldNames) { //console.log('UpdateDependentFields:'); @@ -248,6 +249,7 @@ function UpdateDependentFields(aFieldNames) } oWizardHelper.AjaxQueryServer(); } +*/ function ResetPwd(id) { diff --git a/js/wizardhelper.js b/js/wizardhelper.js index 044b40277..1576b68a5 100644 --- a/js/wizardhelper.js +++ b/js/wizardhelper.js @@ -1,5 +1,5 @@ // Wizard Helper JavaScript class to communicate with the WizardHelper PHP class -function WizardHelper(sClass) +function WizardHelper(sClass, sFormPrefix) { this.m_oData = { 'm_sClass' : '', 'm_oFieldsMap': {}, @@ -8,7 +8,8 @@ function WizardHelper(sClass) 'm_aAllowedValuesRequested': [], 'm_oDefaultValue': {}, 'm_oAllowedValues': {}, - 'm_iFieldsCount' : 0 + 'm_iFieldsCount' : 0, + 'm_sFormPrefix' : sFormPrefix }; this.m_oData.m_sClass = sClass; @@ -135,4 +136,20 @@ function WizardHelper(sClass) this.m_oData.m_oCurrentValues[sFieldCode] = value; return value; } + + this.UpdateDependentFields = function(aFieldNames) + { + index = 0; + this.ResetQuery(); + this.UpdateWizard(); + while(index < aFieldNames.length ) + { + sAttCode = aFieldNames[index]; + sFieldId = this.GetFieldId(sAttCode); + $('#v_'+sFieldId).html(''); + this.RequestAllowedValues(sAttCode); + index++; + } + this.AjaxQueryServer(); + } } diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 8a4908d9e..5a2e00d9a 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -75,7 +75,6 @@ switch($operation) $sAttCode = utils::ReadParam('sAttCode', ''); $iInputId = utils::ReadParam('iInputId', ''); $sSuffix = utils::ReadParam('sSuffix', ''); - // To do: retrieve the object under construction & use it to filter the allowed values $sJson = utils::ReadParam('json', ''); $oWizardHelper = WizardHelper::FromJSON($sJson); $oObj = $oWizardHelper->GetTargetObject(); @@ -84,6 +83,36 @@ switch($operation) $oWidget->SearchObjectsToSelect($oPage, $sTargetClass); break; + // ui.autocompletewidget + case 'objectCreationForm': + $sTargetClass = utils::ReadParam('sRemoteClass', ''); + $sAttCode = utils::ReadParam('sAttCode', ''); + $iInputId = utils::ReadParam('iInputId', ''); + $sSuffix = utils::ReadParam('sSuffix', ''); + $sJson = utils::ReadParam('json', ''); + $oWizardHelper = WizardHelper::FromJSON($sJson); + $oObj = $oWizardHelper->GetTargetObject(); + $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array('this' => $oObj)); + $oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', $aAllowedValues, $oObj->Get($sAttCode), $iInputId, $sSuffix, ''); + $oWidget->GetObjectCreationForm($oPage); + break; + + // ui.autocompletewidget + case 'doCreateObject': + $sTargetClass = utils::ReadParam('sRemoteClass', ''); + $sAttCode = utils::ReadParam('sAttCode', ''); + $iInputId = utils::ReadParam('iInputId', ''); + $sSuffix = utils::ReadParam('sSuffix', ''); + $sJson = utils::ReadParam('json', ''); + $oWizardHelper = WizardHelper::FromJSON($sJson); + $oObj = $oWizardHelper->GetTargetObject(); + $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array('this' => $oObj)); + // The iInputId of the autocomplete is the prefix for the form used to create the target object + $oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', $aAllowedValues, null, $iInputId, $sSuffix, $oWizardHelper->GetFormPrefix()); + $aResult = $oWidget->DoCreateObject($oPage); + echo json_encode($aResult); + break; + // ui.autocompletewidget case 'getObjectName': $sTargetClass = utils::ReadParam('sTargetClass', ''); @@ -126,6 +155,7 @@ switch($operation) $oWizardHelper->SetDefaultValue($sAttCode, $defaultValue); $oObj->Set($sAttCode, $defaultValue); } + $sFormPrefix = $oWizardHelper->GetFormPrefix(); foreach($oWizardHelper->GetFieldsForAllowedValues() as $sAttCode) { $sId = $oWizardHelper->GetIdForField($sAttCode); @@ -138,13 +168,13 @@ switch($operation) $displayValue = $oObj->GetEditValue($sAttCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $iFlags = MetaModel::GetAttributeFlags($sClass, $oObj->GetState(), $sAttCode); - $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj)); + $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix)); // Make sure that we immediatly validate the field when we reload it $oPage->add_ready_script("$('#$sId').trigger('validate');"); $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue); } } - $oPage->add("\n"); + $oPage->add_script("oWizardHelper{$sFormPrefix}.m_oData=".$oWizardHelper->ToJSON().";\noWizardHelper{$sFormPrefix}.UpdateFields();\n"); break; case 'ajax':