Commit 8fdc1a15 authored by Tomáš Peterka's avatar Tomáš Peterka Committed by Romain Courteaud

[hal_json+renderjs] Implement "stat" line for ListBox

/reviewed-on nexedi/erp5!528
parent 78bd5926
......@@ -47,10 +47,26 @@ MARKER = []
if REQUEST is None:
REQUEST = context.REQUEST
# raise Unauthorized
if response is None:
response = REQUEST.RESPONSE
def toBasicTypes(obj):
"""Ensure that obj contains only basic types."""
if obj is None:
return obj
if isinstance(obj, (bool, int, float, long, str, unicode)):
return obj
if isinstance(obj, (tuple, list)):
return [toBasicTypes(x) for x in obj]
try:
return {toBasicTypes(key): toBasicTypes(obj[key]) for key in obj}
except:
log('Cannot convert {!s} to basic types {!s}'.format(type(obj), obj), level=100)
return obj
# http://stackoverflow.com/a/13105359
def byteify(string):
if isinstance(string, dict):
......@@ -684,6 +700,8 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
"lines": lines,
"default_params": default_params,
"list_method": list_method_name,
"show_stat": field.get_value('stat_method') != "" or len(field.get_value('stat_columns')) > 0,
"show_count": field.get_value('count_method') != "",
"query": url_template_dict["jio_search_template"] % {
"query": make_query({
"query": sql_catalog.buildQuery(
......@@ -1478,6 +1496,55 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
contents_list.append(contents_item)
result_dict['_embedded']['contents'] = contents_list
# Compute statistics if the search issuer was ListBox
# or in future if the stats (SUM) are required by JIO call
source_field_meta_type = source_field.meta_type if source_field is not None else ""
if source_field_meta_type == "ProxyField":
source_field_meta_type = source_field.getRecursiveTemplateField().meta_type
if source_field is not None and source_field_meta_type == "ListBox":
contents_stat_list = []
# in case the search was issued by listbox we can provide results of
# stat_method and count_method back to the caller
# XXX: we should check whether they asked for it
stat_method = source_field.get_value('stat_method')
stat_columns = source_field.get_value('stat_columns')
# support only selection_name for stat methods because any `selection` is deprecated
# and should be removed
# Romain wants full backward compatibility so putting `selection` back in parameters
selection_name = source_field.get_value('selection_name')
if selection_name and 'selection_name' not in catalog_kw:
catalog_kw['selection_name'] = selection_name
catalog_kw['selection'] = context.getPortalObject().portal_selections.getSelectionFor(selection_name, REQUEST)
contents_stat = {}
if len(stat_columns) > 0:
# prefer stat per column (follow original ListBox.py implementation)
for stat_name, stat_script in stat_columns:
contents_stat[stat_name] = getattr(traversed_document, stat_script)(REQUEST=REQUEST, **catalog_kw)
contents_stat_list.append(contents_stat)
  • @romain: I think the above should care about what columns are visible, otherwise we are computing stats which will not be displayed.

    What about:

            for stat_name, stat_script in stat_columns:
              if stat_name in select_list:
                contents_stat[stat_name] = getattr(traversed_document, stat_script)(REQUEST=REQUEST, **catalog_kw)
            if contents_stat:
              contents_stat_list.append(contents_stat)
  • @vpelletier it seems reasonable. I'll check on my branch and fix asap

Please register or sign in to reply
elif stat_method != "" and stat_method.getMethodName() != list_method:
# 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)
stat_method_result = getattr(traversed_document, stat_method.getMethodName())(REQUEST=REQUEST, **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 []
for contents_stat in contents_stat_list:
for key, value in contents_stat.items():
if key in editable_field_dict:
contents_stat[key] = renderField(
traversed_document, editable_field_dict[key], listbox_form, value, key=editable_field_dict[key].id + '__sum')
if len(contents_stat_list) > 0:
result_dict['_embedded']['sum'] = contents_stat_list
# We should cleanup the selection if it exists in catalog params BUT
# we cannot because it requires escalated Permission.'modifyPortal' so
# the correct solution would be to ReportSection.popReport but unfortunately
# we don't have it anymore because we are asynchronous
return result_dict
elif mode == 'form':
......
"""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>selection, **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>
......@@ -178,27 +178,33 @@
]
)
.push(function (catalog_json) {
var data = catalog_json._embedded.contents,
count = data.length,
k,
uri,
item,
result = [];
for (k = 0; k < count; k += 1) {
item = data[k];
uri = new URI(item._links.self.href);
delete item._links;
result.push({
id: uri.segment(2),
doc: {},
value: item
});
}
var data = catalog_json._embedded.contents || [],
summary = catalog_json._embedded.sum || [],
count = catalog_json._embedded.count;
return {
data: {
rows: result,
total_rows: result.length
}
"data": {
"rows": data.map(function (item) {
var uri = new URI(item._links.self.href);
delete item._links;
return {
"id": uri.segment(2),
"doc": {},
"value": item
};
}),
"total_rows": data.length
},
"sum": {
"rows": summary.map(function (item, index) {
return {
"id": '/#summary' + index, // this is obviously wrong. @Romain help please!
"doc": {},
"value": item
};
}),
"total_rows": summary.length
},
"count": count
};
});
})
......
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>947.45414.13002.10052</string> </value>
<value> <string>963.59331.40212.55432</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1449753994.81</float>
<float>1512454358.33</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -60,18 +60,18 @@
</thead>
</table>
</script>
<script id="listbox-hidden-tbody-template" type="text/x-handlebars-template">
<table>
<tbody class="tbody">
{{#each body_value}}
{{#each row_list}}
<tr>
{{#if ../show_anchor}}
<th>
<a class="ui-link ui-btn ui-corner-all ui-icon-carat-r ui-btn-icon-notext" href="{{jump}}"></a>
</th>
{{/if}}
{{#each tr_value}}
{{#each cell_list}}
<td>
{{#if type}}
{{#if editable}}
......@@ -82,7 +82,7 @@
</a>
{{/if}}
{{else}}
<a href="{{href}}" class="ui-link">{{text}}</a>
<a href="{{href}}" class="ui-link">{{default}}</a>
{{/if}}
</td>
{{/each}}
......@@ -101,7 +101,7 @@
<script id="listbox-show-tbody-template" type="text/x-handlebars-template">
<table>
<tbody class="tbody">
{{#each body_value}}
{{#each row_list}}
<tr>
{{#if ../show_anchor}}
<th>
......@@ -111,7 +111,7 @@
<td>
<input value="{{value}}" type="checkbox" checked="true" class="hide_element">
</td>
{{#each tr_value}}
{{#each cell_list}}
<td>
{{#if type}}
{{#if editable}}
......@@ -122,7 +122,7 @@
</a>
{{/if}}
{{else}}
<a href="{{href}}" class="ui-link">{{text}}</a>
<a href="{{href}}" class="ui-link">{{default}}</a>
{{/if}}
</td>
{{/each}}
......@@ -140,19 +140,40 @@
<script id="listbox-tfoot-template" type="text/x-handlebars-template">
<table>
<tfoot class="ui-bar-inherit tfoot">
<th colspan="{{colspan}}">
<div class="ui-controlgroup ui-controlgroup-horizontal ui-corner-all ui-paging-menu">
<div class="ui-controlgroup-controls">
<a class="{{previous_classname}}" data-i18n="Previous" href="{{previous_url}}">Previous</a>
<a class="{{next_classname}}" data-i18n="Next" href="{{next_url}}">Next</a>
<span class="ui-btn ui-disabled" data-i18n="{{record}}">{{record}}</span>
</div>
</div>
</th>
{{#each row_list}}
<tr>
{{#if ../show_anchor}}
<td>Total</td>
{{/if}}
{{#each cell_list}}
<td>
{{#if type}}
<div class="editable_div" data-column="{{column}}" data-line="{{line}}"></div>
{{else}}
{{#if default}}
{{default}}
{{else}}
{{#unless ../../show_anchor }}
{{#if @first}}
Total
{{/if}}
{{/unless}}
{{/if}}
{{/if}}
</td>
{{/each}}
</tr>
{{/each}}
</tfoot>
</table>
</script>
<script id="listbox-nav-template" type="text/x-handlebars-template">
<a class="{{previous_classname}}" data-i18n="Previous" href="{{previous_url}}">Previous</a>
<a class="{{next_classname}}" data-i18n="Next" href="{{next_url}}">Next</a>
<span class="ui-disabled ui-right" data-i18n="{{record}}">{{record}}</span>
</script>
<script id="listbox-template" type="text/x-handlebars-template">
<div class="ui-table-header ui-header ui-bar-c ui-corner-all">
<h1 data-i18n="{{title}}" class="ui-title ui-override-theme">{{title}}<span> <span class="listboxloader ui-icon-spinner ui-btn-icon-left"></span></span></h1>
......@@ -165,11 +186,11 @@
<tbody></tbody>
<tfoot class="ui-bar-inherit tfoot"></tfoot>
</table>
<nav></nav>
</div>
</script>
<script id="error-message-template" type="text/x-handlebars-template">
<div class="ui-listbox-error">
<a class="ui-btn ui-corner-all ui-btn-inline" href="{{reset_url}}">
......
......@@ -234,7 +234,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>964.27340.60822.54681</string> </value>
<value> <string>964.45882.29366.36147</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -252,7 +252,7 @@
</tuple>
<state>
<tuple>
<float>1514393372.0</float>
<float>1515514305.55</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -75,12 +75,6 @@
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_field_listbox.js</string> </value>
......@@ -242,7 +236,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>964.28739.16428.44868</string> </value>
<value> <string>964.47502.56518.25890</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -260,7 +254,7 @@
</tuple>
<state>
<tuple>
<float>1514478789.32</float>
<float>1515602869.96</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -1305,24 +1305,30 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button {
.document_table table {
width: 100%;
text-align: left;
/* end-of tbody, tfoot*/
}
.document_table table th,
.document_table table td {
vertical-align: middle;
padding: 3pt;
}
.document_table table thead {
.document_table table thead,
.document_table table tfoot {
background-color: #0E81C2;
color: #FFFFFF;
}
.document_table table thead a {
.document_table table thead a,
.document_table table tfoot a {
color: #FFFFFF;
text-decoration: underline;
}
.document_table table thead tr th {
.document_table table thead tr th,
.document_table table tfoot tr th {
padding: 6pt 3pt;
}
@media not screen and (min-width: 45em) {
.document_table table thead {
.document_table table thead,
.document_table table tfoot {
display: none;
}
}
......@@ -1342,7 +1348,6 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button {
@media not screen and (max-width: 85em), only screen and (min-width: 45em) and (max-width: 85em) {
.document_table table tbody a {
display: block;
padding: 3pt;
}
}
@media not screen and (min-width: 45em) {
......@@ -1411,41 +1416,46 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button {
content: " ~ ";
}
}
.document_table table tfoot .ui-controlgroup-controls {
.document_table nav {
display: flex;
padding-top: 6pt;
border-top: 2px solid rgba(0, 0, 0, 0.14902);
}
.document_table table tfoot .ui-controlgroup-controls span {
.document_table nav span {
opacity: .3;
flex: 2;
text-align: right;
float: right;
}
.document_table table tfoot .ui-controlgroup-controls a {
.document_table nav a {
padding: 6pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
margin-right: 6pt;
}
.document_table table tfoot .ui-controlgroup-controls a::before {
.document_table nav a::before {
margin-right: 6pt;
}
.document_table table tfoot .ui-controlgroup-controls a:hover,
.document_table table tfoot .ui-controlgroup-controls a:active {
.document_table nav a:hover,
.document_table nav a:active {
background-color: #e0e0e0;
}
.document_table table tfoot .ui-controlgroup-controls a:last-of-type {
.document_table nav a:last-of-type {
margin-right: 0;
}
.document_table nav a:hover,
.document_table nav a:active {
background-color: #e0e0e0;
}
@media not screen and (min-width: 45em) {
.document_table table tfoot .ui-controlgroup-controls a {
.document_table nav a {
overflow: hidden;
text-indent: -9999px;
white-space: nowrap;
}
}
@media not screen and (min-width: 45em) {
.document_table table tfoot .ui-controlgroup-controls a::before {
.document_table nav a::before {
float: left;
text-indent: 6pt;
}
......
......@@ -1523,9 +1523,10 @@ div[data-gadget-scope='erp5_searchfield'] {
th, td {
// line-height: 1.5em;
vertical-align: middle;
padding: @half-margin-size;
}
thead {
thead, tfoot {
background-color: @colorsubheaderbackground;
color: @white;
......@@ -1565,7 +1566,6 @@ div[data-gadget-scope='erp5_searchfield'] {
@media @desktop, @tablet {
a {
display: block;
padding: @half-margin-size;
}
}
......@@ -1646,40 +1646,43 @@ div[data-gadget-scope='erp5_searchfield'] {
}
}
}
}
nav {
display: flex;
padding-top: @margin-size;
border-top: 2px solid rgba(0, 0, 0, 0.14902);
tfoot .ui-controlgroup-controls {
display: flex;
padding-top: @margin-size;
border-top: 2px solid rgba(0, 0, 0, 0.14902);
span {
opacity: .3;
flex: 2;
text-align: right;
float: right;
}
a {
.button();
span {
opacity: .3;
flex: 2;
text-align: right;
margin-right: @margin-size;
&:last-of-type {
margin-right: 0;
}
a {
.button();
margin-right: @margin-size;
&:last-of-type {
margin-right: 0;
}
&:hover, &:active {
background-color: @colorblocklinkbackground;
}
@media @smartphone {
.hide_text(@width: initial);
}
@media @smartphone {
.hide_text(@width: initial);
}
&::before {
&::before {
@media @smartphone {
float: left;
text-indent: @margin-size;
}
@media @smartphone {
float: left;
text-indent: @margin-size;
}
}
}
}
}
......
<?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>testEmptyListboxWithStat</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 empty listbox does not show stat line even though it receives stat data.
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI ListBox No Stat Line on No Data</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS UI ListBox No Stat Line on No Data</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>
<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="No records"]</td><td></td></tr>
<tr><td>assertElementNotPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tfoot/tr</td>
<td></td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -128,11 +128,6 @@
<td>//thead/tr/th[3]</td>
<td>Quantity</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//tfoot/tr/th[@colspan="3"]</td>
<td></td>
</tr>
<tr>
......@@ -169,11 +164,6 @@
<td>//thead/tr/th[4]</td>
<td>Quantity</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//tfoot/tr/th[@colspan="4"]</td>
<td></td>
</tr>
<!-- Line checkbox -->
......@@ -233,11 +223,6 @@
<td>//thead/tr/th[3]</td>
<td>Quantity</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//tfoot/tr/th[@colspan="3"]</td>
<td></td>
</tr>
<!-- only one element present -->
<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>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
<?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>testStatMissing</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 no stat line is displayed when no stat_method and no stat_columns are defined.
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI ListBox Stat Missing</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS UI ListBox Stat Missing</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</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>assertElementNotPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//table/tfoot/tr</td>
<td></td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -247,7 +247,7 @@
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//tfoot//span[contains(@data-i18n, "Records")]</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_field_listbox.html')]//nav//span[contains(@data-i18n, "Records")]</td>
<td></td>
</tr>
<tr>
......
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