Prerequisites to the custom fields (and space tabs to regular tabs conversion on some files)

SVN:trunk[3919]
This commit is contained in:
Guillaume Lajarige
2016-02-19 16:43:28 +00:00
parent bfadbc4098
commit 17127a5157
24 changed files with 2278 additions and 1990 deletions

View File

@@ -1,9 +1,10 @@
//iTop Form handler
//iTop Field set
//Used by itop.form_handler and itop.subform_field to list their fields
;
$(function()
{
// the widget definition, where 'itop' is the namespace,
// 'form_handler' the widget name
// 'field_set' the widget name
$.widget( 'itop.field_set',
{
// default options
@@ -34,25 +35,25 @@ $(function()
.addClass('field_set');
this.element
.bind('field_change', function(event, data){
.bind('field_change', function(oEvent, oData){
console.log('field_set: field_change');
me._onFieldChange(event, data);
me._onFieldChange(oEvent, oData);
})
.bind('update_form', function(event, data){
.bind('update_form', function(oEvent, oData){
console.log('field_set: update_form');
me._onUpdateForm(event, data);
me._onUpdateForm(oEvent, oData);
})
.bind('get_current_values', function(event, data){
.bind('get_current_values', function(oEvent, oData){
console.log('field_set: get_current_values');
return me._onGetCurrentValues(event, data);
return me._onGetCurrentValues(oEvent, oData);
})
.bind('validate', function(event, data){
if (data === undefined)
.bind('validate', function(oEvent, oData){
if (oData === undefined)
{
data = {};
oData = {};
}
console.log('field_set: validate');
return me._onValidate(event, data);
return me._onValidate(oEvent, oData);
});
// Creating DOM elements if not using user's specifics
@@ -97,104 +98,103 @@ $(function()
{
this._super( key, value );
},
_getField: function (sFieldId)
getField: function (sFieldId)
{
return this.element.find('[' + this.options.field_identifier_attr + '="' + sFieldId + '"][data-form-path="' + this.options.form_path + '"]');
},
_onGetCurrentValues: function(event, data)
_onGetCurrentValues: function(oEvent, oData)
{
event.stopPropagation();
oEvent.stopPropagation();
var result = {};
var oResult = {};
for(var i in this.options.fields_list)
{
var field = this.options.fields_list[i];
if(this._getField(field.id).hasClass('form_field'))
var oField = this.options.fields_list[i];
if(this.getField(oField.id).hasClass('form_field'))
{
result[field.id] = this._getField(field.id).triggerHandler('get_current_value');
oResult[oField.id] = this.getField(oField.id).triggerHandler('get_current_value');
}
else
{
console.log('Field set : Cannot retrieve current value from field [' + this.options.field_identifier_attr + '="'+field.id+'"] as it seems to have no itop.form_field widget attached.');
console.log('Field set : Cannot retrieve current value from field [' + this.options.field_identifier_attr + '="' + oField.id + '"][data-form-path="' + this.options.form_path + '"] as it seems to have no itop.form_field widget attached.');
}
}
return result;
return oResult;
},
_getRequestedFields: function(sourceFieldName)
_getRequestedFields: function(sSourceFieldName)
{
var fieldsName = [];
var aFieldsName = [];
if(this.options.fields_impacts[sourceFieldName] !== undefined)
if(this.options.fields_impacts[sSourceFieldName] !== undefined)
{
for(var i in this.options.fields_impacts[sourceFieldName])
for(var i in this.options.fields_impacts[sSourceFieldName])
{
fieldsName.push(this.options.fields_impacts[sourceFieldName][i]);
aFieldsName.push(this.options.fields_impacts[sSourceFieldName][i]);
}
}
return fieldsName;
return aFieldsName;
},
_onFieldChange: function(event, data)
_onFieldChange: function(oEvent, oData)
{
event.stopPropagation();
oEvent.stopPropagation();
// Set field as touched so we know that we have to do checks on it later
if(this.options.touched_fields.indexOf(data.name) < 0)
if(this.options.touched_fields.indexOf(oData.name) < 0)
{
this.options.touched_fields.push(data.name);
this.options.touched_fields.push(oData.name);
}
// Validate the field
var oRes = this._getField(data.name).triggerHandler('validate', {touched_fields_only: true});
if (!oRes.is_valid)
var oResult = this.getField(oData.name).triggerHandler('validate', {touched_fields_only: true});
if (!oResult.is_valid)
{
this.options.is_valid = false;
}
var requestedFields = this._getRequestedFields(data.name);
if(requestedFields.length > 0)
var oRequestedFields = this._getRequestedFields(oData.name);
if(oRequestedFields.length > 0)
{
this.element.trigger('update_fields', {form_path: this.options.form_path, requested_fields: requestedFields});
this.element.trigger('update_fields', {form_path: this.options.form_path, requested_fields: oRequestedFields});
}
},
_onUpdateForm: function(event, data)
_onUpdateForm: function(oEvent, oData)
{
event.stopPropagation();
oEvent.stopPropagation();
this.buildData.script_code = '';
this.buildData.style_code = '';
for (var i in data.updated_fields)
for (var i in oData.updated_fields)
{
var updated_field = data.updated_fields[i];
this.options.fields_list[updated_field.id] = updated_field;
this._prepareField(updated_field.id);
var oUpdatedField = oData.updated_fields[i];
this.options.fields_list[oUpdatedField.id] = oUpdatedField;
this._prepareField(oUpdatedField.id);
}
// Adding code to the dom
this.options.script_element.append('\n\n// Appended by update at ' + Date() + '\n' + this.buildData.script_code);
this.options.style_element.append('\n\n// Appended by update at ' + Date() + '\n' + this.buildData.style_code);
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);
// Evaluating script code as adding it to dom did not executed it (only script from update !)
eval(this.buildData.script_code);
},
_onValidate: function(event, data)
_onValidate: function(oEvent, oData)
{
event.stopPropagation();
oEvent.stopPropagation();
this.options.is_valid = true;
var aFieldsToValidate = [];
if ((data.touched_fields_only !== undefined) && (data.touched_fields_only === true))
if ((oData.touched_fields_only !== undefined) && (oData.touched_fields_only === true))
{
aFieldsToValidate = this.options.touched_fields;
}
else
{
// Requires IE9+ Object.keys(this.options.fields_list);
// TODO : Requires IE9+ Object.keys(this.options.fields_list);
for (var sFieldId in this.options.fields_list)
{
aFieldsToValidate.push(sFieldId);
@@ -203,7 +203,7 @@ $(function()
for(var i in aFieldsToValidate)
{
var oRes = this._getField(aFieldsToValidate[i]).triggerHandler('validate', data);
var oRes = this.getField(aFieldsToValidate[i]).triggerHandler('validate', oData);
if (!oRes.is_valid)
{
this.options.is_valid = false;
@@ -211,9 +211,9 @@ $(function()
}
return this.options.is_valid;
},
showOptions: function() // Debug helper
// Debug helper
showOptions: function()
{
console.log(this.options);
return this.options;
},
_loadCssFile: function(url)
@@ -227,55 +227,57 @@ $(function()
$.getScript(url);
},
// Place a field for which no container exists
_addField: function(field_id)
_addField: function(sFieldId)
{
$('<div ' + this.options.field_identifier_attr + '="'+field_id+'" data-form-path="' + this.options.form_path + '"></div>').appendTo(this.element);
$('<div ' + this.options.field_identifier_attr + '="' + sFieldId + '" data-form-path="' + this.options.form_path + '"></div>').appendTo(this.element);
},
_prepareField: function(field_id)
_prepareField: function(sFieldId)
{
var field = this.options.fields_list[field_id];
var oField = this.options.fields_list[sFieldId];
if(this._getField(field.id).length === 1)
if(this.getField(oField.id).length === 1)
{
// We replace the node instead of just replacing the inner html so the previous widget is automatically destroyed.
this._getField(field.id).replaceWith( $('<div ' + this.options.field_identifier_attr + '="'+field.id+'" data-form-path="' + this.options.form_path + '"></div>') );
this.getField(oField.id).replaceWith(
$('<div ' + this.options.field_identifier_attr + '="' + oField.id + '" data-form-path="' + this.options.form_path + '"></div>')
);
}
else
{
this._addField(field.id);
this._addField(oField.id);
}
var field_container = this._getField(field.id);
var oFieldContainer = this.getField(oField.id);
// HTML
if( (field.html !== undefined) && (field.html !== '') )
if( (oField.html !== undefined) && (oField.html !== '') )
{
field_container.html(field.html);
oFieldContainer.html(oField.html);
}
// JS files
if( (field.js_files !== undefined) && (field.js_files.length > 0) )
if( (oField.js_files !== undefined) && (oField.js_files.length > 0) )
{
for(var j in field.js_files)
for(var j in oField.js_files)
{
this._loadJsFile(field.js_files[i]);
this._loadJsFile(oField.js_files[i]);
}
}
// CSS files
if( (field.css_files !== undefined) && (field.css_files.length > 0) )
if( (oField.css_files !== undefined) && (oField.css_files.length > 0) )
{
for(var j in field.css_files)
for(var j in oField.css_files)
{
this._loadCssFile(field.css_files[i]);
this._loadCssFile(oField.css_files[i]);
}
}
// JS inline
if( (field.js_inline !== undefined) && (field.js_inline !== '') )
if( (oField.js_inline !== undefined) && (oField.js_inline !== '') )
{
this.buildData.script_code += '; '+ field.js_inline;
this.buildData.script_code += '; '+ oField.js_inline;
}
// CSS inline
if( (field.css_inline !== undefined) && (field.css_inline !== '') )
if( (oField.css_inline !== undefined) && (oField.css_inline !== '') )
{
this.buildData.style_code += ' '+ field.css_inline;
this.buildData.style_code += ' '+ oField.css_inline;
}
},
@@ -286,14 +288,14 @@ $(function()
for(var i in this.options.fields_list)
{
var field = this.options.fields_list[i];
if(field.id === undefined)
var oField = this.options.fields_list[i];
if(oField.id === undefined)
{
console.log('Field set : An field must have at least an id property.');
return false;
}
this._prepareField(field.id);
this._prepareField(oField.id);
}
this.options.script_element.text('$(document).ready(function(){ ' + this.buildData.script_code + ' });');

View File

@@ -25,22 +25,23 @@ $(function()
.addClass('form_field');
this.element
.bind('set_validators', function(event, data){
event.stopPropagation();
me.options.validators = data;
.bind('set_validators', function(oEvent, oData){
oEvent.stopPropagation();
me.options.validators = oData;
});
this.element
.bind('validate get_current_value', function(event, data){
event.stopPropagation();
var callback = me.options[event.type+'_callback'];
.bind('validate get_current_value', function(oEvent, oData){
oEvent.stopPropagation();
var callback = me.options[oEvent.type+'_callback'];
if(typeof callback === 'string')
{
return me[callback](event, data);
return me[callback](oEvent, oData);
}
else if(typeof callback === 'function')
{
return callback(me, event, data);
return callback(me, oEvent, oData);
}
else
{
@@ -76,27 +77,27 @@ $(function()
{
var value = null;
this.element.find(':input').each(function(index, elem){
if($(elem).is(':hidden') || $(elem).is(':text') || $(elem).is('textarea'))
this.element.find(':input').each(function(iIndex, oElem){
if($(oElem).is(':hidden') || $(oElem).is(':text') || $(oElem).is('textarea'))
{
value = $(elem).val();
value = $(oElem).val();
}
else if($(elem).is('select'))
else if($(oElem).is('select'))
{
value = [];
$(elem).find('option:selected').each(function(){
$(oElem).find('option:selected').each(function(){
value.push($(this).val());
});
}
else if($(elem).is(':checkbox') || $(elem).is(':radio'))
else if($(oElem).is(':checkbox') || $(oElem).is(':radio'))
{
if(value === null)
{
value = [];
}
if($(elem).is(':checked'))
if($(oElem).is(':checked'))
{
value.push($(elem).val());
value.push($(oElem).val());
}
}
else
@@ -107,7 +108,7 @@ $(function()
return value;
},
validate: function(event, data)
validate: function(oEvent, oData)
{
var oResult = { is_valid: true, error_messages: [] };
@@ -196,6 +197,7 @@ $(function()
return oResult;
},
// Debug helper
showOptions: function()
{
return this.options;

View File

@@ -26,18 +26,19 @@ $(function()
this.element
.addClass('form_handler');
this.element.bind('update_fields', function(event, data){
this._onUpdateFields(event, data);
// Binding events
this.element.bind('update_fields', function(oEvent, oData){
me._onUpdateFields(oEvent, oData);
});
// Binding buttons
if(this.options.submit_btn_selector !== null)
{
this.options.submit_btn_selector.off('click').on('click', function(event){ me._onSubmitClick(event); });
this.options.submit_btn_selector.off('click').on('click', function(oEvent){ me._onSubmitClick(oEvent); });
}
if(this.options.cancel_btn_selector !== null)
{
this.options.cancel_btn_selector.off('click').on('click', function(event){ me._onCancelClick(event); });
this.options.cancel_btn_selector.off('click').on('click', function(oEvent){ me._onCancelClick(oEvent); });
}
},
@@ -68,10 +69,10 @@ $(function()
{
return this.options.field_set.triggerHandler('get_current_values');
},
_onUpdateFields: function(event, data)
_onUpdateFields: function(oEvent, oData)
{
var me = this;
var sFormPath = data.form_path;
var sFormPath = oData.form_path;
// Data checks
if(this.options.endpoint === null)
@@ -98,38 +99,38 @@ $(function()
formmanager_class: this.options.formmanager_class,
formmanager_data: JSON.stringify(this.options.formmanager_data),
current_values: this.getCurrentValues(),
requested_fields: data.requested_fields,
requested_fields: oData.requested_fields,
form_path: sFormPath
},
function(data){
me._onUpdateSuccess(data, sFormPath);
function(oData){
me._onUpdateSuccess(oData, sFormPath);
}
)
.fail(function(data){ me._onUpdateFailure(data, sFormPath); })
.always(function(data){ me._onUpdateAlways(data, sFormPath); });
.fail(function(oData){ me._onUpdateFailure(oData, sFormPath); })
.always(function(oData){ me._onUpdateAlways(oData, sFormPath); });
},
// Intended for overloading in derived classes
_onSubmitClick: function(event)
_onSubmitClick: function(oEvent)
{
},
// Intended for overloading in derived classes
_onCancelClick: function(event)
_onCancelClick: function(oEvent)
{
},
// Intended for overloading in derived classes
_onUpdateSuccess: function(data, sFormPath)
_onUpdateSuccess: function(oData, sFormPath)
{
if(data.form.updated_fields !== undefined)
if(oData.form.updated_fields !== undefined)
{
this.element.find('[data-form-path="'+sFormPath+'"]').trigger('update_form', {updated_fields: data.form.updated_fields});
this.element.find('[data-form-path="' + sFormPath + '"]').trigger('update_form', {updated_fields: oData.form.updated_fields});
}
},
// Intended for overloading in derived classes
_onUpdateFailure: function(data, sFormPath)
_onUpdateFailure: function(oData, sFormPath)
{
},
// Intended for overloading in derived classes
_onUpdateAlways: function(data, sFormPath)
_onUpdateAlways: function(oData, sFormPath)
{
// Check all touched AFTER ajax is complete, otherwise the renderer will redraw the field in the mean time.
this.element.find('[data-form-path="' + sFormPath + '"]').trigger('validate');

View File

@@ -1,4 +1,4 @@
//iTop Form field
//iTop Subform field
;
$(function()
{
@@ -35,10 +35,10 @@ $(function()
{
return this.options.field_set.triggerHandler('get_current_values');
},
validate: function(event, data)
validate: function(oEvent, oData)
{
return {
is_valid: this.options.field_set.triggerHandler('validate', data),
is_valid: this.options.field_set.triggerHandler('validate', oData),
error_messages: []
}
},

View File

@@ -48,13 +48,15 @@ abstract class Field
protected $onFinalizeCallback;
/**
* Default constructor
*
* @param Closure $callback (Used in the $oForm->AddField($sId, ..., function() use ($oManager, $oForm, '...') { ... } ); )
* @param string $sId
* @param Closure $onFinalizeCallback (Used in the $oForm->AddField($sId, ..., function() use ($oManager, $oForm, '...') { ... } ); )
*/
public function __construct($sId, Closure $onFinalizeCallback = null)
{
$this->sId = $sId;
$this->sGlobalId = 'field_'.$sId.uniqid();
$this->sGlobalId = 'field_' . $sId . '_' . uniqid();
$this->sLabel = static::DEFAULT_LABEL;
$this->bReadOnly = static::DEFAULT_READ_ONLY;
$this->bMandatory = static::DEFAULT_MANDATORY;
@@ -65,7 +67,8 @@ abstract class Field
}
/**
* Get the field id within its container form
* Returns the field id within its container form
*
* @return string
*/
public function GetId()
@@ -74,7 +77,8 @@ abstract class Field
}
/**
* Get a unique field id within the top level form
* Returns a unique field id within the top level form
*
* @return string
*/
public function GetGlobalId()
@@ -83,7 +87,8 @@ abstract class Field
}
/**
* Get the id of the container form
* Returns the id of the container form
*
* @return string
*/
public function GetFormPath()
@@ -91,21 +96,37 @@ abstract class Field
return $this->sFormPath;
}
/**
*
* @return string
*/
public function GetLabel()
{
return $this->sLabel;
}
/**
*
* @return boolean
*/
public function GetReadOnly()
{
return $this->bReadOnly;
}
/**
*
* @return boolean
*/
public function GetMandatory()
{
return $this->bMandatory;
}
/**
*
* @return array
*/
public function GetValidators()
{
return $this->aValidators;
@@ -122,28 +143,66 @@ abstract class Field
return $this->bValid;
}
/**
*
* @return array
*/
public function GetErrorMessages()
{
return $this->aErrorMessages;
}
/**
*
* @return array
*/
public function GetCurrentValue()
{
return $this->currentValue;
}
/**
* Sets the field formpath
* Usually Called by the form when adding the field
*
* @param string $sFormPath
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetFormPath($sFormPath)
{
$this->sFormPath = $sFormPath;
return $this;
}
/**
*
* @param type $sLabel
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetLabel($sLabel)
{
$this->sLabel = $sLabel;
return $this;
}
/**
*
* @param boolean $bReadOnly
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetReadOnly($bReadOnly)
{
$this->bReadOnly = $bReadOnly;
return $this;
}
/**
* Sets if the field is mandatory or not.
* Setting the value will automatically add/remove a MandatoryValidator to the Field
*
* @param boolean $bMandatory
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetMandatory($bMandatory)
{
// Before changing the property, we check if it was already mandatory. If not, we had the mandatory validator
@@ -167,6 +226,11 @@ abstract class Field
return $this;
}
/**
*
* @param array $aValidators
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetValidators($aValidators)
{
$this->aValidators = $aValidators;
@@ -197,12 +261,22 @@ abstract class Field
return $this;
}
/**
*
* @param mixed $currentValue
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetCurrentValue($currentValue)
{
$this->currentValue = $currentValue;
return $this;
}
/**
*
* @param Closure $onFinalizeCallback
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetOnFinalizeCallback(Closure $onFinalizeCallback)
{
$this->onFinalizeCallback = $onFinalizeCallback;
@@ -210,19 +284,21 @@ abstract class Field
}
/**
* Called by the form when adding the field
*
* @param Validator $oValidator
* @return \Combodo\iTop\Form\Field\Field
*/
public function SetFormPath($sFormPath)
{
$this->sFormPath = $sFormPath;
}
public function AddValidator(Validator $oValidator)
{
$this->aValidators[] = $oValidator;
return $this;
}
/**
*
* @param Validator $oValidator
* @return \Combodo\iTop\Form\Field\Field
*/
public function RemoveValidator(Validator $oValidator)
{
foreach ($this->aValidators as $iKey => $oValue)

View File

@@ -23,7 +23,7 @@ use \Closure;
use \Combodo\iTop\Form\Form;
/**
* Description of StringField
* Description of SubFormField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
@@ -31,12 +31,23 @@ class SubFormField extends Field
{
protected $oForm;
/**
* Default constructor
*
* @param string $sId
* @param string $sParentFormId
* @param Closure $onFinalizeCallback
*/
public function __construct($sId, $sParentFormId, Closure $onFinalizeCallback = null)
{
$this->oForm = new Form($sParentFormId.'-subform_'.$sId);
parent::__construct($sId, $onFinalizeCallback);
}
/**
*
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
return $this->oForm;
@@ -53,11 +64,19 @@ class SubFormField extends Field
$this->oForm->Validate();
}
/**
*
* @return boolean
*/
public function GetValid()
{
return $this->oForm->GetValid();
}
/**
*
* @return array
*/
public function GetErrorMessages()
{
$aRet = array();
@@ -68,13 +87,23 @@ class SubFormField extends Field
return $aRet;
}
/**
*
* @return array
*/
public function GetCurrentValue()
{
return $this->oForm->GetCurrentValues();
}
/**
*
* @param array $value
* @return \Combodo\iTop\Form\Field\SubFormField
*/
public function SetCurrentValue($value)
{
return $this->oForm->SetCurrentValues($value);
$this->oForm->SetCurrentValues($value);
return $this;
}
}

View File

@@ -36,6 +36,11 @@ class Form
protected $bValid;
protected $aErrorMessages;
/**
* Default constructor
*
* @param string $sId
*/
public function __construct($sId)
{
$this->sId = $sId;
@@ -45,21 +50,38 @@ class Form
$this->aErrorMessages = array();
}
/**
*
* @return string
*/
public function GetId()
{
return $this->sId;
}
/**
*
* @return array
*/
public function GetFields()
{
return $this->aFields;
}
/**
*
* @return array
*/
public function GetDependencies()
{
return $this->aDependencies;
}
/**
* Returns a hash array of "Field id" => "Field value"
*
* @return array
*/
public function GetCurrentValues()
{
$aValues = array();
@@ -70,6 +92,11 @@ class Form
return $aValues;
}
/**
*
* @param array $aValues Must be a hash array of "Field id" => "Field value"
* @return \Combodo\iTop\Form\Form
*/
public function SetCurrentValues($aValues)
{
foreach ($aValues as $sId => $value)
@@ -77,6 +104,8 @@ class Form
$oField = $this->GetField($sId);
$oField->SetCurrentValue($value);
}
return $this;
}
/**
@@ -102,6 +131,10 @@ class Form
return $this;
}
/**
*
* @return array
*/
public function GetErrorMessages()
{
return $this->aErrorMessages;
@@ -157,6 +190,12 @@ class Form
return $this;
}
/**
*
* @param string $sId
* @return \Combodo\iTop\Form\Field\Field
* @throws Exception
*/
public function GetField($sId)
{
if (!array_key_exists($sId, $this->aFields))
@@ -166,11 +205,22 @@ class Form
return $this->aFields[$sId];
}
/**
*
* @param string $sId
* @return boolean
*/
public function HasField($sId)
{
return array_key_exists($sId, $this->aFields);
}
/**
*
* @param \Combodo\iTop\Form\Field\Field $oField
* @param array $aDependsOnIds
* @return \Combodo\iTop\Form\Form
*/
public function AddField(Field $oField, $aDependsOnIds = array())
{
$oField->SetFormPath($this->sId);
@@ -178,6 +228,11 @@ class Form
return $this;
}
/**
*
* @param string $sId
* @return \Combodo\iTop\Form\Form
*/
public function RemoveField($sId)
{
if (array_key_exists($sId, $this->aFields))
@@ -214,6 +269,12 @@ class Form
return $this->aDependencies[$sFieldId];
}
/**
*
* @param string $sFieldId
* @param array $aDependsOnIds
* @return \Combodo\iTop\Form\Form
*/
public function AddFieldDependencies($sFieldId, array $aDependsOnIds)
{
foreach ($aDependsOnIds as $sDependsOnId)
@@ -223,6 +284,12 @@ class Form
return $this;
}
/**
*
* @param string $sFieldId
* @param string $sDependsOnId
* @return \Combodo\iTop\Form\Form
*/
public function AddFieldDependency($sFieldId, $sDependsOnId)
{
if (!array_key_exists($sFieldId, $this->aDependencies))
@@ -263,6 +330,9 @@ class Form
return $aRes;
}
/**
*
*/
public function Finalize()
{
//TODO : Call GetOrderedFields
@@ -274,6 +344,11 @@ class Form
}
}
/**
* Validate the form and return if it's valid or not
*
* @return boolean
*/
public function Validate()
{
$this->SetValid(true);

View File

@@ -32,6 +32,14 @@ abstract class FormManager
protected $oForm;
protected $oRenderer;
/**
* Creates an instance of \Combodo\iTop\Form\FormManager from JSON data that must contain at least :
* - formrenderer_class : The class of the FormRenderer to use in the FormManager
* - formrenderer_endpoint : The endpoint of the renderer
*
* @param string $sJson
* @return \Combodo\iTop\Form\FormManager
*/
static function FromJSON($sJson)
{
// Overload in child class when needed
@@ -53,7 +61,8 @@ abstract class FormManager
}
/**
* @return Form
*
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
@@ -61,24 +70,54 @@ abstract class FormManager
}
/**
* @return FormRenderer
*
* @param \Combodo\iTop\Form\Form $oForm
* @return \Combodo\iTop\Form\FormManager
*/
public function SetForm(Form $oForm)
{
$this->oForm = $oForm;
return $this;
}
/**
*
* @return \Combodo\iTop\Renderer\FormRenderer
*/
public function GetRenderer()
{
return $this->oRenderer;
}
/**
*
* @param \Combodo\iTop\Renderer\FormRenderer $oRenderer
* @return \Combodo\iTop\Form\FormManager
*/
public function SetRenderer(FormRenderer $oRenderer)
{
$this->oRenderer = $oRenderer;
return $this;
}
/**
*
* @return string
*/
public function GetClass()
{
return get_class($this);
}
/**
* Creates a JSON string from the current object including :
* - id : Id of the current Form
* - formmanager_class
* - formrenderer_class
* - formrenderer_endpoint
*
* @return string
*/
public function ToJSON()
{
// Overload in child class when needed

View File

@@ -31,6 +31,11 @@ class BsFormRenderer extends FormRenderer
{
const DEFAULT_RENDERER_NAMESPACE = 'Combodo\\iTop\\Renderer\\Bootstrap\\FieldRenderer\\';
/**
* Default constructor
*
* @param \Combodo\iTop\Form\Form $oForm
*/
public function __construct(Form $oForm = null)
{
parent::__construct($oForm);
@@ -41,4 +46,5 @@ class BsFormRenderer extends FormRenderer
$this->AddSupportedField('RadioField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('CheckboxField', 'BsSimpleFieldRenderer');
}
}

View File

@@ -31,11 +31,15 @@ use \Combodo\iTop\Renderer\RenderingOutput;
class BsSimpleFieldRenderer extends FieldRenderer
{
/**
* Returns a RenderingOutput for the FieldRenderer's Field
*
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function Render()
{
$oOutput = new RenderingOutput();
$sFieldClass = get_class($this->oField);
$sFieldId = 'field_' . spl_object_hash($this->oField);
$sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : '';
// TODO : Shouldn't we have a field type so we don't have to maintain FQN classname ?
@@ -48,10 +52,10 @@ class BsSimpleFieldRenderer extends FieldRenderer
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<input type="text" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('<input type="text" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
@@ -59,10 +63,10 @@ class BsSimpleFieldRenderer extends FieldRenderer
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<textarea id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" class="form-control" rows="8">' . $this->oField->GetCurrentValue() . '</textarea>');
$oOutput->AddHtml('<textarea id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" class="form-control" rows="8">' . $this->oField->GetCurrentValue() . '</textarea>');
$oOutput->AddHtml('</div>');
break;
@@ -70,10 +74,10 @@ class BsSimpleFieldRenderer extends FieldRenderer
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<select id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" ' . ( ($this->oField->GetMultipleValuesEnabled()) ? 'multiple' : '' ) . ' class="form-control">');
$oOutput->AddHtml('<select id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" ' . ( ($this->oField->GetMultipleValuesEnabled()) ? 'multiple' : '' ) . ' class="form-control">');
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)
@@ -88,7 +92,7 @@ class BsSimpleFieldRenderer extends FieldRenderer
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$sFieldType = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\RadioField') ? 'radio' : 'checkbox';
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '" id="' . $sFieldId . '">');
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '" id="' . $this->oField->GetGlobalId() . '">');
if ($this->oField->GetLabel() !== '')
{
@@ -112,7 +116,7 @@ class BsSimpleFieldRenderer extends FieldRenderer
break;
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '"/>');
$oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '"/>');
break;
}
}
@@ -134,10 +138,10 @@ class BsSimpleFieldRenderer extends FieldRenderer
$oOutput->AddHtml('<div class="form-group">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="form-control-static">' . $this->oField->GetCurrentValue() . '</div>');
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
@@ -149,10 +153,10 @@ class BsSimpleFieldRenderer extends FieldRenderer
$oOutput->AddHtml('<div class="form-group">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="form-control-static">' . $sFieldValue . '</div>');
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
}
@@ -168,11 +172,13 @@ class BsSimpleFieldRenderer extends FieldRenderer
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
$oOutput->AddJs(
<<<EOF
$("#$sFieldId").off("change").on("change", function(){
$(this).closest(".form_handler").trigger("field_change", {
id: $(this).attr("id"),
name: $(this).attr("name"),
value: $(this).val()
$("#{$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
@@ -183,11 +189,13 @@ EOF
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$oOutput->AddJs(
<<<EOF
$("#$sFieldId input").off("change").on("change", function(){
$(this).closest(".form_handler").trigger("field_change", {
id: $(this).closest("#$sFieldId").attr("id"),
name: $(this).attr("name"),
value: $(this).val()
$("#{$this->oField->GetGlobalId()} input").off("change").on("change", function(){
var me = this;
$(this).closest(".field_set").trigger("field_change", {
id: $(me).closest("#{$this->oField->GetGlobalId()}").attr("id"),
name: $(me).attr("name"),
value: $(me).val()
});
});
EOF
@@ -219,7 +227,7 @@ EOF
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$oOutput->AddJs(
<<<EOF
$("[data-field-id='{$this->oField->GetId()}']").form_field($sFormFieldOptions);
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field($sFormFieldOptions);
EOF
);
break;

View File

@@ -41,11 +41,19 @@ abstract class FieldRenderer
$this->oField = $oField;
}
/**
*
* @return string
*/
public function GetEndpoint()
{
return $this->sEndpoint;
}
/**
*
* @param string $sEndpoint
*/
public function SetEndpoint($sEndpoint)
{
$this->sEndpoint = $sEndpoint;

View File

@@ -22,6 +22,7 @@ namespace Combodo\iTop\Renderer;
use \Exception;
use \Dict;
use \Combodo\iTop\Form\Form;
use \Combodo\iTop\Form\Field\Field;
/**
* Description of FormRenderer
@@ -55,40 +56,73 @@ abstract class FormRenderer
$this->InitOutputs();
}
/**
*
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
return $this->oForm;
}
public function SetForm($oForm)
/**
*
* @param \Combodo\iTop\Form\Form $oForm
* @return \Combodo\iTop\Renderer\FormRenderer
*/
public function SetForm(Form $oForm)
{
$this->oForm = $oForm;
return $this;
}
/**
*
* @return string
*/
public function GetEndpoint()
{
return $this->sEndpoint;
}
/**
*
* @param string $sEndpoint
* @return \Combodo\iTop\Renderer\FormRenderer
*/
public function SetEndpoint($sEndpoint)
{
$this->sEndpoint = $sEndpoint;
return $this;
}
/**
*
* @return string
*/
public function GetBaseLayout()
{
return $this->sBaseLayout;
}
/**
*
* @param string $sBaseLayout
* @return \Combodo\iTop\Renderer\FormRenderer
*/
public function SetBaseLayout($sBaseLayout)
{
$this->sBaseLayout = $sBaseLayout;
return $this;
}
public function GetFieldRendererClass($oField)
/**
*
* @param \Combodo\iTop\Form\Field\Field $oField
* @return string
* @throws Exception
*/
public function GetFieldRendererClass(Field $oField)
{
if (array_key_exists(get_class($oField), $this->aSupportedFields))
{
@@ -120,7 +154,6 @@ abstract class FormRenderer
return $this->aOutputs;
}
/**
* Registers a Renderer class for the specified Field class.
*
@@ -140,12 +173,20 @@ abstract class FormRenderer
return $this;
}
/**
*
* @return \Combodo\iTop\Renderer\FormRenderer
*/
public function InitOutputs()
{
$this->aOutputs = array();
return $this;
}
/**
*
* @return array
*/
public function Render()
{
$this->InitOutputs();
@@ -257,4 +298,5 @@ abstract class FormRenderer
return $output;
}
}