Commit 2119056f authored by Tomáš Peterka's avatar Tomáš Peterka

Finish?

parent d2f8c300
...@@ -140,6 +140,9 @@ def kwargsForCallable(func, initial_kwargs, kwargs_dict): ...@@ -140,6 +140,9 @@ def kwargsForCallable(func, initial_kwargs, kwargs_dict):
In case the function cannot state required arguments it throws an AttributeError. In case the function cannot state required arguments it throws an AttributeError.
""" """
if not hasattr(func, 'params'):
return initial_kwargs
func_param_list = [func_param.strip() for func_param in func.params().split(",")] func_param_list = [func_param.strip() for func_param in func.params().split(",")]
func_param_name_list = [func_param if '=' not in func_param else func_param.split('=')[0] func_param_name_list = [func_param if '=' not in func_param else func_param.split('=')[0]
for func_param in func_param_list if '*' not in func_param] for func_param in func_param_list if '*' not in func_param]
...@@ -180,7 +183,6 @@ def anythingUidAndAccessor(search_result, result_index, traversed_document): ...@@ -180,7 +183,6 @@ def anythingUidAndAccessor(search_result, result_index, traversed_document):
result[uid] = {'url': portal.abolute_url() + url} result[uid] = {'url': portal.abolute_url() + url}
value = getter(random_object, "value") value = getter(random_object, "value")
""" """
context.log("anythingUidAndAccessor({!s}#type:{!s}, {:d}, {!s}".format(search_result, type(search_result), result_index, traversed_document))
if hasattr(search_result, "getObject"): if hasattr(search_result, "getObject"):
# "Brain" object - which simulates DB Cursor thus result must have UID # "Brain" object - which simulates DB Cursor thus result must have UID
contents_uid = search_result.uid contents_uid = search_result.uid
...@@ -387,6 +389,10 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -387,6 +389,10 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
if selection_params is None: if selection_params is None:
selection_params = {} selection_params = {}
# some TALES expressions are using Base_getRelatedObjectParameter which requires that
previous_request_field = REQUEST.other.pop('field_id', None)
REQUEST.other['field_id'] = field.id
if meta_type is None: if meta_type is None:
meta_type = field.meta_type meta_type = field.meta_type
if key is None: if key is None:
...@@ -396,9 +402,6 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -396,9 +402,6 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
# resolve the base meta_type # resolve the base meta_type
meta_type = field.getRecursiveTemplateField().meta_type meta_type = field.getRecursiveTemplateField().meta_type
# some TALES expressions are using Base_getRelatedObjectParameter which requires that
previous_request_field = REQUEST.other.pop('field_id', None)
REQUEST.other['field_id'] = field.id
result = { result = {
"type": meta_type, "type": meta_type,
"title": Base_translateString(field.get_value("title")), "title": Base_translateString(field.get_value("title")),
...@@ -416,7 +419,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -416,7 +419,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
"default": getFieldDefault(form, field, key, value), "default": getFieldDefault(form, field, key, value),
}) })
# start the actuall "switch" on field's meta_type here # start the actual "switch" on field's meta_type here
if meta_type in ("ListField", "RadioField", "ParallelListField", "MultiListField"): if meta_type in ("ListField", "RadioField", "ParallelListField", "MultiListField"):
result.update({ result.update({
# XXX Message can not be converted to json as is # XXX Message can not be converted to json as is
...@@ -591,6 +594,11 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -591,6 +594,11 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
"url": field.get_value("gadget_url"), "url": field.get_value("gadget_url"),
"sandbox": field.get_value("js_sandbox") "sandbox": field.get_value("js_sandbox")
}) })
try:
result["renderjs_extra"] = json.dumps(dict(field.get_value("renderjs_extra")))
except KeyError:
# Ensure compatibility if the products are not yet up to date
result["renderjs_extra"] = json.dumps({})
elif meta_type == "ListBox": elif meta_type == "ListBox":
"""Display list of objects with optional search/sort capabilities on columns from catalog. """Display list of objects with optional search/sort capabilities on columns from catalog.
...@@ -629,7 +637,6 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -629,7 +637,6 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
# see https://lab.nexedi.com/nexedi/erp5/blob/HEAD/product/ERP5Form/ListBox.py#L1004 # see https://lab.nexedi.com/nexedi/erp5/blob/HEAD/product/ERP5Form/ListBox.py#L1004
# implemented in javascript in the end # implemented in javascript in the end
# see https://lab.nexedi.com/nexedi/erp5/blob/master/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js#L163 # see https://lab.nexedi.com/nexedi/erp5/blob/master/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_listbox_js.js#L163
default_params = dict(field.get_value('default_params')) # default_params is a list of tuples default_params = dict(field.get_value('default_params')) # default_params is a list of tuples
default_params['ignore_unknown_columns'] = True default_params['ignore_unknown_columns'] = True
# we abandoned Selections in RJS thus we mix selection query parameters into # we abandoned Selections in RJS thus we mix selection query parameters into
...@@ -659,6 +666,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -659,6 +666,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
field, list_method_name, error), level=100) field, list_method_name, error), level=100)
else: else:
list_method = None list_method = None
# Put all ListBox's search method params from REQUEST to `default_param_json` # Put all ListBox's search method params from REQUEST to `default_param_json`
# because old code expects synchronous render thus having all form's values # because old code expects synchronous render thus having all form's values
# still in the request which is not our case because we do asynchronous rendering # still in the request which is not our case because we do asynchronous rendering
...@@ -666,7 +674,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -666,7 +674,7 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
kwargsForCallable(list_method, list_method_query_dict, REQUEST) kwargsForCallable(list_method, list_method_query_dict, REQUEST)
# Now if the list_method does not specify **kwargs we need to remove # Now if the list_method does not specify **kwargs we need to remove
# unwanted parameters like "portal_type" which is everywhere # unwanted parameters like "portal_type" which is everywhere
if "**" not in list_method.params(): if hasattr(list_method, 'params') and "**" not in list_method.params():
_param_key_list = tuple(list_method_query_dict.keys()) # copy the keys _param_key_list = tuple(list_method_query_dict.keys()) # copy the keys
for param_key in _param_key_list: for param_key in _param_key_list:
if param_key not in list_method.params(): # we search in raw string if param_key not in list_method.params(): # we search in raw string
...@@ -901,7 +909,6 @@ def renderForm(traversed_document, form, response_dict, key_prefix=None, selecti ...@@ -901,7 +909,6 @@ def renderForm(traversed_document, form, response_dict, key_prefix=None, selecti
if report_item.selection_name: if report_item.selection_name:
selection_name = report_prefix + "_" + report_item.selection_name selection_name = report_prefix + "_" + report_item.selection_name
context.log('Report {} defines selection_name {}'.format(report_title, selection_name))
report_form_params.update(selection_name=selection_name) report_form_params.update(selection_name=selection_name)
# this should load selections with correct values - since it is modifying # this should load selections with correct values - since it is modifying
# global state in the backend we have nothing more to do here # global state in the backend we have nothing more to do here
...@@ -1464,7 +1471,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1464,7 +1471,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
# #
# for k, v in catalog_kw.items(): # for k, v in catalog_kw.items():
# REQUEST.set(k, v) # REQUEST.set(k, v)
context.log('list_method >>> {}({!s})'.format(list_method, catalog_kw))
search_result_iterable = callable_list_method(**catalog_kw) search_result_iterable = callable_list_method(**catalog_kw)
# Cast to list if only one element is provided # Cast to list if only one element is provided
...@@ -1533,6 +1540,10 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1533,6 +1540,10 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
contents_uid, contents_relative_url, property_getter, property_hasser = \ contents_uid, contents_relative_url, property_getter, property_hasser = \
anythingUidAndAccessor(search_result, result_index, traversed_document) anythingUidAndAccessor(search_result, result_index, traversed_document)
# Check if this object provides a specific URL method.
# if getattr(search_result, 'getListItemUrl', None) is not None:
# search_result.getListItemUrl(contents_uid, result_index, selection_name)
# _links.self.href is mandatory for JIO so it can create reference to the # _links.self.href is mandatory for JIO so it can create reference to the
# (listbox) item alone # (listbox) item alone
contents_item['_links'] = { contents_item['_links'] = {
...@@ -1565,14 +1576,6 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1565,14 +1576,6 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
# if there is no tales expr (or is empty) we extract the value from search result # if there is no tales expr (or is empty) we extract the value from search result
default_field_value = getAttrFromAnything(search_result, select, property_getter, property_hasser, {}) default_field_value = getAttrFromAnything(search_result, select, property_getter, property_hasser, {})
context.log('renderField!for"{}"({!s}, field={!s}, form={!s}, value={!s}, key={}'.format(
select,
traversed_document,
editable_field_dict[select],
listbox_form,
default_field_value,
'field_%s_%s' % (editable_field_dict[select].id, contents_uid)))
contents_item[select] = renderField( contents_item[select] = renderField(
traversed_document, traversed_document,
editable_field_dict[select], editable_field_dict[select],
...@@ -1588,7 +1591,6 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1588,7 +1591,6 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
contents_item[select] = getAttrFromAnything(search_result, select, property_getter, property_hasser, {'brain': search_result}) contents_item[select] = getAttrFromAnything(search_result, select, property_getter, property_hasser, {'brain': search_result})
# endfor select # endfor select
contents_list.append(contents_item) contents_list.append(contents_item)
result_dict['_embedded']['contents'] = ensureSerializable(contents_list) result_dict['_embedded']['contents'] = ensureSerializable(contents_list)
# Compute statistics if the search issuer was ListBox # Compute statistics if the search issuer was ListBox
...@@ -1604,13 +1606,11 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1604,13 +1606,11 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
# XXX: we should check whether they asked for it # XXX: we should check whether they asked for it
stat_method = source_field.get_value('stat_method') stat_method = source_field.get_value('stat_method')
stat_columns = source_field.get_value('stat_columns') stat_columns = source_field.get_value('stat_columns')
context.log('stat_method "{!s}", stat_columns {!s}'.format(stat_method, stat_columns))
# support only selection_name for stat methods because any `selection` is deprecated # support only selection_name for stat methods because any `selection` is deprecated
# and should be removed # and should be removed
selection_name = source_field.get_value('selection_name') selection_name = source_field.get_value('selection_name')
if selection_name and 'selection_name' not in catalog_kw: if selection_name and 'selection_name' not in catalog_kw:
catalog_kw['selection_name'] = selection_name catalog_kw['selection_name'] = selection_name
context.log('stat_method will receive selection_name "{}"'.format(catalog_kw['selection_name']))
contents_stat = {} contents_stat = {}
if len(stat_columns) > 0: if len(stat_columns) > 0:
# prefer stat per column (follow original ListBox.py implementation) # prefer stat per column (follow original ListBox.py implementation)
...@@ -1621,6 +1621,9 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1621,6 +1621,9 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
# general stat_method is second in priority list - should return dictionary or list of dictionaries # general stat_method is second in priority list - should return dictionary or list of dictionaries
# where all "fields" should be accessible by their "select" name (no "listbox_" prefix) # where all "fields" should be accessible by their "select" name (no "listbox_" prefix)
stat_method_result = getattr(traversed_document, stat_method.getMethodName())(**catalog_kw) stat_method_result = getattr(traversed_document, stat_method.getMethodName())(**catalog_kw)
# stat method can return simple dictionary or subscriptable object thus we put it into one-item list
if stat_method_result is not None and not isinstance(stat_method_result, (list, tuple)):
stat_method_result = [stat_method_result, ]
contents_stat_list = toBasicTypes(stat_method_result) or [] contents_stat_list = toBasicTypes(stat_method_result) or []
for contents_stat in contents_stat_list: for contents_stat in contents_stat_list:
...@@ -1628,9 +1631,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1628,9 +1631,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
if key in editable_field_dict: if key in editable_field_dict:
contents_stat[key] = renderField( contents_stat[key] = renderField(
traversed_document, editable_field_dict[key], listbox_form, value, key=editable_field_dict[key].id + '__sum') traversed_document, editable_field_dict[key], listbox_form, value, key=editable_field_dict[key].id + '__sum')
for contents_stat in contents_stat_list:
for key, value in contents_stat.items():
context.log('contents_stat["{}"] = type {!s}, value {!s}'.format(key, type(value), value))
if len(contents_stat_list) > 0: if len(contents_stat_list) > 0:
result_dict['_embedded']['sum'] = ensureSerializable(contents_stat_list) result_dict['_embedded']['sum'] = ensureSerializable(contents_stat_list)
......
"""Compute stats from actual Foo Lines on a Foo object"""
column_list = ['getQuantity', 'id']
result = {c: 0.0 for c in column_list}
for line in context.contentValues(portal_type="Foo"):
for column in column_list:
value = getattr(line, column)
if callable(value):
value = value()
result[column] = result[column] + float(value)
return [result, ]
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Python Script" module="erp5.portal_type"/>
</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>**kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>FooModule_statMethod</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Python Script</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
counter = 0
for value in context.contentValues():
counter = counter + int(value.getQuantity())
return counter
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Python Script" module="erp5.portal_type"/>
</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>**kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>FooModule_statQuantity</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Python Script</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
</a> </a>
{{/if}} {{/if}}
{{else}} {{else}}
<a href="{{href}}" class="ui-link">{{text}}</a> <a href="{{href}}" class="ui-link">{{default}}</a>
{{/if}} {{/if}}
</td> </td>
{{/each}} {{/each}}
...@@ -131,7 +131,13 @@ ...@@ -131,7 +131,13 @@
{{#if type}} {{#if type}}
<div class="editable_div" data-column="{{column}}" data-line="{{line}}"></div> <div class="editable_div" data-column="{{column}}" data-line="{{line}}"></div>
{{else}} {{else}}
{{text}} {{#if default}}
{{default}}
{{else}}
{{#if @first}}
Total
{{/if}}
{{/if}}
{{/if}} {{/if}}
</td> </td>
{{/each}} {{/each}}
......
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>963.52015.15055.51592</string> </value> <value> <string>963.63278.21548.22971</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1512039069.26</float> <float>1512617871.97</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -495,9 +495,9 @@ ...@@ -495,9 +495,9 @@
cell_list = []; cell_list = [];
for (j = 0; j < column_list.length; j += 1) { for (j = 0; j < column_list.length; j += 1) {
value = allDocs_result.data.rows[i].value[column_list[j][0]] || ""; value = allDocs_result.data.rows[i].value[column_list[j][0]] || "";
// value can be simple string with value in case of non-editable field // value can be simply just a value in case of non-editable field
// thus we construct basic "field_json" manually and insert the value in "default" // thus we construct "field_json" manually and insert the value in "default"
if (typeof value === "string") { if (value.constructor !== Object) {
value = { value = {
'editable': 0, 'editable': 0,
'default': value 'default': value
...@@ -564,8 +564,8 @@ ...@@ -564,8 +564,8 @@
"uid": 'summary' + row_index, "uid": 'summary' + row_index,
"cell_list": column_list.map(function (col_name, col_index) { "cell_list": column_list.map(function (col_name, col_index) {
var field_json = row.value[col_name[0]] || ""; var field_json = row.value[col_name[0]] || "";
if (typeof field_json === "string") { if (field_json.constructor !== Object) {
field_json = {'default': 'value', 'editable': 0}; field_json = {'default': field_json, 'editable': 0};
} }
field_json.editable = field_json.editable && row_editability; field_json.editable = field_json.editable && row_editability;
field_json.column = col_index; field_json.column = col_index;
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>963.60288.35957.62805</string> </value> <value> <string>963.61737.34616.6621</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1512439237.91</float> <float>1512556744.93</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
<?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>testStatColumns</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">
<!--
Ensure Stat Column methods are executed correctly and result displayed in tfoot element of the listbox table.
- if anchor, then text "Total" is present
- columns which are not present in Stat Columns do not display any data
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS ListBox Stat Columns</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS ListBox Stat Columns</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Clean Up -->
<tr><td>open</td>
<td>${base_url}/foo_module/ListBoxZuite_reset</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Reset Successfully.</td><td></td></tr>
<!-- Shortcut for full renderjs url -->
<tr><td>store</td>
<td>${base_url}/web_site_module/renderjs_runner</td>
<td>renderjs_url</td></tr>
<!-- Create Foo objects with IDs 0-9 -->
<tr><td>open</td>
<td>${base_url}/foo_module/FooModule_createObjects?start:int=1&amp;num:int=2</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Created Successfully.</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/wait_for_activities" />
<!-- Let's set up stat column property on listbox -->
<tr><td>open</td>
<td>${base_url}/FooModule_viewFooList/listbox/ListBox_setPropertyList?field_stat_columns=getQuantity+%7C+FooModule_statQuantity+%0A+title+%7C+FooModule_statTitle</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Set Successfully.</td><td></td></tr>
<tr><td>open</td>
<td>${renderjs_url}/#/foo_module</td><td></td></tr>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//nav/span[@data-i18n="2 Records"]</td><td></td></tr>
<tr><td>store</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table</td>
<td>listbox_table</td></tr>
<!-- Default sort on ID column has to be ASCENDING -->
<tr><td>assertFloat</td>
<td>${listbox_table}/tbody/tr[1]/td[3]/a</td>
<td>9</td></tr>
<tr><td>assertFloat</td>
<td>${listbox_table}/tbody/tr[2]/td[3]/a</td>
<td>8</td></tr>
<tr><td>assertText</td><!-- This tests that "Total" appears when first column has no stat defined -->
<td>${listbox_table}/tfoot/tr[1]/td[1]</td>
<td>Total</td></tr>
<tr><td>assertText</td><!-- Test multiple Stat Columns -->
<td>${listbox_table}/tfoot/tr[1]/td[2]</td>
<td>Foos</td></tr>
<tr><td>assertFloat</td>
<td>${listbox_table}/tfoot/tr[1]/td[3]</td>
<td>17</td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?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>testStatMethod</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">
<!--
Ensure stat_method gets executed and result displayed in tfoot element of the listbox table.
- if anchor, then text "Total" is present
- columns for which stat_method does not return any data remain empty
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI ListBox Stat Method</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS UI ListBox Stat Method</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Clean Up -->
<tr><td>open</td>
<td>${base_url}/foo_module/ListBoxZuite_reset</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Reset Successfully.</td><td></td></tr>
<!-- Shortcut for full renderjs url -->
<tr><td>store</td>
<td>${base_url}/web_site_module/renderjs_runner</td>
<td>renderjs_url</td></tr>
<!-- Create Foo objects with IDs 0-9 -->
<tr><td>open</td>
<td>${base_url}/foo_module/FooModule_createObjects?start:int=1&amp;num:int=3</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Created Successfully.</td><td></td></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/wait_for_activities" />
<!-- Let's set up the default sort correctly: id | ASC -->
<tr><td>open</td>
<td>${base_url}/FooModule_viewFooList/listbox/ListBox_setPropertyList?field_stat_method=FooModule_statMethod</td><td></td></tr>
<tr><td>assertTextPresent</td>
<td>Set Successfully.</td><td></td></tr>
<tr><td>open</td>
<td>${renderjs_url}/#/foo_module</td><td></td></tr>
<tr><td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//nav/span[@data-i18n="3 Records"]</td><td></td></tr>
<tr><td>store</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table</td>
<td>listbox_table</td></tr>
<!-- Default sort on ID column has to be ASCENDING -->
<tr><td>assertFloat</td>
<td>${listbox_table}/tbody/tr[1]/td[3]/a</td>
<td>9</td></tr>
<tr><td>assertFloat</td>
<td>${listbox_table}/tbody/tr[2]/td[3]/a</td>
<td>8</td></tr>
<tr><td>assertFloat</td>
<td>${listbox_table}/tbody/tr[3]/td[3]/a</td>
<td>7</td></tr>
<tr><td>assertFloat</td><!-- This tests that "Total" does not appear when first column has stat defined -->
<td>${listbox_table}/tfoot/tr[1]/td[1]</td>
<td>6</td></tr>
<tr><td>assertFloat</td>
<td>${listbox_table}/tfoot/tr[1]/td[3]</td>
<td>24</td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
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