Commit ff5355ae authored by Romain Courteaud's avatar Romain Courteaud

GadgetField: use an external field validator.

GadgetField doesn't know how to validate/store REQUEST form data.
Use an external field to handle this task.
The external field must be located in the same form, and can be put in the hidden group if not rendered.

Add a test with a stringfield and a textarea field as validator.
parent 6e53cb2c
......@@ -56,7 +56,7 @@
<!-- Initialize -->
<tr>
<td>waitForElementPresent</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
......@@ -64,7 +64,7 @@
<tr>
<td>type</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>123</td>
</tr>
......@@ -84,14 +84,14 @@
<tr>
<td>waitForElementPresent</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
<tr>
<td>verifyValue</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>123</td>
</tr>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testSaveAndLoadMultiline</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Gadget Field</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Gadget Field</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<tr>
<td>open</td>
<td>${base_url}/bar_module/ListBoxZuite_reset</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Reset Successfully.</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>${base_url}/bar_module/FooModule_createObjects?num:int=1;portal_type=Bar</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Created Successfully.</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>${base_url}/bar_module/Zuite_waitForActivities</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Done.</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>${base_url}/bar_module/0/Bar_viewGadgetField</td>
<td></td>
</tr>
<!-- Initialize -->
<tr>
<td>waitForElementPresent</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//textarea[@title='field_my_description']</td>
<td>123
456</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>//button[@title='Save']</td>
<td></td>
</tr>
<tr>
<td>verifyPortalStatusMessage</td>
<td>Data updated.</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
<tr>
<td>verifyValue</td>
<td>//textarea[@title='field_my_description']</td>
<td>123
456</td>
</tr>
<tr>
<td>open</td>
<td>${base_url}/bar_module/0/Bar_representDescription</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>'123\n456'</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -117,7 +117,7 @@
<tr>
<td>waitForElementPresent</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
......@@ -129,7 +129,7 @@
<tr>
<td>type</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>relationFieldTest</td>
</tr>
......@@ -149,7 +149,7 @@
<tr>
<td>waitForElementPresent</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
......@@ -161,14 +161,14 @@
<tr>
<td>verifyValue</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>relationFieldTest</td>
</tr>
<tr>
<td>type</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>relationFieldTestSuite</td>
</tr>
......@@ -199,7 +199,7 @@
<tr>
<td>waitForElementPresent</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td></td>
</tr>
......@@ -211,7 +211,7 @@
<tr>
<td>verifyValue</td>
<td>//input[@title='field_my_description']</td>
<td>//textarea[@title='field_my_description']</td>
<td>relationFieldTestSuite</td>
</tr>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Bar_representDescription</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -67,7 +67,10 @@
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
<list>
<string>textarea_validator</string>
<string>stringfield_validator</string>
</list>
</value>
</item>
<item>
......
......@@ -10,8 +10,9 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
<string>gadget_url</string>
<string>title</string>
<string>validator_field_id</string>
</list>
</value>
</item>
......@@ -71,6 +72,10 @@
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
......@@ -86,6 +91,10 @@
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>gadget_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
......@@ -94,6 +103,10 @@
<key> <string>title</string> </key>
<value> <string>Description</string> </value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>textarea_validator</string> </value>
</item>
</dictionary>
</value>
</item>
......@@ -108,7 +121,7 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: field.restrictedTraverse(\'gadget_stringfield.html\').absolute_url()</string> </value>
<value> <string>python: field.restrictedTraverse(\'gadget_textareafield.html\').absolute_url()</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -188,6 +188,10 @@
<key> <string>title</string> </key>
<value> <string>File</string> </value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>stringfield_validator</string> </value>
</item>
</dictionary>
</value>
</item>
......
......@@ -184,6 +184,18 @@
<key> <string>js_sandbox</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
......@@ -192,6 +204,18 @@
<key> <string>title</string> </key>
<value> <string>Language</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>stringfield_validator</string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
......
......@@ -136,6 +136,10 @@
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>data_url</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
......@@ -160,6 +164,10 @@
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
......@@ -180,6 +188,10 @@
<key> <string>title</string> </key>
<value> <string>Right</string> </value>
</item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>stringfield_validator</string> </value>
</item>
</dictionary>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>stringfield_validator</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_title</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>textarea_validator</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_description</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -10,7 +10,5 @@
<script src="gadget_create_manual_dataurl.js" type="text/javascript"></script>
</head>
<body>
<input type='text'/>
</body>
<body><input type='text'/></body>
</html>
\ No newline at end of file
......@@ -4,29 +4,19 @@
"use strict";
rJS(window)
.ready(function (g) {
g.props = {};
})
.ready(function (g) {
return g.getElement()
.push(function (element) {
g.props.element = element;
});
})
.declareMethod('render', function (options) {
var gadget = this;
gadget.props.key = options.key || "";
gadget.props.element.querySelector('input').value = options.value;
gadget.props.element.querySelector('input').title = options.key;
gadget.element.querySelector('input').key = options.key || "";
gadget.element.querySelector('input').value = options.value;
gadget.element.querySelector('input').title = options.key;
})
.declareMethod('getContent', function () {
var input = this.props.element.querySelector('input'),
var input = this.element.querySelector('input'),
form_gadget = this,
result = {};
if (input.value) {
result[form_gadget.props.key] = "data:text/plain;base64,"
+ btoa(input.value);
result[input.key] = "data:text/plain;base64," + btoa(input.value);
}
return result;
});
......
......@@ -12,7 +12,5 @@
<script src="gadget_stringfield.js" type="text/javascript"></script>
</head>
<body>
<input type='text'/>
</body>
<body><input type='text'/></body>
</html>
\ No newline at end of file
......@@ -4,26 +4,18 @@
"use strict";
rJS(window)
.ready(function (g) {
g.props = {};
})
.ready(function (g) {
return g.getElement()
.push(function (element) {
g.props.element = element;
});
})
.declareMethod('render', function (options) {
this.props.key = options.key || "";
this.props.element.querySelector('input').value = options.value || "";
this.props.element.querySelector('input').title = options.key;
this.element.firstChild.value = options.value || "";
this.element.firstChild.title = options.key;
this.element.firstChild.setAttribute('data-name',
options.key || "");
})
.declareMethod('getContent', function () {
var input = this.props.element.querySelector('input'),
var input = this.element.firstChild,
form_gadget = this,
result = {};
result[form_gadget.props.key] = input.value;
result[input.getAttribute('data-name')] = input.value;
return result;
});
......
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>ERP5 Textareafield</title>
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_textareafield.js" type="text/javascript"></script>
</head>
<body><textarea></textarea></body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_textareafield.html</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*global window, rJS*/
/*jslint nomen: true, maxlen:80, indent:2*/
(function (rJS) {
"use strict";
rJS(window)
.declareMethod('render', function (options) {
this.element.firstChild.value = options.value || "";
this.element.firstChild.title = options.key;
this.element.firstChild.setAttribute('data-name',
options.key || "");
})
.declareMethod('getContent', function () {
var input = this.element.firstChild,
form_gadget = this,
result = {};
result[input.getAttribute('data-name')] = input.value;
return result;
});
}(rJS));
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>gadget_textareafield.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -28,7 +28,7 @@ class GadgetWidget(Widget.Widget):
required=0)
def render(self, field, key, value, REQUEST, render_prefix=None):
return self.render_view(field, value, REQUEST, render_prefix, key)
return self.render_view(field, value, REQUEST, render_prefix, key)
def render_view(self, field, value, REQUEST=None, render_prefix=None, key=None):
kw = {
......@@ -56,7 +56,10 @@ class GadgetWidget(Widget.Widget):
class GadgetFieldValidator(Validator.Validator):
property_names = Validator.Validator.property_names + ['data_url']
property_names = Validator.Validator.property_names + [
'data_url',
'validator_field_id'
]
data_url = fields.CheckBoxField('data_url',
title='Data Url',
......@@ -64,8 +67,38 @@ class GadgetFieldValidator(Validator.Validator):
"Checked if gadget return data url."),
default=0)
validator_field_id = fields.StringField(
'validator_field_id',
title='Field ID',
description= "Field used to validate REQUEST form data.",
default="",
display_width=40,
required=0
  • @romain @gabriel shouldn't we make this required here, so that we see it on the form that something is wrong ?

  • I'm not sure, as many gadgets will be created without edition in mind, but only to visualize some data.

  • Ah that makes sense, so it's good as is. Thanks !

Please register or sign in to reply
)
message_names = Validator.Validator.message_names + ['no_validator']
no_validator = 'Does not support this operation.'
def getValidatorField(self, field):
"""Get an external validator field located in the same form.
"""
field_id = field.id
validator_field_id = field.get_value('validator_field_id')
if validator_field_id:
if field.aq_parent.has_field(validator_field_id,
include_disabled=1):
return field.aq_parent.get_field(validator_field_id,
include_disabled=1)
return None
def validate(self, field, key, REQUEST):
value = REQUEST.get(key, None)
validator_field = self.getValidatorField(field)
if validator_field is None:
# not editable if no validator
self.raise_error('no_validator', field)
else:
value = validator_field._validate_helper(key, REQUEST)
if value is not None:
if field.get_value('data_url'):
value=value.split(",")[1]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment