mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-19 16:48:42 +02:00
The FormSelectorField now has its own widget to properly cope with its "subfields" in "property sheet" mode.
SVN:trunk[3458]
This commit is contained in:
@@ -255,9 +255,21 @@ class DesignerForm
|
||||
$sAutoApply = $oField->IsAutoApply() ? 'true' : 'false';
|
||||
$sHandlerEquals = $oField->GetHandlerEquals();
|
||||
$sHandlerGetValue = $oField->GetHandlerGetValue();
|
||||
|
||||
$sWidgetClass = $oField->GetWidgetClass();
|
||||
$sJSExtraParams = '';
|
||||
if (count($oField->GetWidgetExtraParams()) > 0)
|
||||
{
|
||||
$aExtraParams = array();
|
||||
foreach($oField->GetWidgetExtraParams() as $key=> $value)
|
||||
{
|
||||
$aExtraParams[] = "'$key': ".json_encode($value);
|
||||
}
|
||||
$sJSExtraParams = ', '.implode(', ', $aExtraParams);
|
||||
}
|
||||
$this->AddReadyScript(
|
||||
<<<EOF
|
||||
$('#row_$sFieldId').property_field({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams });
|
||||
$('#row_$sFieldId').$sWidgetClass({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams $sJSExtraParams });
|
||||
EOF
|
||||
);
|
||||
}
|
||||
@@ -664,6 +676,7 @@ class DesignerFormField
|
||||
protected $bAutoApply;
|
||||
protected $aCSSClasses;
|
||||
protected $bDisplayed;
|
||||
protected $aWidgetExtraParams;
|
||||
|
||||
public function __construct($sCode, $sLabel, $defaultValue)
|
||||
{
|
||||
@@ -675,6 +688,7 @@ class DesignerFormField
|
||||
$this->bAutoApply = false;
|
||||
$this->aCSSClasses = array();
|
||||
$this->bDisplayed = true;
|
||||
$this->aWidgetExtraParams = array();
|
||||
}
|
||||
|
||||
public function GetCode()
|
||||
@@ -728,6 +742,16 @@ class DesignerFormField
|
||||
return $this->oForm->GetFieldId($this->sCode);
|
||||
}
|
||||
|
||||
public function GetWidgetClass()
|
||||
{
|
||||
return 'property_field';
|
||||
}
|
||||
|
||||
public function GetWidgetExtraParams()
|
||||
{
|
||||
return $this->aWidgetExtraParams;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -1402,6 +1426,11 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
$this->aSubForms = array();
|
||||
}
|
||||
|
||||
public function GetWidgetClass()
|
||||
{
|
||||
return 'selector_property_field';
|
||||
}
|
||||
|
||||
public function AddSubForm($oSubForm, $sLabel, $sValue)
|
||||
{
|
||||
$idx = count($this->aSubForms);
|
||||
@@ -1519,8 +1548,8 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
|
||||
if ($sRenderMode == 'property')
|
||||
{
|
||||
$this->aWidgetExtraParams['data_selector'] = $sSelector;
|
||||
$sSelector = $this->oForm->GetHierarchyPath().'/'.$this->sCode.$this->oForm->GetSuffix();
|
||||
$oP->add_ready_script("InitFormSelectorField('$sId', '$sSelector');");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -16,7 +16,8 @@ $(function()
|
||||
submit_parameters: {operation: 'async_action'},
|
||||
do_apply: null,
|
||||
do_cancel: null,
|
||||
auto_apply: false
|
||||
auto_apply: false,
|
||||
can_apply: true
|
||||
},
|
||||
|
||||
// the constructor
|
||||
@@ -49,7 +50,14 @@ $(function()
|
||||
if (this.bModified)
|
||||
{
|
||||
this.element.addClass("itop-property-field-modified");
|
||||
this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''});
|
||||
if (this.options.can_apply)
|
||||
{
|
||||
this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: 'hidden'});
|
||||
}
|
||||
this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: ''});
|
||||
}
|
||||
else
|
||||
@@ -93,12 +101,16 @@ $(function()
|
||||
else
|
||||
{
|
||||
this.bModified = true;
|
||||
if (this.options.auto_apply)
|
||||
if (this.options.auto_apply && this.options.can_apply)
|
||||
{
|
||||
this._do_apply();
|
||||
}
|
||||
}
|
||||
this._refresh();
|
||||
if (this.options.parent_selector)
|
||||
{
|
||||
$(this.options.parent_selector).trigger('subitem_changed');
|
||||
}
|
||||
},
|
||||
_equals: function( value1, value2 )
|
||||
{
|
||||
@@ -130,10 +142,18 @@ $(function()
|
||||
return this.options.get_field_value();
|
||||
}
|
||||
},
|
||||
get_field_name: function()
|
||||
{
|
||||
return $('#'+this.options.field_id, this.element).attr('name');
|
||||
},
|
||||
_get_committed_value: function()
|
||||
{
|
||||
return { name: $('#'+this.options.field_id, this.element).attr('name'), value: this.value };
|
||||
},
|
||||
_get_current_value: function()
|
||||
{
|
||||
return { name: $('#'+this.options.field_id, this.element).attr('name'), value: this._get_field_value() };
|
||||
},
|
||||
_do_apply: function()
|
||||
{
|
||||
if (this.options.parent_selector)
|
||||
@@ -196,6 +216,10 @@ $(function()
|
||||
this._refresh();
|
||||
oField.trigger('reverted', {type: 'designer', previous_value: this.value });
|
||||
oField.trigger('validate');
|
||||
if (this.options.parent_selector)
|
||||
{
|
||||
$(this.options.parent_selector).trigger('subitem_changed');
|
||||
}
|
||||
}
|
||||
},
|
||||
_do_submit: function()
|
||||
@@ -228,6 +252,190 @@ $(function()
|
||||
_is_visible: function()
|
||||
{
|
||||
return this.element.is(':visible');
|
||||
},
|
||||
mark_as_applied: function()
|
||||
{
|
||||
this.bModified = false;
|
||||
this.previous_value = this.value;
|
||||
this.value = this._get_field_value();
|
||||
this._refresh();
|
||||
},
|
||||
validate: function()
|
||||
{
|
||||
var oField = $('#'+this.options.field_id, this.element);
|
||||
oField.trigger('validate');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where "itop" is the namespace,
|
||||
// "selector_property_field" the widget name
|
||||
$.widget( "itop.selector_property_field", $.itop.property_field,
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
parent_selector: null,
|
||||
field_id: '',
|
||||
get_field_value: null,
|
||||
equals: null,
|
||||
submit_to: 'index.php',
|
||||
submit_parameters: {operation: 'async_action'},
|
||||
do_apply: null,
|
||||
do_cancel: null,
|
||||
auto_apply: false,
|
||||
can_apply: true,
|
||||
data_selector: ''
|
||||
},
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
var me = this;
|
||||
this._superApply();
|
||||
|
||||
this.element
|
||||
.addClass( "itop-selector-property-field" );
|
||||
|
||||
$('#'+this.options.field_id).bind('reverted init', function() {
|
||||
me._update_subform();
|
||||
}).trigger('init'); // initial refresh
|
||||
|
||||
this.element.bind('subitem_changed', function() {
|
||||
me._on_subitem_changed();
|
||||
});
|
||||
},
|
||||
_update_subform: function()
|
||||
{
|
||||
var sSelector = this.options.data_selector;
|
||||
var me = this;
|
||||
|
||||
// Mark all the direct children as hidden
|
||||
$('tr[data-selector="'+sSelector+'"]').attr('data-state', 'hidden');
|
||||
// Mark the selected one as visible
|
||||
var sSelectedHierarchy = sSelector+'-'+$('#'+this.options.field_id).val();
|
||||
$('tr[data-path="'+sSelectedHierarchy+'"]').attr('data-state', 'visible');
|
||||
|
||||
// Show all items behind the current one
|
||||
$('tr[data-path^="'+sSelector+'"]').show();
|
||||
// Hide items behind the current one as soon as it is behind a hidden node (or itself is marked as hidden)
|
||||
$('tr[data-path^="'+sSelector+'"][data-state="hidden"]').each(function() {
|
||||
$(this).hide();
|
||||
var sPath = $(this).attr('data-path');
|
||||
$('tr[data-path^="'+sPath+'/"]').hide();
|
||||
});
|
||||
|
||||
$('tr[data-path^="'+sSelector+'"]').each(function() {
|
||||
if($(this).is(':visible'))
|
||||
{
|
||||
var oPropField = $(this).closest('.itop-property-field');
|
||||
oPropField.property_field('option', {can_apply: !me.bModified, parent_selector: '#'+me.element.attr('id') });
|
||||
oPropField.property_field('validate');
|
||||
}
|
||||
});
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
this.element.removeClass( "itop-selector-property-field" );
|
||||
this._superApply();
|
||||
},
|
||||
_on_change: function()
|
||||
{
|
||||
var new_value = this._get_field_value();
|
||||
if (this._equals(new_value, this.value))
|
||||
{
|
||||
this.bModified = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bModified = true;
|
||||
}
|
||||
|
||||
this._update_subform();
|
||||
|
||||
if (this.options.auto_apply && this.options.can_apply)
|
||||
{
|
||||
this._do_apply();
|
||||
}
|
||||
this._on_subitem_changed(); // initial validation
|
||||
this._refresh();
|
||||
},
|
||||
_do_apply: function()
|
||||
{
|
||||
this._superApply();
|
||||
this._update_subform();
|
||||
},
|
||||
_do_submit: function()
|
||||
{
|
||||
var oData = {};
|
||||
this.element.closest('form').find(':input[type=hidden]').each(function()
|
||||
{
|
||||
// Hidden form fields
|
||||
oData[$(this).attr('name')] = $(this).val();
|
||||
});
|
||||
|
||||
var sSelector = this.options.data_selector;
|
||||
var me = this;
|
||||
var aUpdated = [];
|
||||
$('tr[data-path^="'+sSelector+'"]').each(function() {
|
||||
if($(this).is(':visible'))
|
||||
{
|
||||
var sName = $(this).closest('.itop-property-field').property_field('mark_as_applied').property_field('get_field_name');
|
||||
if (typeof sName == 'string')
|
||||
{
|
||||
aUpdated.push(sName);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.element.closest('form').find('.itop-property-field').each(function()
|
||||
{
|
||||
var oWidget = $(this).data('itopProperty_field');
|
||||
if (!oWidget)
|
||||
{
|
||||
// try the form selector widget
|
||||
oWidget = $(this).data('itopSelector_property_field');
|
||||
}
|
||||
if (oWidget && oWidget._is_visible())
|
||||
{
|
||||
var oVal = oWidget._get_committed_value();
|
||||
oData[oVal.name] = oVal.value;
|
||||
}
|
||||
});
|
||||
|
||||
var oPostedData = this.options.submit_parameters;
|
||||
var sName = $('#'+this.options.field_id, this.element).attr('name');
|
||||
oPostedData.params = oData;
|
||||
oPostedData.params.updated = [];
|
||||
aUpdated.push(sName); // several fields updated in this case
|
||||
oPostedData.params.updated = aUpdated;
|
||||
oPostedData.params.previous_values = {};
|
||||
oPostedData.params.previous_values[sName] = this.previous_value; // pass also the previous value(s)
|
||||
|
||||
$.post(this.options.submit_to, oPostedData, function(data)
|
||||
{
|
||||
$('#prop_submit_result').html(data);
|
||||
});
|
||||
},
|
||||
_on_subitem_changed : function()
|
||||
{
|
||||
sFormId = this.element.closest('form').attr('id');
|
||||
oFormValidation[sFormId] = [];
|
||||
this.options.can_apply = true;
|
||||
var sSelector = this.options.data_selector
|
||||
$('tr[data-path^="'+sSelector+'"]').each(function() {
|
||||
if($(this).is(':visible'))
|
||||
{
|
||||
var oPropField = $(this).closest('.itop-property-field');
|
||||
oPropField.property_field('validate');
|
||||
}
|
||||
});
|
||||
this.options.can_apply = (oFormValidation[sFormId].length == 0); // apply allowed only if no error
|
||||
this._refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -465,22 +673,3 @@ function AddSubForm(sId, sUrl, oParams)
|
||||
});
|
||||
}
|
||||
|
||||
function InitFormSelectorField(sId, sSelector)
|
||||
{
|
||||
$('#'+sId).bind('change reverted init', function() {
|
||||
// Mark all the direct children as hidden
|
||||
$('tr[data-selector="'+sSelector+'"]').attr('data-state', 'hidden');
|
||||
// Mark the selected one as visible
|
||||
var sSelectedHierarchy = sSelector+'-'+this.value;
|
||||
$('tr[data-path="'+sSelectedHierarchy+'"]').attr('data-state', 'visible');
|
||||
|
||||
// Show all items behind the current one
|
||||
$('tr[data-path^="'+sSelector+'"]').show();
|
||||
// Hide items behind the current one as soon as it is behind a hidden node (or itself is marked as hidden)
|
||||
$('tr[data-path^="'+sSelector+'"][data-state="hidden"]').each(function() {
|
||||
$(this).hide();
|
||||
var sPath = $(this).attr('data-path');
|
||||
$('tr[data-path^="'+sPath+'/"]').hide();
|
||||
});
|
||||
}).trigger('init'); // initial refresh
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user