Commit dfb62b97 authored by Tomáš Peterka's avatar Tomáš Peterka

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

parent f4eb48d9
...@@ -46,10 +46,26 @@ MARKER = [] ...@@ -46,10 +46,26 @@ MARKER = []
if REQUEST is None: if REQUEST is None:
REQUEST = context.REQUEST REQUEST = context.REQUEST
# raise Unauthorized
if response is None: if response is None:
response = REQUEST.RESPONSE 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 # http://stackoverflow.com/a/13105359
def byteify(string): def byteify(string):
if isinstance(string, dict): if isinstance(string, dict):
...@@ -669,6 +685,8 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key ...@@ -669,6 +685,8 @@ def renderField(traversed_document, field, form, value=None, meta_type=None, key
"lines": lines, "lines": lines,
"default_params": default_params, "default_params": default_params,
"list_method": list_method_name, "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": url_template_dict["jio_search_template"] % {
"query": make_query({ "query": make_query({
"query": sql_catalog.buildQuery( "query": sql_catalog.buildQuery(
...@@ -1456,8 +1474,54 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, ...@@ -1456,8 +1474,54 @@ 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'] = contents_list result_dict['_embedded']['contents'] = ensureSerializable(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
selection_name = source_field.get_value('selection_name')
if selection_name and 'selection_name' not in catalog_kw:
catalog_kw['selection_name'] = selection_name
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)(**catalog_kw)
contents_stat_list.append(contents_stat)
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())(**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'] = ensureSerializable(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 return result_dict
elif mode == 'form': 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>**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 @@ ...@@ -178,27 +178,33 @@
] ]
) )
.push(function (catalog_json) { .push(function (catalog_json) {
var data = catalog_json._embedded.contents, var data = catalog_json._embedded.contents || [],
count = data.length, summary = catalog_json._embedded.sum || [],
k, count = catalog_json._embedded.count;
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
});
}
return { return {
data: { "data": {
rows: result, "rows": data.map(function (item) {
total_rows: result.length 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 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>947.45414.13002.10052</string> </value> <value> <string>963.59331.40212.55432</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1449753994.81</float> <float>1512454358.33</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -45,14 +45,14 @@ ...@@ -45,14 +45,14 @@
<script id="listbox-hidden-tbody-template" type="text/x-handlebars-template"> <script id="listbox-hidden-tbody-template" type="text/x-handlebars-template">
<table> <table>
<tbody class="tbody"> <tbody class="tbody">
{{#each body_value}} {{#each row_list}}
<tr> <tr>
{{#if ../show_anchor}} {{#if ../show_anchor}}
<th> <th>
<a class="ui-link ui-btn ui-corner-all ui-icon-carat-r ui-btn-icon-notext" href="{{jump}}"></a> <a class="ui-link ui-btn ui-corner-all ui-icon-carat-r ui-btn-icon-notext" href="{{jump}}"></a>
</th> </th>
{{/if}} {{/if}}
{{#each tr_value}} {{#each cell_list}}
<td> <td>
{{#if type}} {{#if type}}
{{#if editable}} {{#if editable}}
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,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}}
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
<script id="listbox-show-tbody-template" type="text/x-handlebars-template"> <script id="listbox-show-tbody-template" type="text/x-handlebars-template">
<table> <table>
<tbody class="tbody"> <tbody class="tbody">
{{#each body_value}} {{#each row_list}}
<tr> <tr>
{{#if ../show_anchor}} {{#if ../show_anchor}}
<th> <th>
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<td> <td>
<input value="{{value}}" type="checkbox" checked="true" class="hide_element"> <input value="{{value}}" type="checkbox" checked="true" class="hide_element">
</td> </td>
{{#each tr_value}} {{#each cell_list}}
<td> <td>
{{#if type}} {{#if type}}
{{#if editable}} {{#if editable}}
...@@ -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}}
...@@ -121,19 +121,38 @@ ...@@ -121,19 +121,38 @@
<script id="listbox-tfoot-template" type="text/x-handlebars-template"> <script id="listbox-tfoot-template" type="text/x-handlebars-template">
<table> <table>
<tfoot class="ui-bar-inherit tfoot"> <tfoot class="ui-bar-inherit tfoot">
<th colspan="{{colspan}}"> {{#each row_list}}
<div class="ui-controlgroup ui-controlgroup-horizontal ui-corner-all ui-paging-menu"> <tr>
<div class="ui-controlgroup-controls"> {{#if ../show_anchor}}
<a class="{{previous_classname}}" data-i18n="Previous" href="{{previous_url}}">Previous</a> <td>Total</td>
<a class="{{next_classname}}" data-i18n="Next" href="{{next_url}}">Next</a> {{/if}}
<span class="ui-btn ui-disabled" data-i18n="{{record}}">{{record}}</span> {{#each cell_list}}
</div> <td>
</div> {{#if type}}
</th> <div class="editable_div" data-column="{{column}}" data-line="{{line}}"></div>
{{else}}
{{#if default}}
{{default}}
{{else}}
{{#if @first}}
Total
{{/if}}
{{/if}}
{{/if}}
</td>
{{/each}}
</tr>
{{/each}}
</tfoot> </tfoot>
</table> </table>
</script> </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"> <script id="listbox-template" type="text/x-handlebars-template">
<div class="ui-table-header ui-header ui-bar-c ui-corner-all"> <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> <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>
...@@ -153,11 +172,11 @@ ...@@ -153,11 +172,11 @@
<tbody></tbody> <tbody></tbody>
<tfoot class="ui-bar-inherit tfoot"></tfoot> <tfoot class="ui-bar-inherit tfoot"></tfoot>
</table> </table>
<nav></nav>
</div> </div>
</script> </script>
<script id="error-message-template" type="text/x-handlebars-template"> <script id="error-message-template" type="text/x-handlebars-template">
<div class="ui-listbox-error"> <div class="ui-listbox-error">
<a class="ui-btn ui-corner-all ui-btn-inline" href="{{reset_url}}"> <a class="ui-btn ui-corner-all ui-btn-inline" href="{{reset_url}}">
......
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>962.24395.32903.29832</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>1506526285.9</float> <float>1512617871.97</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -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.40734.12928.52855</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>1511430200.52</float> <float>1512556744.93</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -1279,24 +1279,30 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button { ...@@ -1279,24 +1279,30 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button {
.document_table table { .document_table table {
width: 100%; width: 100%;
text-align: left; text-align: left;
/* end-of tbody, tfoot*/
} }
.document_table table th, .document_table table th,
.document_table table td { .document_table table td {
vertical-align: middle; vertical-align: middle;
padding: 3pt;
} }
.document_table table thead { .document_table table thead,
.document_table table tfoot {
background-color: #0E81C2; background-color: #0E81C2;
color: #FFFFFF; color: #FFFFFF;
} }
.document_table table thead a { .document_table table thead a,
.document_table table tfoot a {
color: #FFFFFF; color: #FFFFFF;
text-decoration: underline; text-decoration: underline;
} }
.document_table table thead tr th { .document_table table thead tr th,
.document_table table tfoot tr th {
padding: 6pt 3pt; padding: 6pt 3pt;
} }
@media not screen and (min-width: 45em) { @media not screen and (min-width: 45em) {
.document_table table thead { .document_table table thead,
.document_table table tfoot {
display: none; display: none;
} }
} }
...@@ -1316,7 +1322,6 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button { ...@@ -1316,7 +1322,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) { @media not screen and (max-width: 85em), only screen and (min-width: 45em) and (max-width: 85em) {
.document_table table tbody a { .document_table table tbody a {
display: block; display: block;
padding: 3pt;
} }
} }
@media not screen and (min-width: 45em) { @media not screen and (min-width: 45em) {
...@@ -1385,41 +1390,42 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button { ...@@ -1385,41 +1390,42 @@ div[data-gadget-scope='erp5_searchfield'] div.search_parsed_value button {
content: " ~ "; content: " ~ ";
} }
} }
.document_table table tfoot .ui-controlgroup-controls { .document_table nav {
display: flex; display: flex;
padding-top: 6pt; padding-top: 6pt;
border-top: 2px solid rgba(0, 0, 0, 0.14902); border-top: 2px solid rgba(0, 0, 0, 0.14902);
} }
.document_table table tfoot .ui-controlgroup-controls span { .document_table nav span {
opacity: .3; opacity: .3;
flex: 2; flex: 2;
text-align: right; text-align: right;
float: right;
} }
.document_table table tfoot .ui-controlgroup-controls a { .document_table nav a {
padding: 6pt; padding: 6pt;
border: 1px solid rgba(0, 0, 0, 0.14); border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em; border-radius: 0.325em;
margin-right: 6pt; margin-right: 6pt;
} }
.document_table table tfoot .ui-controlgroup-controls a:last-of-type { .document_table nav a:last-of-type {
margin-right: 0; margin-right: 0;
} }
.document_table table tfoot .ui-controlgroup-controls a:hover, .document_table nav a:hover,
.document_table table tfoot .ui-controlgroup-controls a:active { .document_table nav a:active {
background-color: #e0e0e0; background-color: #e0e0e0;
} }
@media not screen and (min-width: 45em) { @media not screen and (min-width: 45em) {
.document_table table tfoot .ui-controlgroup-controls a { .document_table nav a {
overflow: hidden; overflow: hidden;
text-indent: -9999px; text-indent: -9999px;
white-space: nowrap; white-space: nowrap;
} }
} }
.document_table table tfoot .ui-controlgroup-controls a::before { .document_table nav a::before {
margin-right: 6pt; margin-right: 6pt;
} }
@media not screen and (min-width: 45em) { @media not screen and (min-width: 45em) {
.document_table table tfoot .ui-controlgroup-controls a::before { .document_table nav a::before {
float: left; float: left;
text-indent: 6pt; text-indent: 6pt;
} }
......
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>963.49524.2871.19182</string> </value> <value> <string>963.54869.55137.61115</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1512052879.86</float> <float>1512455490.33</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -1476,9 +1476,10 @@ div[data-gadget-scope='erp5_searchfield'] { ...@@ -1476,9 +1476,10 @@ div[data-gadget-scope='erp5_searchfield'] {
th, td { th, td {
// line-height: 1.5em; // line-height: 1.5em;
vertical-align: middle; vertical-align: middle;
padding: @half-margin-size;
} }
thead { thead, tfoot {
background-color: @colorsubheaderbackground; background-color: @colorsubheaderbackground;
color: @white; color: @white;
...@@ -1518,7 +1519,6 @@ div[data-gadget-scope='erp5_searchfield'] { ...@@ -1518,7 +1519,6 @@ div[data-gadget-scope='erp5_searchfield'] {
@media @desktop, @tablet { @media @desktop, @tablet {
a { a {
display: block; display: block;
padding: @half-margin-size;
} }
} }
...@@ -1598,48 +1598,47 @@ div[data-gadget-scope='erp5_searchfield'] { ...@@ -1598,48 +1598,47 @@ div[data-gadget-scope='erp5_searchfield'] {
} }
} }
} }
} /* end-of tbody, tfoot*/
} /* end-of table */
nav {
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 {
padding: @margin-size;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: @radius;
margin-right: @margin-size;
&:last-of-type {
margin-right: 0;
}
tfoot .ui-controlgroup-controls { &:hover, &:active {
display: flex; background-color: @colorblocklinkbackground;
padding-top: @margin-size; }
border-top: 2px solid rgba(0, 0, 0, 0.14902);
span { @media @smartphone {
opacity: .3; .hide_text(@width: initial);
flex: 2;
text-align: right;
} }
a {
padding: @margin-size;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: @radius;
&::before {
margin-right: @margin-size; margin-right: @margin-size;
&:last-of-type {
margin-right: 0;
}
&:hover, &:active {
background-color: @colorblocklinkbackground;
}
@media @smartphone { @media @smartphone {
.hide_text(@width: initial); float: left;
} text-indent: @margin-size;
&::before {
margin-right: @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>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