/*
* Copyright 2016 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @private
* Class registering the field checkers and allowing to instantiate and manipulate them
*/
Ext.define('Ametys.form.ConfigurableFormPanel.FieldCheckersManager', {
/**
* @property {Ametys.form.ConfigurableFormPanel} _form the configurable form panel
* @private
*/
/**
* @property {Ametys.form.ConfigurableFormPanel.FieldChecker[]} _fieldCheckers The list of field checkers handled
* @private
*/
_fieldCheckers: [],
/**
* @property {Boolean} _isSuspended are the events currently suspended?
* @private
*/
_isSuspended: true,
/**
* @property {Number} _running the amount of tests that are currently running
* @private
*/
/**
* @property {Object} _testResults the results of the tests
* _testResults.successes the amount of successes
* _testResults.failures the amount of failures
* _testResults.notTested the amount of untested checkers
* _testResults.running the amount of tests currently running
* @private
*/
_testResults : {},
/**
* @cfg {Ametys.form.ConfigurableFormPanel} form The form panel the field checkers are attached to
*/
constructor: function(config)
{
this._form = config.form;
this._form.on('formready', Ext.bind(this._resumeEvents, this));
this._fieldCheckers = [];
this._running = 0;
},
/**
* Reset the warnings and the status of the field checkers
*/
reset: function()
{
Ext.Array.each(this._fieldCheckers, function(fieldChecker)
{
fieldChecker.reset();
});
// Reset the field checkers first, otherwise the warnings will not be reset
this._updateWarnings();
},
/**
* Register one or more field checkers
* @param {Ext.container.Container} container the container where to insert the field checker(s)
* @param {Object/Object[]} fieldCheckersCfg the configuration of the field checker(s) to register
* @param {String} path the path of the field checker(s)
* @param {Number} offset The offset of the field checker(s)
* @param {Number} roffset The right offset of the field checker(s)
* @param {Ext.form.Field} [field] when the field checker is graphically attached to a field, the field it is attached to, null otherwise
*/
addFieldCheckers: function(container, fieldCheckersCfg, path, offset, roffset, field)
{
if (fieldCheckersCfg.length > 1)
{
fieldCheckersCfg.sort(Ext.bind(this._compareByOrder, this));
}
Ext.Array.each(fieldCheckersCfg, function(fieldCheckerCfg){
if (this._form._isElement(fieldCheckerCfg))
{
fieldCheckerCfg = this._getFieldCheckerCfgFromXML(fieldCheckerCfg);
}
this._addFieldChecker(container, fieldCheckerCfg, path, offset, roffset, field);
}, this);
},
/**
* @private
* Register a field checker
* @param {Ext.container.Container} container the container where to insert the field checker
* @param {Object} fieldCheckerCfg The configuration of the field checker to add.
* @param {String} fieldCheckerCfg.id the id of the field checker
* @param {String} fieldCheckerCfg.class the class implementing the check
* @param {Number} fieldCheckerCfg.order the order of the field checker (if several are attached to the same location)
* @param {String} fieldCheckerCfg.small-icon-path the path to the small icon representing the field checker
* @param {String} fieldCheckerCfg.medium-icon-path the path to the medium icon representing the field checker
* @param {String} fieldCheckerCfg.large-icon-path the path to the large icon representing the field checker
* @param {String[]} fieldCheckerCfg.linked-fields the ids of the parameters used for the checking
* @param {String} fieldCheckerCfg.label the label of the field checker
* @param {String} fieldCheckerCfg.description the description of the field checker
* @param {String} path the path prefix of the field checker
* @param {Number} offset The offset of the field checker
* @param {Number} roffset The right offset of the field checker
* @param {Ext.form.Field} [field] when the field checker is graphically attached to a field, the field it is attached to, null otherwise
*/
_addFieldChecker: function(container, fieldCheckerCfg, path, offset, roffset, field)
{
var fieldChecker = new Ametys.form.ConfigurableFormPanel.FieldChecker(fieldCheckerCfg, field || container, path, fieldCheckerCfg.label, fieldCheckerCfg.description, this._form.getFieldNamePrefix(), this._form.defaultPathSeparator),
testButton = this._generateTestButton(fieldChecker, offset),
testContainer = this._generateTestContainer(fieldChecker, testButton, offset, roffset);
container.add(testContainer);
// Handle the case of repeaters : field checkers are created dynamically
var parentContainer = container.up();
if (parentContainer)
{
var parentParentContainer = parentContainer.up();
}
if (container.isRepeater || (parentContainer && parentContainer.isRepeater) || (parentParentContainer && parentParentContainer.isRepeater))
{
this._initializeFieldChecker(fieldChecker);
this.updateTestResults();
}
this._fieldCheckers.push(fieldChecker);
},
/**
* @private
* Create a field checker object configuration from an XML configuration
* @param {HTMLElement} fieldChecker the field checker's XML configuration
*/
_getFieldCheckerCfgFromXML: function(fieldChecker)
{
return {
'id': Ext.dom.Query.selectValue("> id", fieldChecker),
'small-icon-path': Ext.dom.Query.selectValue("> small-icon-path", fieldChecker),
'medium-icon-path': Ext.dom.Query.selectValue("> medium-icon-path", fieldChecker),
'large-icon-path': Ext.dom.Query.selectValue("> large-icon-path", fieldChecker),
'icon-glpyh': Ext.dom.Query.selectValue("> icon-glyph", fieldChecker),
'linked-fields': Ext.JSON.decode(Ext.dom.Query.selectValue("> linked-fields", fieldChecker)),
'label': Ext.dom.Query.selectValue("> label", fieldChecker),
'description': Ext.dom.Query.selectValue("> description", fieldChecker),
'order': Ext.dom.Query.selectValue("> order", fieldChecker)
};
},
/**
* @private
* Compare two field checkers with their order
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} a the first field checker
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} b the second field checker
*/
_compareByOrder: function(a, b)
{
var aOrder = this._form._isElement(a) ? Ext.dom.Query.selectValue('order', a) : a.order;
var bOrder = this._form._isElement(b) ? Ext.dom.Query.selectValue('order', b) : b.order;
var comparison = 0;
if (aOrder && bOrder)
{
comparison = aOrder - bOrder;
}
return comparison != 0 ? comparison : 1;
},
/**
* Initialize the listeners on linked fields
*/
initializeFieldCheckers: function()
{
// Field checkers listeners
Ext.Array.each(this._fieldCheckers, function(fieldChecker){
if (!fieldChecker.isInitialized())
{
this._initializeFieldChecker(fieldChecker);
}
}, this);
if (!Ext.isEmpty(this._fieldCheckers))
{
// Initialize test results if there is at least one field checker
this._form.on({
// Update test results after the field checkers are created
formready: {fn: this.updateTestResults, scope: this, single: true, order: 'after'}
});
}
},
/**
* @private
* Initialization of a single field checker
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker to initialize
*/
_initializeFieldChecker: function (fieldChecker)
{
var linkedFields = [],
linkedFieldsLabels = [];
var linkedFieldsPaths = fieldChecker.getLinkedFieldsPaths();
Ext.Array.each(linkedFieldsPaths, function(linkedFieldPath) {
var linkedField = this._form.getForm().findField(linkedFieldPath);
var isHidden = linkedField.isHidden();
linkedFields.push(linkedField);
if (!isHidden)
{
// Remove the starting or trailing '*' character
var fieldLabel = linkedField.getFieldLabel();
if (Ext.String.startsWith(fieldLabel, '*'))
{
fieldLabel = fieldLabel.substr(1).trim();
}
else if (Ext.String.endsWith(fieldLabel, '*'))
{
fieldLabel = fieldLabel.substr(0, fieldLabel.length - 1).trim();
}
linkedFieldsLabels.push(fieldLabel);
linkedField.on('change', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('errorchange', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('disable', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('enable', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('hide', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('show', Ext.bind(this._updateTestButton, this, [fieldChecker], false));
linkedField.on('warningchange', Ext.bind(this._form._updateTabsStatus, this._form, [false], false));
}
}, this);
// Store the list of linked fields and their labels
fieldChecker.setLinkedFields(linkedFields);
fieldChecker.setLinkedFieldsLabels(linkedFieldsLabels.length > 1 ? linkedFieldsLabels.join(', ') : "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_NO_LINKED_FIELD}}");
if (!this._form.isFormReady())
{
// Update the test buttons once as soon as the form is ready
this._form.on({
formready: {fn: Ext.bind(this._updateTestButton, this, [fieldChecker], false), scope: this, single: true}
});
}
else if (this._form._addingRepeaterEntry)
{
this._form.on({
// Update the test buttons once as soon as the repeater entry is ready
repeaterentryready: {fn: Ext.bind(this._updateTestButton, this, [fieldChecker], false), scope: this, single: true}
});
}
else
{
this._updateTestButton(fieldChecker);
}
// Complete initialization: the initialization of field checkers on repeater items is dynamic, and we don't want those
// to be initialized twice
fieldChecker.setInitialized(true);
},
/**
* @private
* Generates the button launching the tests on the corresponding location
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker
* @param {Number} offset the field checker's offset
*/
_generateTestButton: function(fieldChecker, offset)
{
return Ext.create('Ext.button.Button', {
id: Ext.id(),
text: fieldChecker.label,
textAlign: 'left',
iconCls: fieldChecker.iconGlyph + (fieldChecker.iconDecorator ? ' ' + fieldChecker.iconDecorator : ''),
icon: Ext.isEmpty(fieldChecker.iconGlyph) ? Ametys.CONTEXT_PATH + fieldChecker.smallIconPath : null,
cls: 'param-checker-button',
width: Ametys.form.ConfigurableFormPanel.LABEL_WIDTH - offset + Ametys.form.ConfigurableFormPanel.FIELD_MINWIDTH,
border: true,
fieldChecker: fieldChecker,
handler: function(button, event)
{
if (button._hasCheckRunning == null || button._hasCheckRunning === false)
{
this.check([fieldChecker], false);
}
},
scope: this
});
},
/**
* @private
* Generates the container that wraps the test button and the ametys description
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker
* @param {Ext.button.Button} testButton the test button
* @param {Number} offset the offset of the field checker
* @param {Number} roffset the right offset of the field checker
* @return {Ext.container.Container} the container with the test button and the help box
*/
_generateTestContainer: function(fieldChecker, testButton, offset, roffset)
{
var items = [],
me = this;
items.push({
xtype: 'tbspacer',
flex: 1
});
// the button itself
items.push(testButton);
fieldChecker.setButtonId(testButton.getId());
// component initially hidden that will reflect the status of the check
var fieldCheckerStatusCmpId = Ext.id();
fieldChecker.setStatusCmpId(fieldCheckerStatusCmpId);
items.push({
xtype: 'component',
id: fieldCheckerStatusCmpId,
hidden: true,
cls: 'param-checker-status'
});
// the description
var helpBoxId = Ext.id();
fieldChecker.setHelpBoxId(helpBoxId);
items.push({
xtype: 'component',
id: helpBoxId,
cls: "ametys-description",
listeners: {
'render': function() {
Ext.tip.QuickTipManager.register(me._getAmetysDescriptionTooltipConfig(fieldChecker, this.getEl()));
},
'destroy': function() {
Ext.tip.QuickTipManager.unregister(this.getEl());
}
}
});
return Ext.create('Ext.Container', {
layout: {
type: 'hbox',
align: 'stretch',
pack: 'start'
},
style: 'margin-right:' + Math.max(this._form.maxNestedLevel * Ametys.form.ConfigurableFormPanel.OFFSET_FIELDSET - roffset, 0) + 'px',
cls: 'param-checker-container',
items: items
});
},
/**
* Updates the test results panel in the actions' tooltips
* Fires a 'testresultschange' event if the test results have changed
*/
updateTestResults: function()
{
var notTested = 0,
failures = 0,
successes = 0;
Ext.Array.each(this._fieldCheckers, function(fieldChecker){
var status = fieldChecker.getStatus();
switch (status)
{
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_SUCCESS:
successes += 1;
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE:
failures += 1;
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_NOT_TESTED:
notTested += 1;
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_DEACTIVATED:
notTested += 1;
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_WARNING:
notTested += 1;
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_HIDDEN: // ignore
break;
default:
throw 'Unknown status ' + status;
}
});
this._testResults = {successes: successes, failures: failures, notTested: notTested, running: this._running};
this._form.fireEvent('testresultschange');
},
/**
* @private
* Listener function invoked to resume the events as soon as the {@link Ametys.form.ConfigurableFormPanel} is ready
*/
_resumeEvents: function()
{
this._isSuspended = false;
},
/**
* @private
* Run the update routine on the test button if the attached {@link Ametys.form.ConfigurableFormPanel} is ready.
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker to update
*/
_updateTestButton: function(fieldChecker)
{
if (this._isSuspended)
{
return;
}
Ext.suspendLayouts();
var isDeactivated = this._isDeactivated(fieldChecker),
mustBeHidden = this._mustBeHidden(fieldChecker),
statusCmp = Ext.getCmp(fieldChecker.statusCmpId),
btn = Ext.getCmp(fieldChecker.buttonId);
var oldStatusCmpCls = statusCmp.cls,
oldStatusCmpVisible = statusCmp.isVisible();
if (fieldChecker.getStatus() != Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_NOT_TESTED)
{
if (isDeactivated)
{
statusCmp.setVisible(false);
fieldChecker.setStatus(Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_NOT_TESTED);
}
else
{
btn.enable();
btn.up('container').setVisible(true);
statusCmp.removeCls(['success', 'failure', 'warning']);
statusCmp.setVisible(false);
if (fieldChecker.getStatus() != Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_DEACTIVATED)
{
statusCmp.addCls('warning');
statusCmp.setVisible(true);
fieldChecker.setStatus(Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_WARNING);
}
// update the tooltip of the status component
this._updateStatusCmpTooltip(fieldChecker);
// update the warnings
this._updateWarnings([fieldChecker]);
// update the tabs of the attached form
this._form._updateTabsStatus();
}
}
// We want to be able to deactivate a field checker even when its status is 'not tested'
if (isDeactivated)
{
btn.disable();
btn.up('container').setHidden(mustBeHidden);
fieldChecker.setStatus(Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_DEACTIVATED);
// Update the test results : a deactivated field checker is considered as not tested.
this.updateTestResults();
if (!mustBeHidden)
{
statusCmp.removeCls(['success', 'failure']);
statusCmp.addCls('warning');
statusCmp.setVisible(true);
}
// update the tooltip of the status component
this._updateStatusCmpTooltip(fieldChecker);
}
var flush = oldStatusCmpCls != statusCmp.cls && oldStatusCmpVisible != statusCmp.isVisible();
// Do not flush the layouts if the rendering of the field checker hasn't changed
Ext.resumeLayouts(flush);
},
/**
* @private
* Test whether the given field checker is activated or not
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker to test
* @return true if the field checker is deactivated, false otherwise
*/
_isDeactivated: function(fieldChecker)
{
var linkedFields = fieldChecker.getLinkedFields(),
isDeactivated = true;
Ext.Array.each(linkedFields, function(linkedField) {
// check if all linked fields are disabled
if (!linkedField.isDisabled())
{
isDeactivated = false;
return false;
}
});
return isDeactivated;
},
/**
* @private
* Test whether the given field checker has to be hidden
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker to test
* @return true if the field checker must be hidden, false otherwise
*/
_mustBeHidden: function(fieldChecker)
{
var linkedFields = fieldChecker.getLinkedFields(),
mustBeHidden = true;
Ext.Array.each(linkedFields, function(linkedField) {
// check if all linked fields are hidden
if (!linkedField.isHidden())
{
mustBeHidden = false;
return false;
}
});
return mustBeHidden;
},
/**
* @private
* Test whether the given field checker has an invalid linked field
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker to test
* @return true if the field checker has at least one invalid linked field, false otherwise
*/
_hasInvalidField: function(fieldChecker)
{
var linkedFields = fieldChecker.getLinkedFields(),
hasInvalidField = false;
Ext.Array.each(linkedFields, function(linkedField)
{
if (!linkedField.isDisabled() && linkedField.isVisible() && !Ext.isEmpty(linkedField.getActiveErrors()))
{
hasInvalidField = true;
return false;
}
});
return hasInvalidField;
},
/**
* @private
* Update the warnings on fields
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker[]} fieldCheckers the list of field checkers to update. Can be null
*/
_updateWarnings: function(fieldCheckers)
{
fieldCheckers = Ext.isEmpty(fieldCheckers) ? this._fieldCheckers : fieldCheckers;
Ext.suspendLayouts();
var flushLayouts = false;
Ext.Array.each(fieldCheckers, function(fieldChecker){
var button = Ext.getCmp(fieldChecker.buttonId),
helpBox = Ext.getCmp(fieldChecker.helpBoxId),
notTested = fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_NOT_TESTED,
success = fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_SUCCESS,
failure = fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE,
warningMsg = "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_WARNING_TEXT_BEGINNING}}" + fieldChecker.label + "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_WARNING_TEXT_END}}";
Ext.Array.each(fieldChecker.getLinkedFields(), function(linkedField){
linkedField._warnings = linkedField._warnings || {};
var activeWarnings = linkedField.getActiveWarnings();
var oldActiveWarnings = Ext.clone(activeWarnings);
if (success || notTested)
{
Ext.Array.remove(activeWarnings, warningMsg);
linkedField._warnings[fieldChecker.id] = null;
linkedField.markWarning(activeWarnings);
}
else if (failure)
{
if (!linkedField._warnings[fieldChecker.id])
{
linkedField._warnings[fieldChecker.id] = warningMsg;
activeWarnings.push(warningMsg);
}
linkedField.markWarning(activeWarnings);
}
if (!Ext.Array.equals(oldActiveWarnings, activeWarnings))
{
flushLayouts = true;
}
});
});
// Do not flush the pending layouts if the warnings did not change
Ext.resumeLayouts(flushLayouts);
},
/**
* @private
* Updates the tooltip for the status component of the given field checker
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker
*/
_updateStatusCmpTooltip: function(fieldChecker)
{
var target = Ext.getCmp(fieldChecker.statusCmpId).getEl();
tooltipCfg =
{
target: target,
inribbon: false
};
switch (fieldChecker.getStatus())
{
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE:
tooltipCfg.text = '<strong>{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_STATUS_FAILURE}}</strong> ' + fieldChecker.errorMsg
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_DEACTIVATED:
tooltipCfg.text = "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_TOOLTIP_DEACTIVATED_MESSAGE}}";
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_WARNING:
tooltipCfg.text = "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_STATUS_WARNING}}" +
(!fieldChecker.errorMsg ? "" :
" </br></br>" +
"{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_TOOLTIP_LAST_MESSAGE}} " + "\"" + fieldChecker.errorMsg + "\"");
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_SUCCESS: // no tooltip
tooltipCfg = {};
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_NOT_TESTED: // no tooltip
tooltipCfg = {};
break;
case Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_HIDDEN: // no tooltip
tooltipCfg = {};
break;
default:
throw 'Unknown status ' + status;
}
if (fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_WARNING || fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_DEACTIVATED)
{
tooltipCfg.cls = 'x-tip-form-warning';
tooltipCfg.image = Ametys.getPluginResourcesPrefix('core-ui') + '/themes/theme-ametys-admin/images/form/field/warning.png';
tooltipCfg.imageHeight = 17;
tooltipCfg.imageWidth = 17;
}
else if (fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE)
{
tooltipCfg.cls = 'x-tip-form-invalid';
tooltipCfg.image = Ametys.getPluginResourcesPrefix('core-ui') + '/themes/theme-ametys-admin/images/form/exclamation.png';
tooltipCfg.imageHeight = 17;
tooltipCfg.imageWidth = 17;
}
if (!Ext.Object.isEmpty(tooltipCfg))
{
Ext.tip.QuickTipManager.register(tooltipCfg);
}
else
{
Ext.tip.QuickTipManager.unregister(target);
}
},
/**
* @private
* Get the tooltip configuration for a given field checker's ametys description
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker} fieldChecker the field checker
* @param {Ext.dom.Element} target the target element of the tooltip
* @return {Object} the configuration object for the tooltip
*/
_getAmetysDescriptionTooltipConfig: function(fieldChecker, target)
{
var tooltipCfg =
{
target: target,
title: fieldChecker.label,
inribbon: false,
text: '<emphasis>' + fieldChecker.description + '</emphasis><br /><br />'
+ "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_TOOLTIP_TESTED_PARAMS}}" + fieldChecker.linkedFieldsLabels
};
if (fieldChecker.iconGlyph)
{
tooltipCfg.glyphIcon = fieldChecker.iconGlyph;
tooltipCfg.iconDecorator = fieldChecker.iconDecorator;
}
else if (fieldChecker.largeIconPath)
{
tooltipCfg.image = Ametys.CONTEXT_PATH + fieldChecker.largeIconPath;
}
return tooltipCfg;
},
/**
* Calls the server-side with the values of the linked fields.
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker[]} fieldCheckers the field checkers to use, can be null to run all the tests
* @param {Boolean} displayErrors true if the errors have to be displayed at the end of the tests
* @param {Function} [callback] the optional callback for this function.
* @param {Boolean} [forceTest=true] to replay even successful tests
*/
check: function(fieldCheckers, displayErrors, callback, forceTest)
{
var form = this._form;
forceTest = forceTest !== false ? true : false;
fieldCheckers = fieldCheckers != null ? fieldCheckers : this._fieldCheckers;
// Add information concerning the involved field checkers
var fieldCheckersInfo = {};
Ext.Array.each(fieldCheckers, function(fieldChecker) {
this._running++;
if (forceTest || fieldChecker.getStatus() != Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_SUCCESS)
{
if (!this._hasInvalidField(fieldChecker))
{
// Reset the error message before the test
fieldChecker.setErrorMsg(null);
var btn = Ext.getCmp(fieldChecker.buttonId);
btn._hasCheckRunning = true;
btn.getEl().mask("");
var fieldCheckerId = fieldChecker.id;
fieldCheckersInfo[fieldCheckerId] = {};
var rawTestValues = [],
testParamsNames = [];
// Add the names and the raw values of the linked parameters
Ext.Array.each(fieldChecker.getLinkedFields(), function(linkedField){
rawTestValues.push(linkedField.getValue());
testParamsNames.push(linkedField.getName());
});
fieldCheckersInfo[fieldCheckerId].rawTestValues = rawTestValues;
fieldCheckersInfo[fieldCheckerId].testParamsNames = testParamsNames;
}
else
{
fieldChecker.setErrorMsg("{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_INVALID_LINKED_FIELD}}");
}
}
}, this);
// Don't run tests if there is no test to run... execute the check callback routine directly instead
if (Ext.Object.isEmpty(fieldCheckersInfo))
{
this._checkCb({}, true, {}, fieldCheckers, callback, displayErrors);
}
else
{
// Inform the controllers that tests are running
this.updateTestResults();
// Server call
Ext.Ajax.request({
url: this._form.getTestURL(),
params: "fieldCheckersInfo=" + encodeURIComponent(Ext.JSON.encode(this._form.testHandler(fieldCheckers, fieldCheckersInfo))),
callback: Ext.bind(this._checkCb, this, [fieldCheckers, callback, displayErrors], true)
});
}
},
/**
* @private
* Callback function invoked upon reception of the server's response
* @param {Object} options the {@link Ext.Ajax#request} call configuration
* @param {Object} options.params the call parameters
* @param {boolean} success true if the request succeeded, false otherwise
* @param {Object} response the server's response
* @param {Ametys.form.ConfigurableFormPanel.FieldChecker[]} fieldCheckers the field checkers
* @param {Function} callback the optional callback for this function.
* @param {Boolean} displayErrors true if the errors have to be displayed at then end of the tests
*/
_checkCb: function(options, success, response, fieldCheckers, callback, displayErrors)
{
if (!success)
{
Ametys.log.ErrorDialog.display({
title: "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_SERVER_CALL_ERROR_TITLE}}",
text: "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_SERVER_CALL_ERROR_TEXT}}",
category: this.self.getName()
});
// Re-enable buttons and reinitialize test buttons
for (var i = 0; i < fieldCheckers.length; i++)
{
var fieldChecker = fieldCheckers[i];
var btn = Ext.getCmp(fieldChecker.buttonId);
btn.getEl().unmask();
btn._hasCheckRunning = false;
this._running--;
}
return;
}
var form = this._form,
result = response.responseXML,
errorMessages = Ext.dom.Query.selectDirectElements("* > *", result); // We cannot use a better selector because of possible "." in the tagName.
errors = 0;
// Server's response handler
Ext.Array.each(fieldCheckers, function(fieldChecker) {
this._running--;
var btn = Ext.getCmp(fieldChecker.buttonId),
helpBox = Ext.getCmp(fieldChecker.helpBoxId),
statusCmp = Ext.getCmp(fieldChecker.statusCmpId);
// Compute the corresponding error message
Ext.Array.each(errorMessages, function(errorMessage){
if (errorMessage.tagName == fieldChecker.id)
{
fieldChecker.setErrorMsg(errorMessage.childNodes[0].textContent);
}
});
btn.getEl().unmask();
btn._hasCheckRunning = false;
statusCmp.setVisible(true);
statusCmp.removeCls(['failure', 'warning', 'success']);
// Update the field checker's component
if (fieldChecker.getErrorMsg() == null)
{
statusCmp.addCls('success');
fieldChecker.setStatus(Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_SUCCESS);
}
else
{
errors++;
statusCmp.addCls('failure');
fieldChecker.setStatus(Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE);
}
this._updateStatusCmpTooltip(fieldChecker);
}, this);
this.updateTestResults();
this._form._updateTabsStatus(displayErrors);
this._updateWarnings(fieldCheckers);
if (callback && typeof callback === 'function')
{
callback(errors == 0);
}
if (displayErrors)
{
this._displayErrorDialog();
}
},
/**
* @private
* Displays the error dialogs at the end of a check
*/
_displayErrorDialog: function()
{
var nbErrors = 0,
mainFormContainerId = this._form.getFormContainer().getId();
details = '';
for (var i = 0; i < this._fieldCheckers.length; i++)
{
var fieldChecker = this._fieldCheckers[i];
if (Ext.getCmp(fieldChecker.buttonId).isVisible() && fieldChecker.getStatus() == Ametys.form.ConfigurableFormPanel.FieldChecker.STATUS_FAILURE)
{
var fullLabel = "";
nbErrors += 1;
if (fieldChecker.uiComponent.getId() == mainFormContainerId)
{
fullLabel = "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_GLOBAL_FIELD_CHECKER}}";
}
else
{
fullLabel = this._form._getFullLabel(fieldChecker.uiComponent);
}
details += fullLabel + ":\n\t" + fieldChecker.errorMsg + "\n\n";
}
}
if (nbErrors > 0)
{
Ametys.log.ErrorDialog.display({
title: "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_ERROR}}",
text: nbErrors > 1 ? nbErrors + " {{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_ERROR_TEXT}}" : "{{i18n PLUGINS_CORE_UI_CONFIGURABLE_FORM_FIELD_CHECKER_SINGLE_ERROR_TEXT}}",
category: this.self.getName(),
details: details
});
}
}
});