Implement some basic client-side validation (required)

This commit is contained in:
Nathan Gray 2013-06-26 20:50:10 +00:00
parent a0cba996a0
commit 0c6f70005a
11 changed files with 81 additions and 29 deletions

View File

@ -112,7 +112,7 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned,
.addClass("message")
.addClass(_type)
.addClass(_floating ? "floating" : "")
.text(_text);
.text(_text.valueOf() + "");
// Decide whether to prepend or append the div
if (_prepend)
@ -152,10 +152,11 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned,
{
var surr = this.getSurroundings();
var self = this;
var messageDiv = this._messageDiv;
self._messageDiv = null;
var _done = function() {
surr.removeDOMNode(self._messageDiv[0]);
self._messageDiv = null;
surr.removeDOMNode(messageDiv[0]);
// Update the surroundings manager
if (!_noUpdate)
@ -167,7 +168,7 @@ var et2_baseWidget = et2_DOMWidget.extend(et2_IAligned,
// Either fade out or directly call the function which removes the div
if (_fade)
{
this._messageDiv.fadeOut("fast", _done);
messageDiv.fadeOut("fast", _done);
}
else
{

View File

@ -25,10 +25,10 @@
*
* @augments et2_valueWidget
*/
var et2_inputWidget = et2_valueWidget.extend(et2_IInput,
var et2_inputWidget = et2_valueWidget.extend([et2_IInput,et2_ISubmitListener],
{
attributes: {
"required": {
"needed": {
"name": "Required",
"default": false,
"type": "boolean",
@ -124,10 +124,17 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput,
},
change: function(_node) {
if (this.onchange)
var messages = [];
var valid = this.isValid(messages);
// Passing false will clear any set messages
this.set_validation_error(valid ? false : messages);
if (valid && this.onchange)
{
return et2_compileLegacyJS(this.onchange, this, _node)();
}
return valid;
},
set_value: function(_value) {
@ -218,7 +225,7 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput,
this.label = _value;
},
set_required: function(_value) {
set_needed: function(_value) {
var node = this.getInputNode();
if (node)
{
@ -281,7 +288,34 @@ var et2_inputWidget = et2_valueWidget.extend(et2_IInput,
resetDirty: function() {
this._oldValue = this.getValue();
}
},
isValid: function(messages) {
var ok = true;
// Check for required
if(this.options.needed && (this.getValue() == null || this.getValue().valueOf() == ''))
{
messages.push(this.egw().lang('input required'));
ok = false;
}
return ok;
},
/**
* Called whenever the template gets submitted. We return false if the widget
* is not valid, which cancels the submission.
*
* @param _values contains the values which will be sent to the server.
* Listeners may change these values before they get submitted.
*/
submit: function(_values) {
var messages = [];
var valid = this.isValid(messages);
// Passing false will clear any set messages
this.set_validation_error(valid ? false : messages);
return valid;
}
});

View File

@ -57,7 +57,23 @@ var et2_IInput = new Interface({
/**
* Causes the dirty flag to be reseted.
*/
resetDirty: function() {}
resetDirty: function() {},
/**
* Checks the data to see if it is valid, as far as the client side can tell.
* Return true if it's not possible to tell on the client side, because the server
* will have the chance to validate also.
*
* The messages array is to be populated with everything wrong with the data,
* so don't stop checking after the first problem unless it really makes sense
* to ignore other problems.
*
* @param {String[]} messages List of messages explaining the failure(s).
* messages should be fairly short, and already translated.
*
* @return {boolean} True if the value is valid (enough), false to fail
*/
isValid: function(messages) {}
});
/**

View File

@ -190,7 +190,7 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput
var attrs = {
'id': id,
'statustext': field.help,
'required': field.needed,
'needed': field.needed,
'readonly': this.options.readonly,
'value': this.options.value[this.prefix+field_name]
};
@ -370,6 +370,11 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput
}
}
},
isValid: function() {
// Individual customfields will handle themselves
return true;
},
/**
* Adapt provided attributes to match options for widget

View File

@ -248,6 +248,9 @@ var et2_button = et2_baseWidget.extend([et2_IInput, et2_IDetachedDOM],
// array.
return null;
},
isValid: function() {
return true;
},
/**
* et2_IDetachedDOM

View File

@ -867,7 +867,7 @@ var et2_link = et2_valueWidget.extend([et2_IDetachedDOM],
description: "Array with keys app, id, and optionally title",
type: "any"
},
"required": {
"needed": {
"ignore": true
}
},

View File

@ -236,7 +236,7 @@ var et2_radioGroup = et2_valueWidget.extend([et2_IDetachedDOM],
"default": {},
"description": "Options for radio buttons. Should be {value: label, ...}"
},
"required": {
"needed": {
"name": "Required",
"default": false,
"type": "boolean",
@ -258,7 +258,7 @@ var et2_radioGroup = et2_valueWidget.extend([et2_IDetachedDOM],
this.node = $j(document.createElement("div"))
.addClass("et2_vbox")
.addClass("et2_box_widget");
if(this.options.required)
if(this.options.needed)
{
// This isn't strictly allowed, but it works
this.node.attr("required","required");
@ -298,7 +298,7 @@ var et2_radioGroup = et2_valueWidget.extend([et2_IDetachedDOM],
ro_true: this.options.ro_true,
ro_false: this.options.ro_false,
readonly: this.options.readonly,
required: this.options.required
needed: this.options.needed
};
var radio = et2_createWidget("radio", attrs, this);
}

View File

@ -72,7 +72,7 @@ var et2_selectAccount = et2_selectbox.extend(
}
// If not required, make sure there's an empty label
if(_attrs['rows'] == 1 && !_attrs['empty_label'] && !_attrs['required'])
if(_attrs['rows'] == 1 && !_attrs['empty_label'] && !_attrs['needed'])
{
_attrs['empty_label'] = 'None';
}

View File

@ -304,6 +304,9 @@ var et2_tabbox = et2_valueWidget.extend([et2_IInput],
resetDirty: function()
{
this.value = this.selected_index;
},
isValid: function(messages) {
return true;
}
});
et2_register_widget(et2_tabbox, ["tabbox"]);

View File

@ -208,7 +208,7 @@ var et2_textbox_ro = et2_valueWidget.extend([et2_IDetachedDOM],
"size": {
"ignore": true
},
"required": {
"needed": {
"ignore": true
}
},

View File

@ -88,7 +88,7 @@ function etemplate2(_container, _menuaction)
// List of templates (XML) that are known, but not used. Indexed by id.
this.templates = {};
// Connect to the window resize event
$j(window).resize(this, function(e) {e.data.resize();});
}
@ -115,11 +115,10 @@ etemplate2.prototype.clear = function()
{
if (this.widgetContainer != null)
{
// $j(':input',this.DOMContainer).validator().data("validator").destroy();
this.widgetContainer.free();
this.widgetContainer = null;
}
// Remove self from the index
for(name in this.templates)
{
@ -262,15 +261,6 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
etemplate2.prototype.submit = function(button)
{
// Validator
/*var valid = true;
var inputs = $j(':input',this.DOMContainer).each(function() {
if(typeof $j(this).data("validator") == "undefined") return true;
valid = valid && $j(this).data("validator").checkValidity();
return true;
});
if(!valid) return false;*/
// Get the form values
var values = this.getValues(this.widgetContainer);