Bläddra i källkod

Added the validation of mandatory form fields before submitting the creation / modification / clone forms.

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@140 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 15 år sedan
förälder
incheckning
e71a308958

+ 49 - 12
application/cmdbabstract.class.inc.php

@@ -596,7 +596,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 		return $sHtml;
 	}
 	
-	public static function GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value = '', $sDisplayValue = '', $iId = '', $sNameSuffix = '')
+	public static function GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value = '', $sDisplayValue = '', $iId = '', $sNameSuffix = '', $iFlags = 0)
 	{
 		static $iInputId = 0;
 		if (!empty($iId))
@@ -607,20 +607,29 @@ abstract class cmdbAbstractObject extends CMDBObject
 		{
 			$iInputId++;
 		}
+
 		if (!$oAttDef->IsExternalField())
 		{
+			$aCSSClasses = array();
+			if ( (!$oAttDef->IsNullAllowed()) || ($iFlags & OPT_ATT_MANDATORY))
+			{
+				$aCSSClasses[] = 'mandatory';
+			}
+			$sCSSClasses = self::GetCSSClasses($aCSSClasses);
 			switch($oAttDef->GetEditClass())
 			{
 				case 'Date':
-				$sHTMLValue = "<input type=\"text\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\" class=\"date-pick\"/>";
+				$aCSSClasses[] = 'date-pick';
+				$sCSSClasses = self::GetCSSClasses($aCSSClasses);
+				$sHTMLValue = "<input type=\"text\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses}/>";
 				break;
 				
 				case 'Password':
-				$sHTMLValue = "<input type=\"password\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"/>";
+				$sHTMLValue = "<input type=\"password\" size=\"20\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses}/>";
 				break;
 				
 				case 'Text':
-					$sHTMLValue = "<textarea name=\"attr_{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iInputId\">$value</textarea>";
+					$sHTMLValue = "<textarea name=\"attr_{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iInputId\"{$sCSSClasses}>$value</textarea>";
 				break;
 	
 				case 'List':
@@ -637,13 +646,13 @@ abstract class cmdbAbstractObject extends CMDBObject
 						//Enum field or external key, display a combo
 						if (count($aAllowedValues) == 0)
 						{
-							$sHTMLValue = "<input type=\"text\" size=\"70\" value=\"\" name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iInputId\"/>";
+							$sHTMLValue = "<input type=\"text\" size=\"70\" value=\"\" name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iInputId\"{$sCSSClasses}/>";
 						}
 						else if (count($aAllowedValues) > 50)
 						{
 							// too many choices, use an autocomplete
 							// The input for the auto complete
-							$sHTMLValue = "<input type=\"text\" id=\"label_$iInputId\" size=\"50\" name=\"\" value=\"$sDisplayValue\" />";
+							$sHTMLValue = "<input type=\"text\" id=\"label_$iInputId\" size=\"50\" name=\"\" value=\"$sDisplayValue\"{$sCSSClasses}/>";
 							// 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', { minChars:3, onItemSelect:selectItem, onFindValue:findValue, formatItem:formatItem, autoFill:true, keyHolder:'#$iInputId', extraParams:{operation:'autocomplete', sclass:'$sClass',attCode:'".$sAttCode."'}});");
@@ -651,7 +660,8 @@ abstract class cmdbAbstractObject extends CMDBObject
 						else
 						{
 							// Few choices, use a normal 'select'
-							$sHTMLValue = "<select name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iInputId\">\n";
+							$sHTMLValue = "<select name=\"attr_{$sAttCode}{$sNameSuffix}\" id=\"$iInputId\"{$sCSSClasses}>\n";
+							$sHTMLValue .= "<option value=\"0\">-- select one --</option>\n";
 							foreach($aAllowedValues as $key => $display_value)
 							{
 								$sSelected = ($value == $key) ? ' selected' : '';
@@ -662,7 +672,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 					}
 					else
 					{
-						$sHTMLValue = "<input type=\"text\" size=\"50\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\">";
+						$sHTMLValue = "<input type=\"text\" size=\"50\" name=\"attr_{$sAttCode}{$sNameSuffix}\" value=\"$value\" id=\"$iInputId\"{$sCSSClasses}>";
 					}
 					break;
 			}
@@ -672,11 +682,13 @@ abstract class cmdbAbstractObject extends CMDBObject
 	
 	public function DisplayModifyForm(web_page $oPage)
 	{
+		static $iFormId = 0;
+		$iFormId++;
 		$oAppContext = new ApplicationContext();
 		$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
 		$iKey = $this->GetKey();
 		$aDetails = array();
-		$oPage->add("<form method=\"post\">\n");
+		$oPage->add("<form id=\"form_{$iFormId}\" method=\"post\" onSubmit=\"return CheckMandatoryFields('form_{$iFormId}')\">\n");
 		foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
 		{
 			if ('finalclass' == $sAttCode) // finalclass is a reserved word, hardcoded !
@@ -707,7 +719,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 					{
 						$sValue = $this->Get($sAttCode);
 						$sDisplayValue = $this->GetDisplayValue($sAttCode);
-						$sHTMLValue = self::GetFormElementForField($oPage, get_class($this), $sAttCode, $oAttDef, $sValue, $sDisplayValue);
+						$sHTMLValue = self::GetFormElementForField($oPage, get_class($this), $sAttCode, $oAttDef, $sValue, $sDisplayValue, '', '', $iFlags);
 					}
 					$aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
 				}
@@ -726,11 +738,24 @@ abstract class cmdbAbstractObject extends CMDBObject
 	
 	public static function DisplayCreationForm(web_page $oPage, $sClass, $oObjectToClone = null)
 	{
+		static $iCreationFormId = 0;
+
+		$iCreationFormId++;
 		$oAppContext = new ApplicationContext();
 		$aDetails = array();
 		$sOperation = ($oObjectToClone == null) ? 'apply_new' : 'apply_clone';
 		$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($oObjectToClone));
-		$oPage->add("<form method=\"post\">\n");
+		$oPage->add("<form id=\"creation_form_{$iCreationFormId}\" method=\"post\" onSubmit=\"return CheckMandatoryFields('creation_form_{$iCreationFormId}')\">\n");
+		$aStates = MetaModel::EnumStates($sClass);
+		if ($oObjectToClone == null)
+		{
+			$sTargetState = MetaModel::GetDefaultState($sClass);
+		}
+		else
+		{
+			$sTargetState = $oObjectToClone->GetState();
+		}
+
 		foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
 		{
 			if ('finalclass' == $sAttCode) // finalclass is a reserved word, hardcoded !
@@ -747,7 +772,9 @@ abstract class cmdbAbstractObject extends CMDBObject
 			{
 				$sValue = ($oObjectToClone == null) ? '' : $oObjectToClone->Get($sAttCode);
 				$sDisplayValue = ($oObjectToClone == null) ? '' : $oObjectToClone->GetDisplayValue($sAttCode);
-				$sHTMLValue = self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue);
+				$iOptions = isset($aStates[$sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$sTargetState]['attribute_list'][$sAttCode] : 0;
+				
+				$sHTMLValue = self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, '', '', $iOptions);
 				$aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
 			}
 		}
@@ -764,5 +791,15 @@ abstract class cmdbAbstractObject extends CMDBObject
 		$oPage->add("<button type=\"submit\" class=\"action\"><span>Apply</span></button>\n");
 		$oPage->add("</form>\n");
 	}
+
+	protected static function GetCSSClasses($aCSSClasses)
+	{
+		$sCSSClasses = '';
+		if (!empty($aCSSClasses))
+		{
+			$sCSSClasses = ' class="'.implode(' ', $aCSSClasses).'" ';
+		}
+		return $sCSSClasses;
+	}
 }
 ?>

+ 1 - 1
application/uiwizard.class.inc.php

@@ -56,7 +56,7 @@ class UIWizard
 				
 				$sFieldFlag = ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) ? ' <span class="hilite">*</span>' : '';
 				$oDefaultValuesSet = $oAttDef->GetDefaultValue(); // @@@ TO DO: get the object's current value if the object exists
-				$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId");
+				$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions);
 				$aFieldsMap[$iMaxInputId] = $sAttCode;
 				$aDetails[] = array('label' => $oAttDef->GetLabel().$sFieldFlag, 'value' => "<div id=\"field_$iMaxInputId\">$sHTMLValue</div>");
 				if ($oAttDef->GetValuesDef() != null)

+ 1 - 0
core/attributedef.class.inc.php

@@ -107,6 +107,7 @@ abstract class AttributeDefinition
 	public function IsExternalKey($iType = EXTKEY_RELATIVE) {return false;} 
 	public function IsExternalField() {return false;} 
 	public function IsWritable() {return false;} 
+	public function IsNullAllowed() {return true;} 
 	public function GetCode() {return $this->m_sCode;} 
 	public function GetLabel() {return $this->Get("label");} 
 	public function GetDescription() {return $this->Get("description");} 

+ 3 - 0
css/light-grey.css

@@ -660,3 +660,6 @@ div.HRDrawer {
 	nopadding-right: 1em;
 	margin-top: 0;
 }
+.mandatory {
+	border: 1px solid #f00;
+}

+ 41 - 2
js/forms-json-utils.js

@@ -57,8 +57,11 @@ function ReloadObjectFromServer(sJSON)
 function GoToStep(iCurrentStep, iNextStep)
 {
 	var oCurrentStep = document.getElementById('wizStep'+iCurrentStep);
-	oCurrentStep.style.display = 'none';
-	ActivateStep(iNextStep);
+	if (CheckMandatoryFields('wizStep'+iCurrentStep))
+	{
+		oCurrentStep.style.display = 'none';
+		ActivateStep(iNextStep);
+	}
 }
 
 function ActivateStep(iTargetStep)
@@ -104,3 +107,39 @@ function AjaxGetDefaultValue(oObj, sClass, sAttCode, iFieldId)
 		);
 	}
 }
+
+function CheckMandatoryFields(sFormId)
+{
+	$('#'+sFormId+' :submit').attr('disable', 'disabled');
+	$('#'+sFormId+' :button[type=submit]').attr('disable', 'disabled');
+	firstErrorId = '';
+	
+	var iErrorsCount = 0;
+	$('#'+sFormId+' :input.mandatory').each( function() {
+		if (( this.value == '') || (this.value == 0))
+		{
+			this.style.background = '#fcc';
+			iErrorsCount++;
+			if (iErrorsCount == 1)
+			{
+				firstErrorId = this.id;
+			}
+		}
+		else
+		{
+			this.style.background = '#fff';
+		}
+	}
+	);
+	if(iErrorsCount > 0)
+	{
+		alert('Please fill-in all mandatory fields before continuing.');
+		$('#'+sFormId+' :submit').attr('disable', '');
+		$('#'+sFormId+' :button[type=submit]').attr('disable', '');
+		if (firstErrorId != '')
+		{
+			$('#'+firstErrorId).focus();
+		}
+	}
+	return(iErrorsCount == 0);
+}

+ 13 - 2
pages/UI.php

@@ -278,9 +278,20 @@ switch($operation)
 		$bIsReadAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_READ, $oSet) == UR_ALLOWED_YES);
 		if( ($oObjToClone != null) && ($bIsModifiedAllowed) && ($bIsReadAllowed))
 		{
+			$oP->add_linked_script("../js/json.js");
+			$oP->add_linked_script("../js/forms-json-utils.js");
+			$oP->add_linked_script("../js/wizardhelper.js");
+			$oP->add_linked_script("../js/wizard.utils.js");
+			$oP->add_linked_script("../js/linkswidget.js");
+			$oP->add_linked_script("../js/jquery.blockUI.js");
 			$oP->set_title("iTop - ".$oObjToClone->GetName()." - $sClassLabel clone");
-			$oP->add("<h1>".$oObjToClone->GetName()." - $sClassLabel clone</h1>\n");
+			$oP->add("<div class=\"page_header\">\n");
+			$oP->add("<h1>Clone of $sClassLabel: <span class=\"hilite\">".$oObjToClone->GetName()."</span></h1>\n");
+			$oP->add("</div>\n");
+
+			$oP->add("<div class=\"wizContainer\">\n");
 			cmdbAbstractObject::DisplayCreationForm($oP, $sClass, $oObjToClone);
+			$oP->add("</div>\n");
 		}
 		else
 		{
@@ -611,7 +622,7 @@ switch($operation)
 					{
 						$aAttributesDef = MetaModel::ListAttributeDefs($sClass);
 						$oAttDef = $aAttributesDef[$sAttCode];
-						$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetDisplayValue($sAttCode));
+						$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetDisplayValue($sAttCode), '', '', $iExpectCode);
 						$aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
 					}
 				}