Custom fields: alpha version.

SVN:trunk[3943]
This commit is contained in:
Romain Quetiez
2016-03-10 16:55:13 +00:00
parent 67c92ab946
commit e6887ab317
19 changed files with 1047 additions and 197 deletions

View File

@@ -44,6 +44,7 @@ require_once(APPROOT.'/application/ui.passwordwidget.class.inc.php');
require_once(APPROOT.'/application/ui.extkeywidget.class.inc.php');
require_once(APPROOT.'/application/ui.htmleditorwidget.class.inc.php');
require_once(APPROOT.'/application/datatable.class.inc.php');
require_once(APPROOT.'/sources/renderer/console/consoleformrenderer.class.inc.php');
abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
@@ -1712,7 +1713,8 @@ EOF
{
$bMandatory = 'true';
}
$sValidationField = "<span class=\"form_validation\" id=\"v_{$iId}\"></span>";
$sValidationSpan = "<span class=\"form_validation\" id=\"v_{$iId}\"></span>";
$sReloadSpan = "<span class=\"field_status\" id=\"fstatus_{$iId}\"></span>";
$sHelpText = htmlentities($oAttDef->GetHelpOnEdition(), ENT_QUOTES, 'UTF-8');
$aEventsList = array();
switch($oAttDef->GetEditClass())
@@ -1725,7 +1727,7 @@ EOF
{
$sDisplayValue = date($oAttDef->GetDateFormat());
}
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"12\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationField}";
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"12\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
break;
case 'DateTime':
@@ -1736,7 +1738,7 @@ EOF
{
$sDisplayValue = date($oAttDef->GetDateFormat());
}
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationField}";
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
break;
case 'Duration':
@@ -1752,7 +1754,7 @@ EOF
$sMinutes = "<input title=\"$sHelpText\" type=\"text\" style=\"text-align:right\" size=\"2\" name=\"attr_{$sFieldPrefix}{$sAttCode}[m]{$sNameSuffix}\" value=\"{$aVal['minutes']}\" id=\"{$iId}_m\"/>";
$sSeconds = "<input title=\"$sHelpText\" type=\"text\" style=\"text-align:right\" size=\"2\" name=\"attr_{$sFieldPrefix}{$sAttCode}[s]{$sNameSuffix}\" value=\"{$aVal['seconds']}\" id=\"{$iId}_s\"/>";
$sHidden = "<input type=\"hidden\" id=\"{$iId}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\"/>";
$sHTMLValue = Dict::Format('UI:DurationForm_Days_Hours_Minutes_Seconds', $sDays, $sHours, $sMinutes, $sSeconds).$sHidden."&nbsp;".$sValidationField;
$sHTMLValue = Dict::Format('UI:DurationForm_Days_Hours_Minutes_Seconds', $sDays, $sHours, $sMinutes, $sSeconds).$sHidden."&nbsp;".$sValidationSpan.$sReloadSpan;
$oPage->add_ready_script("$('#{$iId}').bind('update', function(evt, sFormId) { return ToggleDurationField('$iId'); });");
break;
@@ -1760,7 +1762,7 @@ EOF
$aEventsList[] ='validate';
$aEventsList[] ='keyup';
$aEventsList[] ='change';
$sHTMLValue = "<input title=\"$sHelpText\" type=\"password\" size=\"30\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationField}";
$sHTMLValue = "<input title=\"$sHelpText\" type=\"password\" size=\"30\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
break;
case 'OQLExpression':
@@ -1799,7 +1801,7 @@ EOF
$sAdditionalStuff = "";
}
// Ok, the text area is drawn here
$sHTMLValue = "<table><tr><td><textarea class=\"resizable\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\" $sStyle>".htmlentities($sEditValue, ENT_QUOTES, 'UTF-8')."</textarea>$sAdditionalStuff</td><td>{$sValidationField}</td></tr></table>";
$sHTMLValue = "<table><tr><td><textarea class=\"resizable\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\" $sStyle>".htmlentities($sEditValue, ENT_QUOTES, 'UTF-8')."</textarea>$sAdditionalStuff</td><td>{$sValidationSpan}{$sReloadSpan}</td></tr></table>";
break;
@@ -1825,12 +1827,12 @@ EOF
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */, array('AttributeText', 'RenderWikiHtml')) : '';
$iEntriesCount = is_object($value) ? count($value->GetIndex()) : 0;
$sHidden = "<input type=\"hidden\" id=\"{$iId}_count\" value=\"$iEntriesCount\"/>"; // To know how many entries the case log already contains
$sHTMLValue = "<div class=\"caselog\" $sStyle><table style=\"width:100%;\"><tr><td>$sHeader<textarea class=\"htmlEditor\" style=\"border:0;width:100%\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">".htmlentities($sEditValue, ENT_QUOTES, 'UTF-8')."</textarea>$sPreviousLog</td><td>{$sValidationField}</td></tr></table>$sHidden</div>";
$sHTMLValue = "<div class=\"caselog\" $sStyle><table style=\"width:100%;\"><tr><td>$sHeader<textarea class=\"htmlEditor\" style=\"border:0;width:100%\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">".htmlentities($sEditValue, ENT_QUOTES, 'UTF-8')."</textarea>$sPreviousLog</td><td>{$sValidationSpan}{$sReloadSpan}</td></tr></table>$sHidden</div>";
$oPage->add_ready_script("$('#$iId').bind('keyup change validate', function(evt, sFormId) { return ValidateCaseLogField('$iId', $bMandatory, sFormId) } );"); // Custom validation function
break;
case 'HTML':
$oWidget = new UIHTMLEditorWidget($iId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $value, $bMandatory);
$oWidget = new UIHTMLEditorWidget($iId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationSpan.$sReloadSpan, $value, $bMandatory);
$sHTMLValue = $oWidget->Display($oPage, $aArgs);
break;
@@ -1862,7 +1864,7 @@ EOF
$sHTMLValue = "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"$iMaxFileSize\" />\n";
$sHTMLValue .= "<input name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[filename]\" type=\"hidden\" id=\"$iId\" \" value=\"".htmlentities($sFileName, ENT_QUOTES, 'UTF-8')."\"/>\n";
$sHTMLValue .= "<span id=\"name_$iInputId\">$sFileName</span><br/>\n";
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[fcontents]\" type=\"file\" id=\"file_$iId\" onChange=\"UpdateFileName('$iId', this.value)\"/>&nbsp;{$sValidationField}\n";
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[fcontents]\" type=\"file\" id=\"file_$iId\" onChange=\"UpdateFileName('$iId', this.value)\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}\n";
break;
case 'StopWatch':
@@ -1902,12 +1904,59 @@ EOF
$sHTMLValue .= $oAttDef->GetDisplayForm($value, $oPage, true);
$sHTMLValue .= '</div>';
$sHTMLValue .= '</td>';
$sHTMLValue .= '<td>'.$sValidationField.'</td>';
$sHTMLValue .= '<td>'.$sValidationSpan.$sReloadSpan.'</td>';
$sHTMLValue .= '</tr>';
$sHTMLValue .= '</table>';
$oPage->add_ready_script("$('#$iId :input').bind('keyup change validate', function(evt, sFormId) { return ValidateRedundancySettings('$iId',sFormId); } );"); // Custom validation function
break;
case 'CustomFields':
$sHTMLValue = '<table>';
$sHTMLValue .= '<tr>';
$sHTMLValue .= '<td>';
$sHTMLValue .= '<div id="'.$iId.'_console_form">';
$sHTMLValue .= '<div id="'.$iId.'_field_set">';
$sHTMLValue .= '</div>';
$sHTMLValue .= '</div>';
$sHTMLValue .= '</td>';
$sHTMLValue .= '<td>'.$sReloadSpan.'</td>'; // No validation span for this one: it does handle its own validation!
$sHTMLValue .= '</tr>';
$sHTMLValue .= '</table>';
$sHTMLValue .= "<input name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" type=\"hidden\" id=\"$iId\" value=\"\"/>\n";
$oForm = $value->GetForm($sFormPrefix);
$oRenderer = new \Combodo\iTop\Renderer\Console\ConsoleFormRenderer($oForm);
$aRenderRes = $oRenderer->Render();
$aFormHandlerOptions = array(
'wizard_helper_var_name' => 'oWizardHelper'.$sFormPrefix,
'custom_field_attcode' => $sAttCode
);
$sFormHandlerOptions = json_encode($aFormHandlerOptions);
$aFieldSetOptions = array(
'field_identifier_attr' => 'data-field-id', // convention: fields are rendered into a div and are identified by this attribute
'fields_list' => $aRenderRes,
'fields_impacts' => $oForm->GetFieldsImpacts(),
'form_path' => $oForm->GetId()
);
$sFieldSetOptions = json_encode($aFieldSetOptions);
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/form_handler.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/console_form_handler.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_set.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/form_field.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/subform_field.js');
$oPage->add_ready_script("$('#{$iId}_console_form').console_form_handler($sFormHandlerOptions);");
$oPage->add_ready_script("$('#{$iId}_field_set').field_set($sFieldSetOptions);");
$oPage->add_ready_script("$('#{$iId}_console_form').console_form_handler('alignColumns');");
$oPage->add_ready_script("$('#{$iId}_console_form').console_form_handler('option', 'field_set', $('#{$iId}_field_set'));");
// field_change must be processed to refresh the hidden value at anytime
$oPage->add_ready_script("$('#{$iId}_console_form .field_set').bind('field_change', function() { $('#{$iId}').val(JSON.stringify($('#{$iId}_field_set').triggerHandler('get_current_values'))); });");
// update_value is triggered when preparing the wizard helper object for ajax calls
$oPage->add_ready_script("$('#{$iId}').bind('update_value', function() { $(this).val(JSON.stringify($('#{$iId}_field_set').triggerHandler('get_current_values'))); });");
// validate is triggered by CheckFields, on all the input fields, once at page init and once before submitting the form
$oPage->add_ready_script("$('#{$iId}').bind('validate', function(evt, sFormId) { return ValidateCustomFields('$iId', sFormId) } );"); // Custom validation function
break;
case 'String':
default:
$aEventsList[] ='validate';
@@ -1925,7 +1974,7 @@ EOF
case 'radio_vertical':
$sHTMLValue = '';
$bVertical = ($sDisplayStyle != 'radio_horizontal');
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $iId, "attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}", $bMandatory, $bVertical, $sValidationField);
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $iId, "attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}", $bMandatory, $bVertical, $sValidationSpan.$sReloadSpan);
$aEventsList[] ='change';
break;
@@ -1946,13 +1995,13 @@ EOF
}
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
}
$sHTMLValue .= "</select>&nbsp;{$sValidationField}\n";
$sHTMLValue .= "</select>&nbsp;{$sValidationSpan}{$sReloadSpan}\n";
$aEventsList[] ='change';
}
}
else
{
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" maxlength=\"$iFieldSize\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationField}";
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" maxlength=\"$iFieldSize\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
$aEventsList[] ='keyup';
$aEventsList[] ='change';
}
@@ -2977,6 +3026,10 @@ EOF
$this->Set($sAttCode, $iValue);
}
}
elseif ($oAttDef->GetEditClass() == 'CustomFields')
{
$this->Set($sAttCode, $value);
}
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() &&
(($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE) || ($oAttDef->GetEditMode() == LINKSET_EDITMODE_ADDREMOVE)))
{
@@ -3089,6 +3142,10 @@ EOF
{
$value = $oAttDef->ReadValueFromPostedForm($sFormPrefix);
}
elseif ($oAttDef->GetEditClass() == 'CustomFields')
{
$value = $oAttDef->ReadValueFromPostedForm($this, $sFormPrefix);
}
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() &&
(($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE) || ($oAttDef->GetEditMode() == LINKSET_EDITMODE_ADDREMOVE)) )
{

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -54,7 +54,7 @@
* | | +--------+ +-----+ | |
* | +--------------------------------------------+ |
* +------------------------------------------------+
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -149,7 +149,7 @@ class UIExtKeyWidget
case 'radio':
case 'radio_horizontal':
case 'radio_vertical':
$sValidationField = "<span id=\"v_{$this->iId}\"></span>";
$sValidationField = "<span id=\"v_{$this->iId}\"></span><span id=\"fstatus_{$this->iId}\"></span>";
$sHTMLValue = '';
$bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false;
@@ -305,7 +305,7 @@ EOF
}
if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
{
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span><span id=\"fstatus_{$this->iId}\"></span>";
}
$sHTMLValue .= "</span>"; // end of no wrap
return $sHTMLValue;

View File

@@ -58,7 +58,7 @@ class UIPasswordWidget
$sConfirmPasswordValue = $aPasswordValues ? $aPasswordValues['confirm'] : '*****';
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
$sHtmlValue = '';
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><span id="fstatus_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';

View File

@@ -31,6 +31,9 @@ require_once('ormstopwatch.class.inc.php');
require_once('ormpassword.class.inc.php');
require_once('ormcaselog.class.inc.php');
require_once('htmlsanitizer.class.inc.php');
require_once(APPROOT.'sources/autoload.php');
require_once('customfieldshandler.class.inc.php');
require_once('ormcustomfieldsvalue.class.inc.php');
/**
* MissingColumnException - sent if an attribute is being created but the column is missing in the row
@@ -178,7 +181,6 @@ abstract class AttributeDefinition
private function ConsistencyCheck()
{
// Check that any mandatory param has been specified
//
$aExpectedParams = $this->ListExpectedParams();
@@ -192,7 +194,18 @@ abstract class AttributeDefinition
throw new Exception("ERROR missing parameter '$sParamName' in ".get_class($this)." declaration for class $sTargetClass ($sCodeInfo)");
}
}
}
}
/**
* Check the validity of the given value
* @param DBObject $oHostObject
* @param string An error if any, null otherwise
*/
public function CheckValue(DBObject $oHostObject, $value)
{
// todo: factorize here the cases implemented into DBObject
return true;
}
// table, key field, name field
public function ListDBJoins()
@@ -212,8 +225,9 @@ abstract class AttributeDefinition
public function IsExternalField() {return false;}
public function IsWritable() {return false;}
public function LoadInObject() {return true;}
public function LoadFromDB() {return true;}
public function AlwaysLoadInTables() {return $this->GetOptional('always_load_in_tables', false);}
public function GetValue($oHostObject){return null;} // must return the value if LoadInObject returns false
public function GetValue($oHostObject, $bOriginal = false){return null;} // must return the value if LoadInObject returns false
public function IsNullAllowed() {return true;}
public function GetCode() {return $this->m_sCode;}
public function GetMirrorLinkAttribute() {return null;}
@@ -417,7 +431,7 @@ abstract class AttributeDefinition
return call_user_func($sComputeFunc);
}
abstract public function GetDefaultValue();
abstract public function GetDefaultValue(DBObject $oHostObject = null);
//
// To be overloaded in subclasses
@@ -503,7 +517,7 @@ abstract class AttributeDefinition
/**
* List the available verbs for 'GetForTemplate'
*/
public static function EnumTemplateVerbs()
public function EnumTemplateVerbs()
{
return array(
'' => 'Plain text (unlocalized) representation',
@@ -692,21 +706,9 @@ class AttributeLinkedSet extends AttributeDefinition
public function GetValuesDef() {return $this->Get("allowed_values");}
public function GetPrerequisiteAttributes($sClass = null) {return $this->Get("depends_on");}
public function GetDefaultValue($aArgs = array())
public function GetDefaultValue(DBObject $oHostObject = null)
{
// Note: so far, this feature is a prototype,
// later, the argument 'this' should always be present in the arguments
//
if (($this->IsParam('default_value')) && array_key_exists('this', $aArgs))
{
$aValues = $this->Get('default_value')->GetValues($aArgs);
$oSet = DBObjectSet::FromArray($this->Get('linked_class'), $aValues);
return $oSet;
}
else
{
return DBObjectSet::FromScratch($this->Get('linked_class'));
}
return DBObjectSet::FromScratch($this->Get('linked_class'));
}
public function GetTrackingLevel()
@@ -849,7 +851,7 @@ class AttributeLinkedSet extends AttributeDefinition
/**
* List the available verbs for 'GetForTemplate'
*/
public static function EnumTemplateVerbs()
public function EnumTemplateVerbs()
{
return array(
'' => 'Plain text (unlocalized) representation',
@@ -1295,7 +1297,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
public function IsScalar() {return true;}
public function IsWritable() {return true;}
public function GetSQLExpr() {return $this->Get("sql");}
public function GetDefaultValue() {return $this->MakeRealValue("", null);}
public function GetDefaultValue(DBObject $oHostObject = null) {return $this->MakeRealValue("", $oHostObject);}
public function IsNullAllowed() {return false;}
//
@@ -1368,7 +1370,7 @@ class AttributeDBField extends AttributeDBFieldVoid
{
return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed"));
}
public function GetDefaultValue() {return $this->MakeRealValue($this->Get("default_value"), null);}
public function GetDefaultValue(DBObject $oHostObject = null) {return $this->MakeRealValue($this->Get("default_value"), $oHostObject);}
public function IsNullAllowed() {return $this->Get("is_null_allowed");}
}
@@ -1480,7 +1482,7 @@ class AttributeObjectKey extends AttributeDBFieldVoid
public function GetEditClass() {return "String";}
protected function GetSQLCol($bFullSpec = false) {return "INT(11)".($bFullSpec ? " DEFAULT 0" : "");}
public function GetDefaultValue() {return 0;}
public function GetDefaultValue(DBObject $oHostObject = null) {return 0;}
public function IsNullAllowed()
{
return $this->Get("is_null_allowed");
@@ -1854,9 +1856,9 @@ class AttributeClass extends AttributeString
parent::__construct($sCode, $aParams);
}
public function GetDefaultValue()
public function GetDefaultValue(DBObject $oHostObject = null)
{
$sDefault = parent::GetDefaultValue();
$sDefault = parent::GetDefaultValue($oHostObject);
if (!$this->IsNullAllowed() && $this->IsNull($sDefault))
{
// For this kind of attribute specifying null as default value
@@ -1953,7 +1955,7 @@ class AttributeFinalClass extends AttributeString
{
$this->m_sValue = $sValue;
}
public function GetDefaultValue()
public function GetDefaultValue(DBObject $oHostObject = null)
{
return $this->m_sValue;
}
@@ -2312,7 +2314,7 @@ class AttributeText extends AttributeString
{
$sClass = $aMatches[1];
$sName = $aMatches[2];
if (MetaModel::IsValidClass($sClass))
{
$sClassLabel = MetaModel::GetName($sClass);
@@ -2357,7 +2359,7 @@ class AttributeText extends AttributeString
{
$sClassLabel = $aMatches[1];
$sName = $aMatches[2];
if (!MetaModel::IsValidClass($sClassLabel))
{
$sClass = MetaModel::GetClassFromLabel($sClassLabel);
@@ -2548,8 +2550,8 @@ class AttributeCaseLog extends AttributeLongText
return (string) $value;
}
}
public function GetDefaultValue() {return new ormCaseLog();}
public function GetDefaultValue(DBObject $oHostObject = null) {return new ormCaseLog();}
public function Equals($val1, $val2) {return ($val1->GetText() == $val2->GetText());}
@@ -2719,7 +2721,7 @@ class AttributeCaseLog extends AttributeLongText
/**
* List the available verbs for 'GetForTemplate'
*/
public static function EnumTemplateVerbs()
public function EnumTemplateVerbs()
{
return array(
'' => 'Plain text representation of all the log entries',
@@ -3372,9 +3374,9 @@ class AttributeDateTime extends AttributeDBField
// This has been done at the time when itop was using TIMESTAMP columns,
// now that iTop is using DATETIME columns, it seems possible to have IsNullAllowed returning false... later when this is needed
public function IsNullAllowed() {return true;}
public function GetDefaultValue()
public function GetDefaultValue(DBObject $oHostObject = null)
{
$default = parent::GetDefaultValue();
$default = parent::GetDefaultValue($oHostObject);
if (!parent::IsNullAllowed())
{
@@ -3769,7 +3771,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
public function GetDisplayStyle() { return $this->GetOptional('display_style', 'select'); }
public function GetDefaultValue() {return 0;}
public function GetDefaultValue(DBObject $oHostObject = null) {return 0;}
public function IsNullAllowed()
{
if (MetaModel::GetConfig()->Get('disable_mandatory_ext_keys'))
@@ -4163,10 +4165,10 @@ class AttributeExternalField extends AttributeDefinition
return $oExtAttDef->GetSQLExpr();
}
public function GetDefaultValue()
public function GetDefaultValue(DBObject $oHostObject = null)
{
$oExtAttDef = $this->GetExtAttDef();
return $oExtAttDef->GetDefaultValue();
return $oExtAttDef->GetDefaultValue();
}
public function IsNullAllowed()
{
@@ -4308,8 +4310,8 @@ class AttributeBlob extends AttributeDefinition
public function IsDirectField() {return true;}
public function IsScalar() {return true;}
public function IsWritable() {return true;}
public function GetDefaultValue() {return "";}
public function IsNullAllowed() {return $this->GetOptional("is_null_allowed", false);}
public function GetDefaultValue(DBObject $oHostObject = null) {return "";}
public function IsNullAllowed(DBObject $oHostObject = null) {return $this->GetOptional("is_null_allowed", false);}
public function GetEditValue($sValue, $oHostObj = null)
{
@@ -4569,7 +4571,7 @@ class AttributeStopWatch extends AttributeDefinition
public function IsDirectField() {return true;}
public function IsScalar() {return true;}
public function IsWritable() {return false;}
public function GetDefaultValue() {return $this->NewStopWatch();}
public function GetDefaultValue(DBObject $oHostObject = null) {return $this->NewStopWatch();}
public function GetEditValue($value, $oHostObj = null)
{
@@ -5186,9 +5188,21 @@ class AttributeSubItem extends AttributeDefinition
public function IsDirectField() {return true;}
public function IsScalar() {return true;}
public function IsWritable() {return false;}
public function GetDefaultValue() {return null;}
public function GetDefaultValue(DBObject $oHostObject = null) {return null;}
// public function IsNullAllowed() {return false;}
public function LoadInObject() {return false;} // if this verb returns true, then GetValue must be implemented
public function LoadInObject() {return false;} // if this verb returns false, then GetValue must be implemented
/**
* Used by DBOBject::Get()
*/
public function GetValue($oHostObject, $bOriginal = false)
{
$oParent = $this->GetTargetAttDef();
$parentValue = $oHostObject->GetStrict($oParent->GetCode());
$res = $oParent->GetSubItemValue($this->Get('item_code'), $parentValue, $oHostObject);
return $res;
}
//
// protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
@@ -5237,16 +5251,6 @@ class AttributeSubItem extends AttributeDefinition
return $res;
}
/**
* Used by DBOBject::Get()
*/
public function GetValue($parentValue, $oHostObject = null)
{
$oParent = $this->GetTargetAttDef();
$res = $oParent->GetSubItemValue($this->Get('item_code'), $parentValue, $oHostObject);
return $res;
}
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
@@ -5303,7 +5307,7 @@ class AttributeOneWayPassword extends AttributeDefinition
public function IsDirectField() {return true;}
public function IsScalar() {return true;}
public function IsWritable() {return true;}
public function GetDefaultValue() {return "";}
public function GetDefaultValue(DBObject $oHostObject = null) {return "";}
public function IsNullAllowed() {return $this->GetOptional("is_null_allowed", false);}
// Facilitate things: allow the user to Set the value from a string or from an ormPassword (already encrypted)
@@ -5676,7 +5680,7 @@ class AttributeComputedFieldVoid extends AttributeDefinition
public function IsScalar() {return true;}
public function IsWritable() {return false;}
public function GetSQLExpr() {return null;}
public function GetDefaultValue() {return $this->MakeRealValue("", null);}
public function GetDefaultValue(DBObject $oHostObject = null) {return $this->MakeRealValue("", $oHostObject);}
public function IsNullAllowed() {return false;}
//
@@ -5827,7 +5831,7 @@ class AttributeFriendlyName extends AttributeComputedFieldVoid
{
$this->m_sValue = $sValue;
}
public function GetDefaultValue()
public function GetDefaultValue(DBObject $oHostObject = null)
{
return $this->m_sValue;
}
@@ -5913,7 +5917,7 @@ class AttributeRedundancySettings extends AttributeDBField
return 20;
}
public function GetDefaultValue($aArgs = array())
public function GetDefaultValue(DBObject $oHostObject = null)
{
$sRet = 'disabled';
if ($this->Get('enabled'))
@@ -6268,3 +6272,251 @@ class AttributeRedundancySettings extends AttributeDBField
return $sRet;
}
}
/**
* Custom fields managed by an external implementation
*
* @package iTopORM
*/
class AttributeCustomFields extends AttributeDefinition
{
static public function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("handler_class"));
}
public function GetEditClass() {return "CustomFields";}
public function IsWritable() {return true;}
public function LoadFromDB() {return false;} // See ReadValue...
public function GetDefaultValue(DBObject $oHostObject = null)
{
return new ormCustomFieldsValue($oHostObject, $this->GetCode());
}
public function GetBasicFilterOperators() {return array();}
public function GetBasicFilterLooseOperator() {return '';}
public function GetBasicFilterSQLExpr($sOpCode, $value) {return '';}
/**
* @param DBObject $oHostObject
* @param ormCustomFieldsValue|null $oValue
* @return CustomFieldsHandler
*/
public function GetHandler(DBObject $oHostObject, ormCustomFieldsValue $oValue = null)
{
$sHandlerClass = $this->Get('handler_class');
$oHandler = new $sHandlerClass($oHostObject, $this->GetCode());
if (!is_null($oValue))
{
$oHandler->SetCurrentValues($oValue->GetValues());
}
return $oHandler;
}
public function GetPrerequisiteAttributes($sClass = null)
{
$sHandlerClass = $this->Get('handler_class');
return $sHandlerClass::GetPrerequisiteAttributes($sClass);
}
public function GetEditValue($sValue, $oHostObj = null)
{
return 'GetEditValueNotImplemented for '.get_class($this);
}
/**
* Makes the string representation out of the values given by the form defined in GetDisplayForm
*/
public function ReadValueFromPostedForm($oHostObject, $sFormPrefix)
{
$aRawData = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->GetCode()}", '{}', 'raw_data'), true);
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aRawData);
}
public function MakeRealValue($proposedValue, $oHostObject)
{
if (is_object($proposedValue) && ($proposedValue instanceof ormCustomFieldsValue))
{
return $proposedValue;
}
elseif (is_string($proposedValue))
{
$aValues = json_decode($proposedValue, true);
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aValues);
}
throw new Exception('Unexpected type for the value of a custom fields attribute: '.gettype($proposedValue));
}
/**
* Override to build the relevant form field
*
* When called first, $oFormField is null and will be created (eg. Make). Then when the ::parent is called and the $oFormField is passed, MakeFormField behaves more like a Prepare.
*/
public function MakeFormField(DBObject $oObject, $oFormField = null)
{
if ($oFormField === null)
{
$oField = new Combodo\iTop\Form\Field\SubFormField($this->GetCode(), $sParentFormId);
$oField->SetForm($this->GetForm($oObject));
}
parent::MakeFormField($oObject, $oFormField);
return $oFormField;
}
/**
* @param DBObject $oHostObject
* @return Combodo\iTop\Form\Form
*/
public function GetForm(DBObject $oHostObject, $sFormPrefix = null)
{
$oHandler = $this->GetHandler($oHostObject, $oHostObject->Get($this->GetCode()));
$sFormId = is_null($sFormPrefix) ? 'cf_'.$this->GetCode() : $sFormPrefix.'_cf_'.$this->GetCode();
$oHandler->BuildForm($sFormId);
return $oHandler->GetForm();
}
/**
* Read the data from where it has been stored. This verb must be implemented as soon as LoadFromDB returns false and LoadInObject returns true
* @param $oHostObject
* @return ormCustomFieldsValue
*/
public function ReadValue($oHostObject)
{
$oHandler = $this->GetHandler($oHostObject);
$aValues = $oHandler->ReadValues();
$oRet = new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aValues);
return $oRet;
}
/**
* Record the data (currently in the processing of recording the host object)
* It is assumed that the data has been checked prior to calling Write()
* @param DBObject $oHostObject
* @param ormCustomFieldsValue|null $oValue (null is the default value)
*/
public function WriteValue(DBObject $oHostObject, ormCustomFieldsValue $oValue = null)
{
$oHandler = $this->GetHandler($oHostObject, $oHostObject->Get($this->GetCode()));
if (is_null($oValue))
{
$aValues = array();
}
else
{
$aValues = $oValue->GetValues();
}
return $oHandler->WriteValues($aValues);
}
/**
* Check the validity of the data
* @param DBObject $oHostObject
* @param $value
* @return bool|string true or error message
*/
public function CheckValue(DBObject $oHostObject, $value)
{
try
{
$oHandler = $this->GetHandler($oHostObject, $value);
$oHandler->BuildForm();
$oForm = $oHandler->GetForm();
$oForm->Validate();
if ($oForm->GetValid())
{
$ret = true;
}
else
{
$aMessages = array();
foreach ($oForm->GetErrorMessages() as $sFieldId => $aFieldMessages)
{
$aMessages[] = $sFieldId.': '.implode(', ', $aFieldMessages);
}
$ret = 'Invalid value: '.implode(', ', $aMessages);
}
}
catch (Exception $e)
{
$ret = $e->getMessage();
}
return $ret;
}
/**
* Cleanup data upon object deletion (object id still available here)
* @param DBObject $oHostObject
*/
public function DeleteValue(DBObject $oHostObject)
{
$oHandler = $this->GetHandler($oHostObject, $oHostObject->Get($this->GetCode()));
return $oHandler->DeleteValues();
}
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
return $value->GetAsHTML($bLocalize);
}
public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return $value->GetAsXML($bLocalize);
}
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false)
{
return $value->GetAsCSV($sSeparator, $sTextQualifier, $bLocalize, $bConvertToPlainText);
}
/**
* List the available verbs for 'GetForTemplate'
*/
public function EnumTemplateVerbs()
{
$sHandlerClass = $this->Get('handler_class');
return $sHandlerClass::EnumTemplateVerbs();
}
/**
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
* @param $value mixed The current value of the field
* @param $sVerb string The verb specifying the representation of the value
* @param $oHostObject DBObject The object
* @param $bLocalize bool Whether or not to localize the value
*/
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
{
return $value->GetForTemplate($sVerb, $bLocalize);
}
public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
{
return null;
}
/**
* Helper to get a value that will be JSON encoded
* The operation is the opposite to FromJSONToValue
*/
public function GetForJSON($value)
{
return null;
}
/**
* Helper to form a value, given JSON decoded data
* The operation is the opposite to GetForJSON
*/
public function FromJSONToValue($json)
{
return null;
}
public function Equals($val1, $val2)
{
return $val1->Equals($val2);
}
}

View File

@@ -302,14 +302,10 @@ abstract class CMDBObject extends DBObject
{
// Stop watches - record changes for sub items only (they are visible, the rest is not visible)
//
if (is_null($original))
{
$original = new OrmStopWatch();
}
foreach ($oAttDef->ListSubItems() as $sSubItemAttCode => $oSubItemAttDef)
{
$item_value = $oSubItemAttDef->GetValue($value);
$item_original = $oSubItemAttDef->GetValue($original);
$item_value = $oSubItemAttDef->GetValue($this);
$item_original = $oSubItemAttDef->GetValue($this, true);
if ($item_value != $item_original)
{

View File

@@ -0,0 +1,127 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Form\Form;
use Combodo\iTop\Form\FormManager;
/**
* Base class to implement a handler for AttributeCustomFields
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class CustomFieldsHandler
{
protected $oHostObject;
protected $sAttCode;
protected $aValues;
protected $oForm;
/**
* This constructor's prototype must be frozen.
* Any specific behavior must be implemented in BuildForm()
*
* @param DBObject $oHostObject
* @param $sAttCode
*/
final public function __construct(DBObject $oHostObject, $sAttCode)
{
$this->oHostObject = $oHostObject;
$this->sAttCode = $sAttCode;
$this->aValues = null;
}
abstract public function BuildForm($sFormId);
/**
*
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
return $this->oForm;
}
public function SetCurrentValues($aValues)
{
$this->aValues = $aValues;
}
static public function GetPrerequisiteAttributes($sClass = null)
{
return array();
}
/**
* List the available verbs for 'GetForTemplate'
*/
static public function EnumTemplateVerbs()
{
return array();
}
/**
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
* @param $aValues array The current values
* @param $sVerb string The verb specifying the representation of the value
* @param $bLocalize bool Whether or not to localize the value
* @return string
*/
abstract public function GetForTemplate($aValues, $sVerb, $bLocalize = true);
/**
* @param $aValues
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsHTML($aValues, $bLocalize = true);
/**
* @param $aValues
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsXML($aValues, $bLocalize = true);
/**
* @param $aValues
* @param string $sSeparator
* @param string $sTextQualifier
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsCSV($aValues, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true);
/**
* @return array Associative array id => value
*/
abstract public function ReadValues();
/**
* Record the data (currently in the processing of recording the host object)
* It is assumed that the data has been checked prior to calling Write()
* @param array Associative array id => value
*/
abstract public function WriteValues($aValues);
/**
* Cleanup data upon object deletion (object id still available here)
*/
abstract public function DeleteValues();
}

View File

@@ -116,7 +116,7 @@ abstract class DBObject implements iDisplay
// set default values
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
{
$this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue();
$this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue($this);
$this->m_aOrigValues[$sAttCode] = null;
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
{
@@ -291,16 +291,30 @@ abstract class DBObject implements iDisplay
if (!$oAttDef->LoadInObject()) continue;
// Note: we assume that, for a given attribute, if it can be loaded,
// then one column will be found with an empty suffix, the others have a suffix
// Take care: the function isset will return false in case the value is null,
// which is something that could happen on open joins
$sAttRef = $sClassAlias.$sAttCode;
if (array_key_exists($sAttRef, $aRow))
unset($value);
$bIsDefined = false;
if ($oAttDef->LoadFromDB())
{
$value = $oAttDef->FromSQLToValue($aRow, $sAttRef);
// Note: we assume that, for a given attribute, if it can be loaded,
// then one column will be found with an empty suffix, the others have a suffix
// Take care: the function isset will return false in case the value is null,
// which is something that could happen on open joins
$sAttRef = $sClassAlias.$sAttCode;
if (array_key_exists($sAttRef, $aRow))
{
$value = $oAttDef->FromSQLToValue($aRow, $sAttRef);
$bIsDefined = true;
}
}
else
{
$value = $oAttDef->ReadValue($this);
$bIsDefined = true;
}
if ($bIsDefined)
{
$this->m_aCurrValues[$sAttCode] = $value;
if (is_object($value))
{
@@ -380,7 +394,7 @@ abstract class DBObject implements iDisplay
{
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sAttCode))
{
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue($this);
unset($this->m_aLoadedAtt[$sCode]);
}
}
@@ -492,9 +506,7 @@ abstract class DBObject implements iDisplay
if (!$oAttDef->LoadInObject())
{
$sParentAttCode = $oAttDef->GetParentAttCode();
$parentValue = $this->GetStrict($sParentAttCode);
$value = $oAttDef->GetValue($parentValue, $this);
$value = $oAttDef->GetValue($this);
}
else
{
@@ -550,7 +562,7 @@ abstract class DBObject implements iDisplay
}
else
{
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue($this);
}
$this->m_aLoadedAtt[$sCode] = true;
}
@@ -1109,6 +1121,10 @@ abstract class DBObject implements iDisplay
return "Wrong format [$toCheck]";
}
}
else
{
return $oAtt->CheckValue($this, $toCheck);
}
return true;
}
@@ -1405,6 +1421,17 @@ abstract class DBObject implements iDisplay
}
}
// used both by insert/update
private function WriteExternalAttributes()
{
foreach (MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
{
if (!$oAttDef->LoadInObject()) continue;
if ($oAttDef->LoadFromDB()) continue;
$oAttDef->WriteValue($this, $this->m_aCurrValues[$sAttCode]);
}
}
// Note: this is experimental - it was designed to speed up the setup of iTop
// Known limitations:
// - does not work with multi-table classes (issue with the unique id to maintain in several tables)
@@ -1591,6 +1618,8 @@ abstract class DBObject implements iDisplay
}
$this->DBWriteLinks();
$this->WriteExternalAttributes();
$this->m_bIsInDB = true;
$this->m_bDirty = false;
@@ -1878,6 +1907,7 @@ abstract class DBObject implements iDisplay
}
$this->DBWriteLinks();
$this->WriteExternalAttributes();
$this->m_bDirty = false;
$this->AfterUpdate();
@@ -1981,6 +2011,10 @@ abstract class DBObject implements iDisplay
}
MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
}
elseif (!$oAttDef->LoadFromDB())
{
$oAttDef->DeleteValue($this);
}
}
foreach(MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL) as $sParentClass)
@@ -2222,7 +2256,7 @@ abstract class DBObject implements iDisplay
public function Reset($sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$this->Set($sAttCode, $oAttDef->GetDefaultValue());
$this->Set($sAttCode, $oAttDef->GetDefaultValue($this));
return true;
}

View File

@@ -0,0 +1,101 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Base class to hold the value managed by CustomFieldsHandler
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ormCustomFieldsValue
{
protected $oHostObject;
protected $sAttCode;
protected $aCurrentValues;
/**
* @param DBObject $oHostObject
* @param $sAttCode
*/
public function __construct(DBObject $oHostObject, $sAttCode, $aCurrentValues = null)
{
$this->oHostObject = $oHostObject;
$this->sAttCode = $sAttCode;
$this->aCurrentValues = $aCurrentValues;
}
public function GetValues()
{
return $this->aCurrentValues;
}
/**
* Wrapper used when the only thing you have is the value...
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
return $oAttDef->GetForm($this->oHostObject);
}
public function GetAsHTML($bLocalize = true)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
$oHandler = $oAttDef->GetHandler($this->oHostObject, $this);
return $oHandler->GetAsHTML($this->aCurrentValues, $bLocalize);
}
public function GetAsXML($bLocalize = true)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
$oHandler = $oAttDef->GetHandler($this->oHostObject, $this);
return $oHandler->GetAsXML($this->aCurrentValues, $bLocalize);
}
public function GetAsCSV($sSeparator = ',', $sTextQualifier = '"', $bLocalize = true)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
$oHandler = $oAttDef->GetHandler($this->oHostObject, $this);
return $oHandler->GetAsCSV($this->aCurrentValues, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true);
}
/**
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
* @param $value mixed The current value of the field
* @param $sVerb string The verb specifying the representation of the value
* @param $bLocalize bool Whether or not to localize the value
*/
public function GetForTemplate($sVerb, $bLocalize = true)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
$oHandler = $oAttDef->GetHandler($this->oHostObject, $this);
return 'template...verb='.$sVerb.' sur "'.json_encode($this->aCurrentValues).'"';
}
/**
* @param ormCustomFieldsValue $fellow
* @return bool
*/
public function Equals(ormCustomFieldsValue $oReference)
{
return (json_encode($this->aCurrentValues) === json_encode($oReference->aCurrentValues));
}
}

115
js/console_form_handler.js Normal file
View File

@@ -0,0 +1,115 @@
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//iTop Form handler
;
$(function()
{
// the widget definition, where 'itop' is the namespace,
// 'consoleform_handler' the widget name
$.widget( 'itop.console_form_handler', $.itop.form_handler,
{
// default options
options:
{
wizard_helper_var_name: '', // Name of the global variable pointing to the wizard helper
custom_field_attcode: ''
},
// the constructor
_create: function()
{
var me = this;
this.element
.addClass('console_form_handler');
this.options.oWizardHelper = window[this.options.wizard_helper_var_name];
this._super();
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element
.removeClass('console_form_handler');
this._super();
},
_onUpdateFields: function(event, data)
{
var me = this;
var sFormPath = data.form_path;
var sUpdateUrl = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php';
$(this.element.find('[data-form-path="' + sFormPath + '"]')).block({message:''});
$.post(
sUpdateUrl,
{
operation: 'custom_fields_update',
attcode: this.options.custom_field_attcode,
//current_values: this.getCurrentValues(),
requested_fields: data.requested_fields,
form_path: sFormPath,
json_obj: this.options.oWizardHelper.UpdateWizardToJSON()
},
function(data){
me._onUpdateSuccess(data, sFormPath);
}
)
.fail(function(data){ me._onUpdateFailure(data, sFormPath); })
.always(function(data){
me.alignColumns();
$(me.element.find('[data-form-path="' + sFormPath + '"]')).unblock();
me._onUpdateAlways(data, sFormPath);
});
},
// On initialization or update
alignColumns: function()
{
var iMaxWidth = 0;
var oLabels = $(this.element.find('td.form-field-label'));
// Reset the width to the automatic (original) value
oLabels.width('');
oLabels.each(function() {
iMaxWidth = Math.max(iMaxWidth, $(this).width());
});
oLabels.width(iMaxWidth);
},
// Intended for overloading in derived classes
_onSubmitClick: function()
{
},
// Intended for overloading in derived classes
_onCancelClick: function()
{
},
// Intended for overloading in derived classes
_onUpdateFailure: function(data)
{
},
// Intended for overloading in derived classes
_disableFormBeforeLoading: function()
{
},
// Intended for overloading in derived classes
_enableFormAfterLoading: function()
{
},
});
});

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2010-2012 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -28,7 +28,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
this.ajax_request = null;
this.bSelectMode = bSelectMode; // true if the edited field is a SELECT, false if it's an autocomplete
this.bSearchMode = bSearchMode; // true if selecting a value in the context of a search form
this.v_html = '';
var me = this;
this.Init = function()
@@ -55,8 +54,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// Query the server to get the form to search for target objects
if (me.bSelectMode)
{
me.v_html = $('#v_'+me.id).html();
$('#v_'+me.id).html('<img src="../images/indicator.gif" />');
$('#fstatus_'+me.id).html('<img src="../images/indicator.gif" />');
}
else
{
@@ -284,8 +282,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// Query the server to get the form to create a target object
if (me.bSelectMode)
{
me.v_html = $('#v_'+me.id).html();
$('#v_'+me.id).html('<img src="../images/indicator.gif" />');
$('#fstatus_'+me.id).html('<img src="../images/indicator.gif" />');
}
else
{
@@ -336,7 +333,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
{
if (me.bSelectMode)
{
$('#v_'+me.id).html(me.v_html);
}
else
{
@@ -446,8 +442,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
if (me.bSelectMode)
{
me.v_html = $('#v_'+me.id).html();
$('#v_'+me.id).html('<img src="../images/indicator.gif" />');
$('#fstatus_'+me.id).html('<img src="../images/indicator.gif" />');
}
else
{
@@ -501,7 +496,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
{
if (me.bSelectMode)
{
$('#v_'+me.id).html(me.v_html);
}
else
{

View File

@@ -1,3 +1,20 @@
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//iTop Field set
//Used by itop.form_handler and itop.subform_field to list their fields
;
@@ -36,15 +53,15 @@ $(function()
this.element
.bind('field_change', function(oEvent, oData){
console.log('field_set: field_change');
//console.log('field_set: field_change');
me._onFieldChange(oEvent, oData);
})
.bind('update_form', function(oEvent, oData){
console.log('field_set: update_form');
//console.log('field_set: update_form');
me._onUpdateForm(oEvent, oData);
})
.bind('get_current_values', function(oEvent, oData){
console.log('field_set: get_current_values');
//console.log('field_set: get_current_values');
return me._onGetCurrentValues(oEvent, oData);
})
.bind('validate', function(oEvent, oData){
@@ -52,7 +69,7 @@ $(function()
{
oData = {};
}
console.log('field_set: validate');
//console.log('field_set: validate');
return me._onValidate(oEvent, oData);
});
@@ -175,8 +192,9 @@ $(function()
}
// Adding code to the dom
this.options.script_element.append('\n\n// Appended by update on ' + Date() + '\n' + this.buildData.script_code);
this.options.style_element.append('\n\n// Appended by update on ' + Date() + '\n' + this.buildData.style_code);
// Note : We use text() instead of append(), otherwise the code will be interpreted as DOM tags (text + <img /> + ...) and can break some browsers
this.options.script_element.text( this.options.script_element.text() + '\n\n// Appended by update on ' + Date() + '\n' + this.buildData.script_code);
this.options.style_element.text( this.options.style_element.text() + '\n\n// Appended by update on ' + Date() + '\n' + this.buildData.style_code);
// Evaluating script code as adding it to dom did not executed it (only script from update !)
eval(this.buildData.script_code);
@@ -291,7 +309,7 @@ $(function()
var oField = this.options.fields_list[i];
if(oField.id === undefined)
{
console.log('Field set : An field must have at least an id property.');
console.log('Field set : A field must have at least an id property.');
return false;
}

View File

@@ -1,3 +1,20 @@
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
// ID of the (hidden) form field used to store the JSON representation of the
// object being edited in this page
var sJsonFieldId = 'json_object';
@@ -417,6 +434,15 @@ function ValidateRedundancySettings(sFieldId, sFormId)
return bValid;
}
//Special validation function for custom fields
function ValidateCustomFields(sFieldId, sFormId)
{
var oFieldSet = $('#'+sFieldId+'_console_form').console_form_handler('option', 'field_set');
bValid = oFieldSet.triggerHandler('validate');
ReportFieldValidationStatus(sFieldId, sFormId, bValid, '');
return bValid;
}
// Manage a 'duration' field
function UpdateDuration(iId)
{

View File

@@ -1,3 +1,20 @@
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
// Wizard Helper JavaScript class to communicate with the WizardHelper PHP class
if (!Array.prototype.indexOf) // Emulation of the indexOf function for IE and old browsers
@@ -151,6 +168,7 @@ function WizardHelper(sClass, sFormPrefix, sState)
{ operation: 'wizard_helper', json_obj: this.ToJSON() },
function(html){
$('#ajax_content').html(html);
$('.blockUI').parent().unblock();
//console.log('data received:', oWizardHelper);
//oWizardHelper.FromJSON(json_data);
//oWizardHelper.UpdateFields(); // Is done directly in the html provided by ajax.render.php
@@ -191,7 +209,8 @@ function WizardHelper(sClass, sFormPrefix, sState)
{
sAttCode = aFieldNames[index];
sFieldId = this.GetFieldId(sAttCode);
$('#v_'+sFieldId).html('<img src="../images/indicator.gif" />');
$('#fstatus_'+sFieldId).html('<img src="../images/indicator.gif" />');
$('#field_'+sFieldId).closest('td').block({message:''});
this.RequestAllowedValues(sAttCode);
index++;
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Handles various ajax requests
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -563,7 +563,7 @@ try
foreach($oWizardHelper->GetFieldsForDefaultValue() as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$defaultValue = $oAttDef->GetDefaultValue();
$defaultValue = $oAttDef->GetDefaultValue($oObj);
$oWizardHelper->SetDefaultValue($sAttCode, $defaultValue);
$oObj->Set($sAttCode, $defaultValue);
}
@@ -2448,6 +2448,28 @@ EOF
}
}
break;
case 'custom_fields_update':
$oPage->SetContentType('application/json');
$sAttCode = utils::ReadParam('attcode', '');
$aRequestedFields = utils::ReadParam('requested_fields', array());
$sRequestedFieldsFormPath = utils::ReadParam('form_path', '');
$sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
$oOrmCustomFieldValue = $oObj->Get($sAttCode);
$oForm = $oOrmCustomFieldValue->GetForm();
$oSubForm = $oForm->FindSubForm($sRequestedFieldsFormPath);
$oRenderer = new \Combodo\iTop\Renderer\Console\ConsoleFormRenderer($oSubForm);
$aRenderRes = $oRenderer->Render($aRequestedFields);
$aResult = array();
$aResult['form']['updated_fields'] = $aRenderRes;
$oPage->add(json_encode($aResult));
break;
default:
$oPage->p("Invalid query.");
}

View File

@@ -1206,6 +1206,10 @@ EOF;
$aParameters['min_up_mode'] = $this->GetMandatoryPropString($oField, 'min_up_mode');
$aParameters['min_up_type'] = $this->GetMandatoryPropString($oField, 'min_up_type');
}
elseif ($sAttType == 'AttributeCustomFields')
{
$aParameters['handler_class'] = $this->GetMandatoryPropString($oField, 'handler_class');
}
else
{
$aParameters['allowed_values'] = 'null'; // or "new ValueSetEnum('SELECT xxxx')"

View File

@@ -61,7 +61,7 @@ class SubFormField extends Field
*/
public function Validate()
{
$this->oForm->Validate();
return $this->oForm->Validate();
}
/**
@@ -106,4 +106,13 @@ class SubFormField extends Field
$this->oForm->SetCurrentValues($value);
return $this;
}
/**
* @param $sFormPath
* @return Form|null
*/
public function FindSubForm($sFormPath)
{
return $this->oForm->FindSubForm($sFormPath);
}
}

View File

@@ -19,6 +19,7 @@
namespace Combodo\iTop\Form;
use Combodo\iTop\Form\Field\SubFormField;
use \Exception;
use \Dict;
use \Combodo\iTop\Form\Field\Field;
@@ -312,83 +313,108 @@ class Form
* @param string $sDependsOnId
* @return \Combodo\iTop\Form\Form
*/
public function AddFieldDependency($sFieldId, $sDependsOnId)
{
if (!array_key_exists($sFieldId, $this->aDependencies))
{
$this->aDependencies[$sFieldId] = array();
}
$this->aDependencies[$sFieldId][] = $sDependsOnId;
return $this;
}
public function AddFieldDependency($sFieldId, $sDependsOnId)
{
if (!array_key_exists($sFieldId, $this->aDependencies))
{
$this->aDependencies[$sFieldId] = array();
}
$this->aDependencies[$sFieldId][] = $sDependsOnId;
return $this;
}
/**
* Returns a hash array of the fields impacts on other fields. Key being the field that impacts the fields stored in the value as a regular array
* (It kind of reversed the dependencies array)
*
* eg :
* - 'service' => array('subservice', 'template')
* - 'subservice' => array()
* - ...
*
* @return array
*/
public function GetFieldsImpacts()
{
$aRes = array();
foreach ($this->aDependencies as $sImpactedFieldId => $aDependentFieldsIds)
{
foreach ($aDependentFieldsIds as $sDependentFieldId)
{
if (!array_key_exists($sDependentFieldId, $aRes))
{
$aRes[$sDependentFieldId] = array();
}
$aRes[$sDependentFieldId][] = $sImpactedFieldId;
}
}
return $aRes;
}
/**
* Returns a hash array of the fields impacts on other fields. Key being the field that impacts the fields stored in the value as a regular array
* (It kind of reversed the dependencies array)
*
* eg :
* - 'service' => array('subservice', 'template')
* - 'subservice' => array()
* - ...
*
* @return array
* @param $sFormPath
* @return Form|null
*/
public function GetFieldsImpacts()
public function FindSubForm($sFormPath)
{
$aRes = array();
foreach ($this->aDependencies as $sImpactedFieldId => $aDependentFieldsIds)
$ret = null;
if ($sFormPath == $this->sId)
{
foreach ($aDependentFieldsIds as $sDependentFieldId)
$ret = $this;
}
else
{
foreach ($this->aFields as $oField)
{
if (!array_key_exists($sDependentFieldId, $aRes))
if ($oField instanceof SubFormField)
{
$aRes[$sDependentFieldId] = array();
$ret = $oField->FindSubForm($sFormPath);
if ($ret !== null) break;
}
$aRes[$sDependentFieldId][] = $sImpactedFieldId;
}
}
return $aRes;
return $ret;
}
/**
*
*/
public function Finalize()
{
//TODO : Call GetOrderedFields
// Must call OnFinalize on each fields, regarding the dependencies order
// On a SubFormField, will call its own Finalize
foreach ($this->aFields as $sId => $oField)
{
$oField->OnFinalize();
}
}
public function Finalize()
{
//TODO : Call GetOrderedFields
// Must call OnFinalize on each fields, regarding the dependencies order
// On a SubFormField, will call its own Finalize
foreach ($this->aFields as $sId => $oField)
{
$oField->OnFinalize();
}
}
/**
* Validate the form and return if it's valid or not
*
* @return boolean
*/
public function Validate()
{
$this->SetValid(true);
$this->EmptyErrorMessages();
public function Validate()
{
$this->SetValid(true);
$this->EmptyErrorMessages();
foreach ($this->aFields as $oField)
{
if (!$oField->Validate())
{
$this->SetValid(false);
foreach ($oField->GetErrorMessages() as $sErrorMessage)
{
$this->AddErrorMessage(Dict::S($sErrorMessage), $oField->Getid());
}
}
}
foreach ($this->aFields as $oField)
{
if (!$oField->Validate())
{
$this->SetValid(false);
foreach ($oField->GetErrorMessages() as $sErrorMessage)
{
$this->AddErrorMessage(Dict::S($sErrorMessage), $oField->Getid());
}
}
}
return $this->GetValid();
}
return $this->GetValid();
}
}

View File

@@ -33,7 +33,9 @@ class ConsoleFormRenderer extends FormRenderer
public function __construct(Form $oForm)
{
parent::__construct($oForm);
$this->AddSupportedField('HiddenField', 'ConsoleSimpleFieldRenderer');
$this->AddSupportedField('StringField', 'ConsoleSimpleFieldRenderer');
$this->AddSupportedField('SelectField', 'ConsoleSimpleFieldRenderer');
$this->AddSupportedField('SubFormField', 'ConsoleSubFormFieldRenderer');
}
}

View File

@@ -18,6 +18,7 @@
namespace Combodo\iTop\Renderer\Console\FieldRenderer;
use Combodo\iTop\Form\Field\StringField;
use \Dict;
use Combodo\iTop\Renderer\FieldRenderer;
use Combodo\iTop\Renderer\RenderingOutput;
@@ -29,35 +30,60 @@ class ConsoleSimpleFieldRenderer extends FieldRenderer
$oOutput = new RenderingOutput();
$sFieldClass = get_class($this->oField);
// TODO : Shouldn't we have a field type so we don't have to maintain FQN classname ?
// Rendering field in edition mode
if (!$this->oField->GetReadOnly())
if ($sFieldClass == 'Combodo\\iTop\\Form\\Field\\HiddenField')
{
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\StringField':
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<input type="text" id="'.$this->oField->GetGlobalId().'" value="' . $this->oField->GetCurrentValue() . '" size="30" />');
$oOutput->AddHtml('<span class="form_validation"></span>');
break;
}
$oOutput->AddHtml('<input type="hidden" id="'.$this->oField->GetGlobalId().'" value="' . htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8') . '"/>');
}
// ... and in read-only mode
else
{
$oOutput->AddHtml('<table class="form-field-container">');
$oOutput->AddHtml('<tr>');
if ($this->oField->GetLabel() != '')
{
$oOutput->AddHtml('<td class="form-field-label label"><span><label for="'.$this->oField->GetGlobalId().'">'.$this->oField->GetLabel().'</label></span></td>');
}
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\StringField':
if ($this->oField->GetLabel() !== '')
$oOutput->AddHtml('<td class="form-field-content">');
if ($this->oField->GetReadOnly())
{
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<input type="hidden" id="'.$this->oField->GetGlobalId().'" value="' . htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8') . '"/>');
$oOutput->AddHtml('<span class="form-field-data">'.htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8').'</span>');
}
$oOutput->AddHtml('<div class="form-control-static">' . $this->oField->GetCurrentValue() . '</div>');
else
{
$oOutput->AddHtml('<input class="form-field-data" type="text" id="'.$this->oField->GetGlobalId().'" value="'.htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8').'" size="30"/>');
}
$oOutput->AddHtml('</td>');
$oOutput->AddHtml('<span class="form_validation"></span>');
break;
case 'Combodo\\iTop\\Form\\Field\\SelectField':
$oOutput->AddHtml('<td class="form-field-content">');
if ($this->oField->GetReadOnly())
{
$aChoices = $this->oField->GetChoices();
$sCurrentLabel = isset($aChoices[$this->oField->GetCurrentValue()]) ? $aChoices[$this->oField->GetCurrentValue()] : '' ;
$oOutput->AddHtml('<input type="hidden" id="'.$this->oField->GetGlobalId().'" value="' . htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8') . '"/>');
$oOutput->AddHtml('<span class="form-field-data">'.htmlentities($sCurrentLabel, ENT_QUOTES, 'UTF-8').'</span>');
}
else
{
$oOutput->AddHtml('<select class="form-field-data" id="'.$this->oField->GetGlobalId().'" '.(($this->oField->GetMultipleValuesEnabled()) ? 'multiple' : '').'>');
foreach ($this->oField->GetChoices() as $sChoice => $sLabel)
{
// Note : The test is a double equal on purpose as the type of the value received from the XHR is not always the same as the type of the allowed values. (eg : string vs int)
$sSelectedAtt = ($this->oField->GetCurrentValue() == $sChoice) ? 'selected' : '';
$oOutput->AddHtml('<option value="'.htmlentities($sChoice, ENT_QUOTES, 'UTF-8').'" '.$sSelectedAtt.' >'.htmlentities($sLabel, ENT_QUOTES, 'UTF-8').'</option>');
}
$oOutput->AddHtml('</select>');
}
$oOutput->AddHtml('</td>');
break;
}
$oOutput->AddHtml('</tr>');
$oOutput->AddHtml('</table>');
}
switch ($sFieldClass)
@@ -65,7 +91,22 @@ class ConsoleSimpleFieldRenderer extends FieldRenderer
case 'Combodo\\iTop\\Form\\Field\\StringField':
$oOutput->AddJs(
<<<EOF
$("#{$this->oField->GetGlobalId()}").off("change").on("change keyup", function(){
$("#{$this->oField->GetGlobalId()}").off("change keyup").on("change keyup", function(){
var me = this;
$(this).closest(".field_set").trigger("field_change", {
id: $(me).attr("id"),
name: $(me).closest(".form_field").attr("data-field-id"),
value: $(me).val()
});
});
EOF
);
break;
case 'Combodo\\iTop\\Form\\Field\\SelectField':
$oOutput->AddJs(
<<<EOF
$("#{$this->oField->GetGlobalId()}").off("change").on("change", function(){
var me = this;
$(this).closest(".field_set").trigger("field_change", {
@@ -88,7 +129,6 @@ EOF
'message' => Dict::S($oValidator->GetErrorMessage())
);
}
$sValidators = json_encode($aValidators);
$sFormFieldOptions =
<<<EOF
@@ -118,19 +158,27 @@ EOF
EOF
;
$oOutput->AddJs(
<<<EOF
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").form_field($sFormFieldOptions);
EOF
);
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\SelectField':
$oOutput->AddJs(
<<<EOF
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").form_field('option', 'get_current_value_callback', function(me){ return $(me.element).find('select').val();});
EOF
);
break;
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
case 'Combodo\\iTop\\Form\\Field\\StringField':
case 'Combodo\\iTop\\Form\\Field\\TextAreaField':
case 'Combodo\\iTop\\Form\\Field\\SelectField':
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
case 'Combodo\\iTop\\Form\\Field\\RadioField':
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$oOutput->AddJs(
<<<EOF
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").form_field($sFormFieldOptions);
EOF
);
break;
}