- Improved (more interactive) validation of the forms.

SVN:trunk[460]
This commit is contained in:
Denis Flaven
2010-06-14 09:10:54 +00:00
parent f29217379e
commit 23c19c599e
9 changed files with 212 additions and 102 deletions

View File

@@ -404,7 +404,7 @@ abstract class cmdbAbstractObject extends CMDBObject
$sFilter = $oSet->GetFilter()->serialize();
$aExtraParams['display_limit'] = false; // To expand the full list
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
$sHtml .= '<tr class="containerHeader"><td>'.Dict::Format('UI:TruncatedResults', utils::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).'&nbsp;&nbsp;<a href="Javascript:ReloadTruncatedList(\''.$divId.'\', \''.$sFilter.'\', \''.$sExtraParams.'\');">'.Dict::S('UI:DisplayAll').'</a></td><td>';
$sHtml .= '<tr class="containerHeader"><td>'.Dict::Format('UI:TruncatedResults', utils::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).'&nbsp;&nbsp;<a href="#open_'.$divId.'" onClick="Javascript:ReloadTruncatedList(\''.$divId.'\', \''.$sFilter.'\', \''.$sExtraParams.'\');">'.Dict::S('UI:DisplayAll').'</a></td><td>';
$oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');");
$oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');");
}
@@ -856,6 +856,7 @@ abstract class cmdbAbstractObject extends CMDBObject
else
{
$iInputId++;
$iId = $iInputId;
}
if (!$oAttDef->IsExternalField())
@@ -868,31 +869,38 @@ abstract class cmdbAbstractObject extends CMDBObject
$bMandatory = 1;
}
$sCSSClasses = self::GetCSSClasses($aCSSClasses);
$sValidationField = "<span id=\"v_{$iInputId}\"></span>";
$sValidationField = "<span id=\"v_{$iId}\"></span>";
$sHelpText = $oAttDef->GetHelpOnEdition();
$aEventsList = array('validate');
switch($oAttDef->GetEditClass())
{
case 'Date':
case 'DateTime':
$aCSSClasses[] = 'date-pick';
$sCSSClasses = self::GetCSSClasses($aCSSClasses);
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses}/>$sValidationField";
$aEventsList[] ='keyup';
$aEventsList[] ='change';
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iId\"/>";
break;
case 'Password':
$sHTMLValue = "<input title=\"$sHelpText\" type=\"password\" size=\"30\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses}/>$sValidationField";
$aEventsList[] ='keyup';
$aEventsList[] ='change';
$sHTMLValue = "<input title=\"$sHelpText\" type=\"password\" size=\"30\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iId\"/>";
break;
case 'Text':
$sHTMLValue = "<textarea title=\"$sHelpText\" name=\"attr_{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iInputId\"{$sCSSClasses}>$value</textarea>$sValidationField";
$aEventsList[] ='keypress';
$aEventsList[] ='change';
$sHTMLValue = "<textarea title=\"$sHelpText\" name=\"attr_{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">$value</textarea>";
break;
case 'List':
$oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sNameSuffix);
$aEventsList[] ='change';
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix);
$sHTMLValue = $oWidget->Display($oPage, $value);
break;
case 'Document':
$aEventsList[] ='change';
$oDocument = $value; // Value is an ormDocument object
$sFileName = '';
if (is_object($oDocument))
@@ -901,9 +909,9 @@ abstract class cmdbAbstractObject extends CMDBObject
}
$iMaxFileSize = utils::ConvertToBytes(ini_get('upload_max_filesize'));
$sHTMLValue = "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"$iMaxFileSize\" />\n";
$sHTMLValue .= "<input name=\"attr_{$sAttCode}{$sNameSuffix}\" type=\"hidden\" id=\"$iInputId\" \" value=\"$sFileName\"/>\n";
$sHTMLValue .= "<input name=\"attr_{$sAttCode}{$sNameSuffix}\" type=\"hidden\" id=\"$iId\" \" value=\"$sFileName\"/>\n";
$sHTMLValue .= "<span id=\"name_$iInputId\">$sFileName</span><br/>\n";
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"file_{$sAttCode}{$sNameSuffix}\" type=\"file\" id=\"file_$iInputId\" onChange=\"UpdateFileName('$iInputId', this.value);\"/>\n";
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"file_{$sAttCode}{$sNameSuffix}\" type=\"file\" id=\"file_$iId\" onChange=\"UpdateFileName('$iId', this.value)\"/>\n";
break;
case 'String':
@@ -922,22 +930,23 @@ abstract class cmdbAbstractObject extends CMDBObject
{
// too many choices, use an autocomplete
// The input for the auto complete
$sHTMLValue = "<input count=\"".count($aAllowedValues)."\" type=\"text\" id=\"label_$iInputId\" size=\"30\" value=\"$sDisplayValue\"{$sCSSClasses}/>$sValidationField";
$sHTMLValue = "<input count=\"".count($aAllowedValues)."\" type=\"text\" id=\"label_$iId\" size=\"30\" value=\"$sDisplayValue\"{$sCSSClasses}/>$sValidationField";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$iInputId\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" />\n";
$oPage->add_ready_script("\$('#label_$iInputId').autocomplete('./ajax.render.php', { scroll:true, minChars:3, onItemSelect:selectItem, onFindValue:findValue, formatItem:formatItem, autoFill:true, keyHolder:'#$iInputId', extraParams:{operation:'autocomplete', sclass:'$sClass',attCode:'".$sAttCode."'}});");
$oPage->add_ready_script("\$('#label_$iInputId').result( function(event, data, formatted) { if (data) { $('#{$iInputId}').val(data[1]); } } );");
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" />\n";
$oPage->add_ready_script("\$('#label_$iId').autocomplete('./ajax.render.php', { scroll:true, minChars:3, onItemSelect:selectItem, onFindValue:findValue, formatItem:formatItem, autoFill:true, keyHolder:'#$iId', extraParams:{operation:'autocomplete', sclass:'$sClass',attCode:'".$sAttCode."'}});");
$oPage->add_ready_script("\$('#label_$iId').result( function(event, data, formatted) { if (data) { $('#{$iId}').val(data[1]); } } );");
// Prepopulate with a default value -- but no display value...
//if (!empty($value))
//{
// $oPage->add_ready_script("\$('#label_$iInputId').search( 'domino.combodo.com' );");
//}
$aEventsList[] ='change';
}
else
{
// Few choices, use a normal 'select'
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iInputId\"{$sCSSClasses}>\n";
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iId\">\n";
$sHTMLValue .= "<option value=\"0\">".Dict::S('UI:SelectOne')."</option>\n";
foreach($aAllowedValues as $key => $display_value)
{
@@ -945,23 +954,26 @@ abstract class cmdbAbstractObject extends CMDBObject
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
}
$sHTMLValue .= "</select>$sValidationField\n";
$aEventsList[] ='change';
}
}
else
{
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses} />$sValidationField";
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iId\"/>";
$aEventsList[] ='keyup';
$aEventsList[] ='change';
}
break;
}
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
$oPage->add_ready_script("$('#$iInputId').bind('validate blur', function(evt, sFormId) { return ValidateField('$iInputId', '$sPattern', $bMandatory, sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId) } );"); // 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("$('#$iInputId').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 UpdateDependentFields(['".implode("','", $aDependencies)."']) } );"); // Bind to a custom event: validate
}
}
return $sHTMLValue;
return "<div>{$sHTMLValue}{$sValidationField}</div>";
}
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array())
@@ -974,7 +986,7 @@ abstract class cmdbAbstractObject extends CMDBObject
$iKey = $this->GetKey();
$aDetails = array();
$aFieldsMap = array();
$oPage->add("<form id=\"form_{$iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return CheckFields('form_{$iFormId}')\">\n");
$oPage->add("<form id=\"form_{$iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return CheckFields('form_{$iFormId}', true)\">\n");
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
{
if ($oAttDef->IsWritable())
@@ -1024,7 +1036,7 @@ abstract class cmdbAbstractObject extends CMDBObject
$oPage->add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">\n");
}
$oPage->add($oAppContext->GetForForm());
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"goBack()\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', $iKey)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oPage->add("<button type=\"submit\" class=\"action\"><span>".Dict::S('UI:Button:Apply')."</span></button>\n");
$oPage->add("</form>\n");
@@ -1038,6 +1050,12 @@ abstract class cmdbAbstractObject extends CMDBObject
oWizardHelper.SetFieldsMap($sJsonFieldsMap);
oWizardHelper.SetFieldsCount($iFieldsCount);
EOF
);
$oPage->add_ready_script(
<<<EOF
// Initializes the object once at the beginning of the page...
CheckFields('form_{$iFormId}', false);
EOF
);
}
@@ -1046,12 +1064,14 @@ EOF
static $iCreationFormId = 0;
$iCreationFormId++;
$iFieldIndex = 0;
$oAppContext = new ApplicationContext();
$aDetails = array();
$aFieldsMap = array();
$sOperation = ($oObjectToClone == null) ? 'apply_new' : 'apply_clone';
$sClass = ($oObjectToClone == null) ? $sClass : get_class($oObjectToClone);
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
$oPage->add("<form id=\"creation_form_{$iCreationFormId}\" method=\"post\" enctype=\"multipart/form-data\" onSubmit=\"return CheckFields('creation_form_{$iCreationFormId}')\">\n");
$oPage->add("<form id=\"creation_form_{$iCreationFormId}\" method=\"post\" enctype=\"multipart/form-data\" onSubmit=\"return CheckFields('creation_form_{$iCreationFormId}', true)\">\n");
$aStates = MetaModel::EnumStates($sClass);
if ($oObjectToClone == null)
{
@@ -1062,24 +1082,31 @@ EOF
$sTargetState = $oObjectToClone->GetState();
}
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
//foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
foreach(MetaModel::GetZListItems($sClass, 'details') as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$iOptions = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0;
if ($sStateAttCode == $sAttCode)
{
// State attribute is always read-only from the UI
$sHTMLValue = $oObjectToClone->GetStateLabel();
$sHTMLValue = MetaModel::GetStateLabel($sClass, $sTargetState);
$aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
}
else if ((!$oAttDef->IsExternalField()) && ($oAttDef->IsWritable()) )
else if ((!$oAttDef->IsExternalField()) && ($oAttDef->IsWritable()) && ($iOptions != OPT_ATT_HIDDEN) && ($iOptions != OPT_ATT_READONLY) )
{
$sFieldId = 'att_'.$iFieldIndex;
$sValue = ($oObjectToClone == null) ? '' : $oObjectToClone->Get($sAttCode);
$sDisplayValue = ($oObjectToClone == null) ? '' : $oObjectToClone->GetEditValue($sAttCode);
$iOptions = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0;
$sHTMLValue = self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, '', '', $iOptions, $aArgs);
$sHTMLValue = "<div id=\"field_{$sFieldId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sFieldId, '', $iOptions, $aArgs)."</div>";
$aFieldsMap[$sFieldId] = $sAttCode;
$aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
$iFieldIndex++;
}
}
$oPage->details($aDetails);
if ($oObjectToClone != null)
{
@@ -1096,6 +1123,20 @@ EOF
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"goBack()\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oPage->add("<button type=\"submit\" class=\"action\"><span>".Dict::S('UI:Button:Apply')."</span></button>\n");
$oPage->add("</form>\n");
$aNewFieldsMap = array();
foreach($aFieldsMap as $id => $sFieldCode)
{
$aNewFieldsMap[$sFieldCode] = $id;
}
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aNewFieldsMap);
$oPage->add_script("
// Initializes the object once at the beginning of the page...
var oWizardHelper = new WizardHelper('$sClass');
oWizardHelper.SetFieldsMap($sJsonFieldsMap);
oWizardHelper.SetFieldsCount($iFieldsCount);");
$oPage->add_ready_script("CheckFields('creation_form_{$iCreationFormId}', false);");
}
protected static function GetCSSClasses($aCSSClasses)

View File

@@ -169,6 +169,11 @@ EOF
{
window.history.back();
}
function BackToDetails(sClass, id)
{
window.location.href = './UI.php?operation=details&class='+sClass+'&id='+id;
}
");
$this->DisplayMenu();
}

View File

@@ -90,6 +90,7 @@ class UILinksWidget
}
else
{
$sJSON = '[]'; // Empty array;
//echo "JSON VA IECH<br/>\n";
}
//echo "JASON: $sJSON<br/>\n";;

View File

@@ -39,12 +39,19 @@ class WizardHelper
*/
public function GetTargetObject($bReadUploadedFiles = false)
{
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
if (isset($this->m_aData['m_oCurrentValues']['id']))
{
$oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
}
else
{
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
}
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
{
// Because this is stored in a Javascript array, unused indexes
// are filled with null values
if ( ($sAttCode !== false) && ($value !== null))
if ( ($sAttCode !='id') && ($sAttCode !== false) && ($value !== null))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if (($oAttDef->IsLinkSet()) && ($value != '') )

View File

@@ -60,7 +60,7 @@ function GoToStep(iCurrentStep, iNextStep)
if (iNextStep > iCurrentStep)
{
// Check the values when moving forward
if (CheckFields('wizStep'+iCurrentStep))
if (CheckFields('wizStep'+iCurrentStep, true))
{
oCurrentStep.style.display = 'none';
ActivateStep(iNextStep);
@@ -120,7 +120,7 @@ function ActivateStep(iTargetStep)
// Store the result of the form validation... there may be several forms per page, beware
var oFormErrors = { err_form0: 0 };
function CheckFields(sFormId)
function CheckFields(sFormId, bDisplayAlert)
{
$('#'+sFormId+' :submit').attr('disable', 'disabled');
$('#'+sFormId+' :button[type=submit]').attr('disable', 'disabled');
@@ -136,7 +136,10 @@ function CheckFields(sFormId)
);
if(oFormErrors['err_'+sFormId] > 0)
{
alert('Please fill-in all mandatory fields before continuing.');
if (bDisplayAlert)
{
alert('Please fill-in all mandatory fields before continuing.');
}
$('#'+sFormId+' :submit').attr('disable', '');
$('#'+sFormId+' :button[type=submit]').attr('disable', '');
if (oFormErrors['input_'+sFormId] != null)
@@ -151,11 +154,11 @@ function ValidateField(sFieldId, sPattern, bMandatory, sFormId)
{
var bValid = true;
var currentVal = $('#'+sFieldId).val();
if (bMandatory && ((currentVal == '') || (currentVal == 0)))
if (bMandatory && ((currentVal == '') || (currentVal == 0) || (currentVal == '[]')))
{
bValid = false;
}
else if ((currentVal == '') || (currentVal == 0))
else if ((currentVal == '') || (currentVal == 0) || (currentVal == '[]'))
{
// An empty field is Ok...
bValid = true;
@@ -168,8 +171,8 @@ function ValidateField(sFieldId, sPattern, bMandatory, sFormId)
}
if (bValid)
{
// Visual feedback
$('#v_'+sFieldId).html('<img src="../images/validation_ok.png" />');
// Visual feedback - none when it's Ok
$('#v_'+sFieldId).html(''); //<img src="../images/validation_ok.png" />');
}
else
{
@@ -184,7 +187,7 @@ function ValidateField(sFieldId, sPattern, bMandatory, sFormId)
$('#v_'+sFieldId).html('<img src="../images/validation_error.png" />');
}
//console.log('Form: '+sFormId+' Validating field: '+sFieldId + ' current value: '+currentVal+' pattern: '+sPattern+' result: '+bValid );
return bValid;
return true; // Do not stop propagation ??
}
function UpdateDependentFields(aFieldNames)
@@ -197,6 +200,8 @@ function UpdateDependentFields(aFieldNames)
while(index < aFieldNames.length )
{
sAttCode = aFieldNames[index];
sFieldId = oWizardHelper.GetFieldId(sAttCode);
$('#v_'+sFieldId).html('<img src="../images/indicator.gif" />');
oWizardHelper.RequestAllowedValues(sAttCode);
index++;
}

View File

@@ -21,14 +21,17 @@ function LinksWidget(id, sLinkedClass, sExtKeyToMe, sExtKeyToRemote, aAttributes
this.Refresh = function ()
{
sLinks = JSON.stringify(this.aLinks);
if (this.aLinks.length == 0)
{
$('#'+this.id+'_values').empty();
$('#'+this.id).val(sLinks);
$('#'+this.id).trigger('validate');
}
else
{
sLinks = JSON.stringify(this.aLinks);
$('#'+this.id).val(sLinks);
$('#'+this.id).trigger('validate');
$('#'+this.id+'_values').load('ajax.render.php?operation=ui.linkswidget.linkedset&sclass='+this.sLinkedClass+'&sextkeytome='+this.sExtKeyToMe+'&sextkeytoremote='+this.sExtKeyToRemote+'&myid='+this.id,
{'sset' : sLinks}, function()
{
@@ -51,7 +54,15 @@ function LinksWidget(id, sLinkedClass, sExtKeyToMe, sExtKeyToRemote, aAttributes
}
this.aPreviousLinks = this.aLinks; // Save the list in case of cancellation
this.aLinks = new Array(); // rebuild the list of links from scratch
$('#LinkDlg_'+this.id).jqmShow();
if (oSelected.length > 0)
{
$('#LinkDlg_'+this.id).jqmShow();
}
else
{
this.Refresh();
$('#ac_add_'+this.id).attr('disabled', 'disabled');
}
}
this.OnCancel = function()

View File

@@ -47,7 +47,9 @@ function UpdateFileName(id, sNewFileName)
var sNewFileName = aPath[aPath.length-1];
$('#'+id).val(sNewFileName);
$('#'+id).trigger('validate');
$('#name_'+id).text(sNewFileName);
return true;
}
/**
* Reload a search form for the specified class
@@ -75,5 +77,4 @@ function ReloadSearchForm(divId, sClassName, sBaseClass)
$('#'+divId).unblock();
}
);
}
}

View File

@@ -23,6 +23,12 @@ function WizardHelper(sClass)
this.m_oData.m_iFieldsCount = count;
}
this.GetFieldId = function(sFieldName)
{
id = this.m_oData.m_oFieldsMap[sFieldName];
return id;
}
this.RequestDefaultValue = function (sFieldName)
{

View File

@@ -685,68 +685,16 @@ try
$oP->add_linked_script("../js/wizard.utils.js");
$oP->add_linked_script("../js/linkswidget.js");
$oP->add_linked_script("../js/jquery.blockUI.js");
$oWizard = new UIWizard($oP, $sClass, $sStateCode);
$oContext = new UserContext();
$aArgs = array_merge($oAppContext->GetAsHash(), utils::ReadParam('default', array()));
$sStateCode = $oWizard->GetTargetState(); // Will computes the default state if none was supplied
$sClassLabel = MetaModel::GetName($sClass);
$oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
$oP->add("<h1>".Dict::Format('UI:CreationTitle_Class', $sClassLabel)."</h1>\n");
if (!empty($sStateCode))
{
$sStateLabel = MetaModel::GetStateLabel($sClass, $sStateCode);
}
$aWizardSteps = $oWizard->GetWizardStructure();
// Display the structure of the wizard
$iStepIndex = 1;
$iMaxInputId = 0;
$aFieldsMap = array();
foreach($aWizardSteps['mandatory'] as $aSteps)
{
$oP->SetCurrentTab("Step $iStepIndex *");
$oWizard->DisplayWizardStep($aSteps, $iStepIndex, $iMaxInputId, $aFieldsMap, false /* no finish button */, $aArgs);
$iStepIndex++;
}
foreach($aWizardSteps['optional'] as $aSteps)
{
$oP->SetCurrentTab("Step $iStepIndex");
$oWizard->DisplayWizardStep($aSteps, $iStepIndex, $iMaxInputId, $aFieldsMap, true, $aArgs); // true means enable the finish button
$iStepIndex++;
}
$oWizard->DisplayFinalStep($iStepIndex, $aFieldsMap);
$oObj = null;
if (!empty($id))
{
$oObj = $oContext->GetObject($sClass, $id);
}
if (!is_object($oObj))
{
// new object or that can't be retrieved (corrupted id or object not allowed to this user)
$id = '';
$oObj = MetaModel::NewObject($sClass);
}
$oP->add("<script type=\"text/javascript\">
// Fill the map between the fields of the form and the attributes of the object\n");
$aNewFieldsMap = array();
foreach($aFieldsMap as $id => $sFieldCode)
{
$aNewFieldsMap[$sFieldCode] = $id;
}
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aNewFieldsMap);
$oP->add("
// Initializes the object once at the beginning of the page...
var oWizardHelper = new WizardHelper('$sClass');
oWizardHelper.SetFieldsMap($sJsonFieldsMap);
oWizardHelper.SetFieldsCount($iFieldsCount);
ActivateStep(1);
</script>\n");
$oP->add("<div class=\"wizContainer\">\n");
cmdbAbstractObject::DisplayCreationForm($oP, $sClass, null /* $oObjToClone */);
$oP->add("</div>\n");
break;
case 'apply_modify':
@@ -954,6 +902,91 @@ try
break;
case 'apply_new':
$sClass = utils::ReadPostedParam('class', '');
$sClassLabel = MetaModel::GetName($sClass);
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
if ( empty($sClass) ) // TO DO: check that the class name is valid !
{
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
}
if (!utils::IsTransactionValid($sTransactionId))
{
$oP->p("<strong>".Dict::S('UI:Error:ObjectAlreadyCreated')."</strong>\n");
}
else
{
$oObj = MetaModel::NewObject($sClass);
foreach(MetaModel::GetZListItems($sClass, 'details') as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsLinkSet())
{
// Link set, the data is a set of link objects, encoded in JSON
$aAttributes[$sAttCode] = trim(utils::ReadPostedParam("attr_$sAttCode", ''));
if (!empty($aAttributes[$sAttCode]))
{
$oLinkSet = WizardHelper::ParseJsonSet($oObj, $oAttDef->GetLinkedClass(), $oAttDef->GetExtKeyToMe(), $aAttributes[$sAttCode]);
$oObj->Set($sAttCode, $oLinkSet);
// TO DO: detect a real modification, for now always update !!
}
}
else if (!$oAttDef->IsExternalField())
{
$rawValue = utils::ReadPostedParam("attr_$sAttCode", null);
if (!is_null($rawValue))
{
$aAttributes[$sAttCode] = trim($rawValue);
$previousValue = $oObj->Get($sAttCode);
if ($previousValue !== $aAttributes[$sAttCode])
{
$oObj->Set($sAttCode, $aAttributes[$sAttCode]);
}
}
}
else if ($oAttDef->IsWritable())
{
$iFlags = $oObj->GetAttributeFlags($sAttCode);
if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY))
{
// Non-visible, or read-only attribute, do nothing
}
else if ($oAttDef->GetEditClass() == 'Document')
{
// There should be an uploaded file with the named attr_<attCode>
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
if (!$oDocument->IsEmpty())
{
// A new file has been uploaded
$oObj->Set($sAttCode, $oDocument);
}
}
}
}
}
if (is_object($oObj))
{
$sClass = get_class($oObj);
$sClassLabel = MetaModel::GetName($sClass);
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
if (UserRights::GetUser() != UserRights::GetRealUser())
{
$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);
$oP->set_title(Dict::S('UI:PageTitle:ObjectCreated'));
$oP->add("<h1>".Dict::Format('UI:Title:Object_Of_Class_Created', $oObj->GetName(), $sClassLabel)."</h1>\n");
$oObj->DisplayDetails($oP);
}
break;
case 'wizard_apply_new':
$sJson = utils::ReadPostedParam('json_obj', '');
$oWizardHelper = WizardHelper::FromJSON($sJson);
@@ -1020,14 +1053,14 @@ try
$oP->add_linked_script("../js/jquery.blockUI.js");
$oP->add("<div class=\"page_header\">\n");
$oP->add("<h1>$sActionLabel - <span class=\"hilite\">{$oObj->GetName()}</span></h1>\n");
$oP->set_title($sActionLabel);
$oP->add("</div>\n");
$oObj->DisplayBareDetails($oP);
$aTargetState = $aTargetStates[$sTargetState];
$aExpectedAttributes = $aTargetState['attribute_list'];
$oP->add("<div class=\"wizHeader\">\n");
$oP->add("<h1>$sActionDetails</h1>\n");
$oP->add("<div class=\"wizContainer\">\n");
$oP->add("<form method=\"post\">\n");
$oP->add("<form id=\"apply_stimulus\" method=\"post\" onSubmit=\"return CheckFields('apply_stimulus', true);\">\n");
$aDetails = array();
$iFieldIndex = 0;
$aFieldsMap = array();
@@ -1049,17 +1082,17 @@ try
}
}
$oP->details($aDetails);
$oP->add("<input type=\"hidden\" name=\"id\" value=\"$id\">\n");
$oP->add("<input type=\"hidden\" name=\"id\" value=\"$id\" id=\"id\">\n");
$aFieldsMap['id'] = 'id';
$oP->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n");
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"apply_stimulus\">\n");
$oP->add("<input type=\"hidden\" name=\"stimulus\" value=\"$sStimulus\">\n");
$oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">\n");
$oP->add($oAppContext->GetForForm());
$oP->add("<button type=\"button\" class=\"action\" onClick=\"goBack()\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oP->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', $id)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oP->add("<button type=\"submit\" class=\"action\"><span>$sActionLabel</span></button>\n");
$oP->add("</form>\n");
$oP->add("</div>\n");
$oP->add("</div>\n");
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
@@ -1119,7 +1152,7 @@ EOF
$aDetails = array();
foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
{
if (($iExpectCode & OPT_ATT_MUSTCHANGE) || ($oObj->Get($sAttCode) == '') )
if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') )
{
$paramValue = utils::ReadPostedParam("attr_$sAttCode", '');
$oObj->Set($sAttCode, $paramValue);