Commit 23bb0fd8 authored by Yoshinori Okuji's avatar Yoshinori Okuji

Heavy rewrite with Page Template.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@8147 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent dacb90c7
...@@ -50,6 +50,7 @@ from ZODB.POSException import ConflictError ...@@ -50,6 +50,7 @@ from ZODB.POSException import ConflictError
from Globals import InitializeClass, Persistent, Acquisition, get_request from Globals import InitializeClass, Persistent, Acquisition, get_request
from Products.PythonScripts.Utility import allow_class from Products.PythonScripts.Utility import allow_class
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
import random import random
import md5 import md5
...@@ -102,6 +103,8 @@ class ReportTree: ...@@ -102,6 +103,8 @@ class ReportTree:
else: else:
self.domain_url = relative_url self.domain_url = relative_url
allow_class(ReportTree)
class ReportSection: class ReportSection:
"""This class describes a report section. """This class describes a report section.
""" """
...@@ -335,11 +338,19 @@ class ListBoxWidget(Widget.Widget): ...@@ -335,11 +338,19 @@ class ListBoxWidget(Widget.Widget):
list_action = fields.StringField('list_action', list_action = fields.StringField('list_action',
title='List Action', title='List Action',
description=('The id of the object action' description=('The id of the object action'
'to display the current list'), ' to display the current list'),
default='list', default='list',
required=1) required=1)
property_names.append('list_action') property_names.append('list_action')
page_template = fields.StringField('page_template',
title='Page Template',
description=('The id of a Page Template'
' to render the ListBox'),
default='',
required=0)
property_names.append('page_template')
def render_view(self, field, value, REQUEST=None, render_format='html', key='listbox'): def render_view(self, field, value, REQUEST=None, render_format='html', key='listbox'):
""" """
Render a ListBox in read-only. Render a ListBox in read-only.
...@@ -858,6 +869,13 @@ class ListBoxRenderer: ...@@ -858,6 +869,13 @@ class ListBoxRenderer:
getCheckedUidList = VolatileCachingMethod(getCheckedUidList) getCheckedUidList = VolatileCachingMethod(getCheckedUidList)
def getCheckedUidSet(self):
"""Return the set of checked uids.
"""
return set(self.getCheckedUidList())
getCheckedUidSet = VolatileCachingMethod(getCheckedUidSet)
def getSelectedColumnList(self): def getSelectedColumnList(self):
"""Return the list of selected columns. """Return the list of selected columns.
""" """
...@@ -1916,7 +1934,7 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine): ...@@ -1916,7 +1934,7 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine):
error = sys.exc_info()) error = sys.exc_info())
else: else:
try: try:
url = '%s/view?selection_index=%s&selection_name=%s&reset:int=1' % (brain.getPath(), self.index, selection_name) url = '%s/view?selection_index=%s&selection_name=%s&reset:int=1' % (brain.getPath(), self.index, selection_name)
except AttributeError: except AttributeError:
pass pass
...@@ -1930,6 +1948,19 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine): ...@@ -1930,6 +1948,19 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine):
return html_list return html_list
allow_class(ListBoxHTMLRendererLine)
class ListBoxRendererContext(Acquisition.Explicit):
"""This class helps making a context for a Page Template,
because Page Template requires an acquisition context.
"""
def __init__(self, renderer):
self.renderer = renderer
# XXX this is a workaround for GlobalTranslationService.
self.Localizer = renderer.getContext().Localizer
def __getattr__(self, name):
return getattr(self.renderer, name)
class ListBoxHTMLRenderer(ListBoxRenderer): class ListBoxHTMLRenderer(ListBoxRenderer):
"""This class implements HTML rendering for ListBox. """This class implements HTML rendering for ListBox.
...@@ -1983,6 +2014,27 @@ class ListBoxHTMLRenderer(ListBoxRenderer): ...@@ -1983,6 +2014,27 @@ class ListBoxHTMLRenderer(ListBoxRenderer):
return md5_string return md5_string
def getPhysicalRoot(self):
"""Return the physical root (an Application object). This method is required for
Page Template to make a context.
"""
return self.getContext().getPhysicalRoot()
asHTML = PageTemplateFile('www/ListBox_asHTML', globals())
def getPageTemplate(self):
"""Return a Page Template to render.
"""
context = ListBoxRendererContext(self)
# If a specific template is specified, use it.
method_id = self.field.get_value('page_template')
if method_id:
return getattr(context, method_id)
# Otherwise, use the default one.
return context.asHTML
def render(self, **kw): def render(self, **kw):
"""Render the data in HTML. """Render the data in HTML.
""" """
...@@ -1998,6 +2050,24 @@ class ListBoxHTMLRenderer(ListBoxRenderer): ...@@ -1998,6 +2050,24 @@ class ListBoxHTMLRenderer(ListBoxRenderer):
selection.edit(method_path = method_path, list_url = list_url) selection.edit(method_path = method_path, list_url = list_url)
self.getSelectionTool().setSelectionFor(self.getSelectionName(), selection, REQUEST = self.request) self.getSelectionTool().setSelectionFor(self.getSelectionName(), selection, REQUEST = self.request)
pt = self.getPageTemplate()
return pt()
def original_render(self, **kw):
"""This is just a reference. Not used any longer.
"""
# Make it sure to store the current selection, only if a list method is defined.
list_method = self.getListMethod()
selection = self.getSelection()
if list_method is not None:
method_path = getPath(self.getContext()) + '/' + self.getListMethodName()
list_url = '%s?selection_name=%s' % (self.getUrl(), self.getRequestedSelectionName())
selection_index = self.getSelectionIndex()
if selection_index is not None:
list_url += '&selection_index=%s' % selection_index
selection.edit(method_path = method_path, list_url = list_url)
self.getSelectionTool().setSelectionFor(self.getSelectionName(), selection, REQUEST = self.request)
# Obtain the list of lines. # Obtain the list of lines.
line_list = self.query() line_list = self.query()
...@@ -2335,7 +2405,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer): ...@@ -2335,7 +2405,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer):
if alias is not None: if alias is not None:
# Render the search field by a widget, if any. # Render the search field by a widget, if any.
if search_field: if search_field is not None:
search_field_html = search_field.render(value = param, key = alias) search_field_html = search_field.render(value = param, key = alias)
else: else:
search_field_html = """<input name="%s" size="8" value="%s" />""" % (alias, cgi.escape(param)) search_field_html = """<input name="%s" size="8" value="%s" />""" % (alias, cgi.escape(param))
...@@ -2356,7 +2426,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer): ...@@ -2356,7 +2426,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer):
# Add data lines. # Add data lines.
selection = self.getSelection() selection = self.getSelection()
checked_uid_set = set(self.getCheckedUidList()) checked_uid_set = self.getCheckedUidSet()
for i, line in enumerate(line_list): for i, line in enumerate(line_list):
# Change the appearance of each line for visibility. # Change the appearance of each line for visibility.
...@@ -2503,6 +2573,8 @@ class ListBoxHTMLRenderer(ListBoxRenderer): ...@@ -2503,6 +2573,8 @@ class ListBoxHTMLRenderer(ListBoxRenderer):
return ''.join(html_list) return ''.join(html_list)
allow_class(ListBoxHTMLRenderer)
class ListBoxListRenderer(ListBoxRenderer): class ListBoxListRenderer(ListBoxRenderer):
"""This class implements list rendering for ListBox. """This class implements list rendering for ListBox.
""" """
...@@ -3047,7 +3119,7 @@ allow_class(ListBoxLine) ...@@ -3047,7 +3119,7 @@ allow_class(ListBoxLine)
# Psyco # Psyco
import psyco import psyco
psyco.bind(ListBoxWidget.render) #psyco.bind(ListBoxWidget.render)
psyco.bind(ListBoxValidator.validate) psyco.bind(ListBoxValidator.validate)
<tal:block
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
tal:define="field_id here/getId;
form_id python: here.getForm().id;
selection_name here/getSelectionName;
requested_selection_name here/getRequestedSelectionName;
selection_index here/getSelectionIndex;
selection here/getSelection;
portal_url_string here/getPortalUrlString;
real_context here/getContext;
context_url real_context/getUrl;
md5_string here/getMD5Checksum;
line_list here/query;
is_domain_tree_mode here/isDomainTreeMode;
is_report_tree_mode here/isReportTreeMode;
is_domain_tree_supported here/isDomainTreeSupported;
is_report_tree_supported here/isReportTreeSupported;
show_select_column here/showSelectColumn;
show_search_line here/showSearchLine;
">
<!-- ListBox starts here. -->
<input type="hidden" name="list_selection_name" value="default" tal:attributes="value selection_name" />
<input tal:condition="md5_string" type="hidden" name="md5_object_uid_list" value="checksum" tal:attributes="value md5_string" />
<tal:replace tal:content="nothing">
Because TAL cannot accept unbalanced tags, the support for a domain tree is realized by a macro.
The macro ListBoxContainer is a no-op, if not in domain tree mode. Otherwise, the macro constructs
a domain tree and extracts the body in an extra table.
</tal:replace>
<tal:block tal:define="expand python: 0">
<tal:block metal:define-macro="ListBoxContainer">
<tal:block tal:condition="expand">
<table tal:condition="is_domain_tree_mode"
border="0" cellpadding="0" cellspacing="0" width="100%"
tal:define="selected_domain_path here/getSelectedDomainPath">
<tr>
<td valign="top">
<select name="domain_root_url" onChange="submitAction(this.form, 'context/portal_selections/setDomainRoot')"
tal:attributes="onChange string:submitAction(this.form, '${context_url}/portal_selections/setDomainRoot')"
tal:repeat="c here/getDomainRootList">
<option value="base_domain"
tal:define="path python: c[0]; title python: c[1]"
tal:attributes="selected python: path == selected_domain_path; value path"
tal:content="title"
i18n:translate="" i18n:domain="ui">Base Domain</option>
</select>
<table id="listbox_domain_tree_table" cellpadding="0" border="0"
tal:attributes="id string:${field_id}_domain_tree_table"
tal:define="report_tree_list python: here.makeReportTreeList(report_path = selected_domain_path, unfolded_list = selection.getDomainList(), is_report_opened = False);
total_depth python: max([report_tree.depth for report_tree in report_tree_list] + [-1])">
<tr tal:repeat="report_tree report_tree_list">
<tal:block tal:repeat="i python: range(report_tree.depth)">
<td width="16" nowrap="nowrap">&nbsp;</td>
</tal:block>
<td nowrap="nowrap" valign="top" align="left" colspan="1"
tal:attributes="colspan python: total_depth - report_tree.depth + 1">
<a href="method"
tal:condition="report_tree/is_open"
tal:attributes="href string:portal_selections/foldDomain?domain_url=${report_tree/domain_url}&form_id=${form_id}&list_selection_name=${selection_name}&domain_depth:int=${report_tree/depth}">-&nbsp;<b tal:content="report_tree/obj/getTitleOrId" i18n:translate="" i18n:domain="ui">Domain</b></a>
<a href="method"
tal:condition="not: report_tree/is_open"
tal:attributes="href string:portal_selections/unfoldDomain?domain_url=${report_tree/domain_url}&form_id=${form_id}&list_selection_name=${selection_name}&domain_depth:int=${report_tree/depth}">+&nbsp;<tal:block tal:content="report_tree/obj/getTitleOrId" i18n:translate="" i18n:domain="ui">Domain</tal:block></a>
</td>
</tr>
</table>
</td>
<td valign="top">
<tal:block metal:define-slot="ListBoxBody" />
</td>
</tr>
</table>
<tal:block tal:condition="not: is_domain_tree_mode">
<tal:block metal:define-slot="ListBoxBody" />
</tal:block>
</tal:block>
</tal:block>
</tal:block>
<tal:block tal:define="expand python: 1">
<tal:block metal:use-macro="template/macros/ListBoxContainer">
<tal:block metal:fill-slot="ListBoxBody">
<div class="ListSummary">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td height="10">
<img src="Left.png" alt="left"
tal:attributes="src string:${portal_url_string}/images/Left.png" />
</td>
<td class="Top" colspan="2" height="10">
<img src="spacer.png" width="5" height="10" alt="spacer"
tal:attributes="src string:${portal_url_string}/images/spacer.png" />
</td>
<td class="Top" colspan="3" height="10">
<img src="spacer.png" width="5" height="10" alt="spacer"
tal:attributes="src string:${portal_url_string}/images/spacer.png" />
</td>
</tr>
<tr id="listbox_title_line" tal:attributes="id string:${field_id}_title_line">
<td class="Left" width="17">
<img src="spacer.png" width="5" height="5" alt="spacer"
tal:attributes="src string:${portal_url_string}/images/spacer.png" />
</td>
<td valign="middle" nowrap="nowrap">
<input tal:condition="python: is_domain_tree_supported or is_report_tree_supported"
type="image" src="text_block.png" id="listbox_flat_list_mode"
title="Flat List" name="portal_selections/setFlatListMode:method"
value="1" alt="Flat List"
tal:attributes="src string:${portal_url_string}/images/text_block.png;
id string:${field_id}_flat_list_mode"
i18n:domain="ui" i18n:attributes="title" />
<input tal:condition="is_report_tree_supported"
type="image" src="view_tree.png" id="listbox_report_tree_mode"
title="Report Tree" name="portal_selections/setReportTreeMode:method"
value="1" alt="Report Tree"
tal:attributes="src string:${portal_url_string}/images/view_tree.png;
id string:${field_id}_report_tree_mode"
i18n:domain="ui" i18n:attributes="title" />
<input tal:condition="is_domain_tree_supported"
type="image" src="view_choose.png" id="listbox_domain_tree_mode"
title="Domain Tree" name="portal_selections/setDomainTreeMode:method"
value="1" alt="Domain Tree"
tal:attributes="src string:${portal_url_string}/images/view_choose.png;
id string:${field_id}_domain_tree_mode"
i18n:domain="ui" i18n:attributes="title" />
</td>
<td width="100%" valign="middle">
&nbsp;
<a id="listbox_title" href="list"
tal:attributes="id string:${field_id}_title; href here/getListActionUrl"
tal:content="here/getTitle" i18n:domain="ui" i18n:translate="">Title</a>:
<span id="listbox_record_number"
tal:attributes="id string:${field_id}_record_number"
i18n:translate="" i18n:domain="ui"><tal:block tal:replace="here/total_size" i18n:name="number">0</tal:block> record(s)</span>
- <span id="listbox_item_number"
tal:attributes="id string:${field_id}_item_number"
i18n:translate="" i18n:domain="ui"><tal:block tal:replace="python: len(here.getCheckedUidList())" i18n:name="number">0</tal:block> item(s) selected</span>
</td>
<td nowrap="nowrap" valign="middle" align="center">
<input tal:condition="python: here.current_page > 0"
id="listbox_previous_page" type="image" src="1leftarrowv.png"
title="Previous Page" name="portal_selections/previousPage:method" border="0"
tal:attributes="id string:${field_id}_previous_page;
src string:${portal_url_string}/images/1leftarrowv.png"
i18n:domain="ui" i18n:attributes="title" />
</td>
<td nowrap="nowrap" valign="middle" align="center">
<select id="listbox_page_selection" name="list_start" title="Change Page" size="1"
onChange="submitAction(this.form, 'context/portal_selections/setPage')"
tal:define="lines here/getMaxLineNumber"
tal:attributes="id string:${field_id}_page_selection;
onChange string:submitAction(this.form, '${context_url}/portal_selections/setPage')"
i18n:domain="ui" i18n:attributes="title">
<option value="0"
tal:repeat="p python: range(0, here.total_pages)"
tal:attributes="selected python: p == here.current_page;
value python: p * lines"
i18n:domain="ui" i18n:translate=""><tal:block tal:replace="python: p + 1" i18n:name="page">0</tal:block> of <tal:block tal:replace="here/total_pages" i18n:name="total_pages">1</tal:block></option>
</select>
</td>
<td nowrap="nowrap" valign="middle" align="center">
<input tal:condition="python: here.current_page < here.total_pages - 1"
id="listbox_next_page" type="image" src="1rightarrowv.png"
title="Next Page" name="portal_selections/nextPage:method" border="0"
tal:attributes="id string:${field_id}_next_page;
src string:${portal_url_string}/images/1rightarrowv.png"
i18n:domain="ui" i18n:attributes="title" />
</td>
</tr>
</table>
</div>
<div class="ListContent">
<table cellpadding="0" cellspacing="0" border="0">
<tr id="listbox_label_line" tal:attributes="id string:${field_id}_label_line">
<td tal:condition="is_report_tree_mode"
class="Data" width="50" align="left" valign="middle">
<select name="report_root_url"
onChange="submitAction(this.form, 'context/portal_selections/setReportRoot')"
tal:attributes="onChange string:submitAction(this.form, '${context_url}/portal_selections/setReportRoot')">
<tal:block tal:repeat="c here/getReportRootList">
<option value="base_domain"
tal:define="path python: c[0]; title python: c[1]"
tal:attributes="selected python: path == here.getSelectedReportPath(); value path"
tal:content="title" i18n:domain="ui" i18n:translate="">Domain</option>
</tal:block>
</select>
</td>
<td tal:condition="show_select_column"
class="Data" width="50" align="center" valign="middle">
<input id="listbox_check_all" type="image"
name="portal_selections/checkAll:method" value="1"
src="checkall.png" border="0" alt="Check All" title="Check All"
tal:attributes="id string:${field_id}_check_all;
src string:${portal_url_string}/images/checkall.png"
i18n:domain="ui" i18n:attributes="title" />&nbsp;<input id="listbox_uncheck_all" type="image" name="portal_selections/uncheckAll:method" value="1"
src="%(portal_url_string)s/images/decheckall.png" border="0" alt="Uncheck All" title="Uncheck All"
tal:attributes="id string:${field_id}_uncheck_all;
src string:${portal_url_string}/images/decheckall.png"
i18n:domain="ui" i18n:attributes="title" />
</td>
<tal:block tal:repeat="value here/getLabelValueList">
<tal:block tal:define="sql python: value[0];
title python: value[1];
sort_order python: value[2]">
<td tal:condition="sql" class="Data">
<a href="portal_selections/setSelectionQuickSortOrder?selection_name=default&amp;sort_on=id"
tal:attributes="href string:portal_selections/setSelectionQuickSortOrder?selection_name=${selection_name}&amp;sort_on=${sql}"
tal:content="title" i18n:domain="ui" i18n:translate="">ID</a>
<img tal:condition="python: sort_order == 'ascending'"
src="1bottomarrow.png" alt="Ascending Display" title="Ascending Display"
tal:attributes="src string:${portal_url_string}/images/1bottomarrow.png"
i18n:domain="ui" i18n:attributes="title" />
<img tal:condition="python: sort_order == 'descending'"
src="1toparrow.png" alt="Descending Display" title="Descending Display"
tal:attributes="src string:${portal_url_string}/images/1toparrow.png"
i18n:domain="ui" i18n:attributes="title" />
</td>
<td tal:condition="not: sql" class="Data" tal:content="title"
i18n:domain="ui" i18n:translate="">
ID
</td>
</tal:block>
</tal:block>
</tr>
<tr tal:condition="python: show_search_line or is_report_tree_mode"
id="listbox_search_line"
tal:attributes="id python: show_search_line and ('%s_search_line' % field_id) or ('%s_report_depth_line' % field_id)">
<tal:block tal:condition="is_report_tree_mode">
<td class="Data" width="50" align="left" valign="middle" colspan="1"
tal:attributes="colspan python: show_search_line and 1 or (len(here.getSelectedColumnList()) + show_select_column + 1)"
tal:define="index python: selection_index is not None and '&amp;selection_index=%d' % selection_index or '';
is_report_opened python: not here.getSelection().isReportOpened();
url here/getUrl"><tal:block tal:repeat="i python: range(0, 6)">&nbsp;<a href="?selection_name=default&amp;selection_index=0&amp;report_depth:int=0"
tal:attributes="href string:${url}?selection_name=${requested_selection_name}${index}&amp;report_depth:int=${i}"
tal:content="i">0</a></tal:block>&nbsp;-&nbsp;<a href="?selection_name=default&amp;selection_index=0&amp;is_report_opened:int=0"
tal:attributes="href string:${url}?selection_name=${requested_selection_name}${index}&amp;is_report_opened:int=${is_report_opened}"
tal:content="python: is_report_opened and 'Show' or 'Hide'"
i18n:domain="ui" i18n:translate="">Show</a>
</td>
</tal:block>
<td tal:condition="python: show_select_column and show_search_line"
class="Data" width="50" align="center" valign="middle">
<input id="listbox_select" type="image" src="exec16.png"
title="Action" alt="Action" name="Base_doSelect:method"
tal:attributes="id string:${field_id}_select;
src string:${portal_url_string}/images/exec16.png"
i18n:domain="ui" i18n:attributes="title" />
</td>
<tal:block tal:condition="show_search_line"
tal:repeat="value here/getSearchValueList">
<td class="DataB"
tal:define="alias python: value[0];
param python: value[1];
search_field python: value[2]">
<font tal:condition="alias" size="-3">
<tal:block tal:condition="python: search_field is not None"
tal:replace="structure python: search_field.render(value = param, key = alias)" />
<input tal:condition="python: search_field is None" name="id" size="8" value=""
tal:attributes="name alias; value param" />
</font>
</td>
</tal:block>
</tr>
<tal:block tal:repeat="line line_list" tal:define="checked_uid_set here/getCheckedUidSet">
<tr id="listbox_data_line_0" class="DataA"
tal:define="css python: test(repeat['line'].index % 2, 'DataB', 'DataA')"
tal:attributes="id string:${field_id}_data_line_${repeat/line/index}; class css">
<td tal:condition="is_report_tree_mode" class="DataA" align="left" valign="middle"
tal:attributes="class css"
tal:define="section_name python: line.getContext() is not None and line.getContext().getTitleOrId() or ''">
<input type="hidden" value="1" name="listbox_uid:list"
tal:attributes="value python: line.getUid() or ''; name string:${field_id}_uid:list" />
<a tal:condition="section_name"
href="portal_selections/foldReport?report_url=base_domain&amp;form_id=form&amp;list_selection_name=default"
tal:define="method_id python: line.isOpen() and 'foldReport' or 'unfoldReport'"
tal:attributes="href string:portal_selections/${method_id}?report_url=${line/getDomainUrl}&amp;form_id=${form_id}&amp;list_selection_name=${selection_name}"
tal:content="structure python: '%s%s&nbsp;%s' % ('&nbsp;&nbsp;' * line.getDepth(), line.isOpen() and '-' or '+', section_name)" />
</td>
<td tal:condition="here/showSelectColumn"
class="DataA" width="50" align="center" valign="middle"
tal:attributes="class css">
<input tal:condition="python: not line.isSummary() and line.getObject() is not None"
type="checkbox" value="checked" id="listbox_cb_1" name="uids:list"
tal:attributes="checked python: line.getUid() in checked_uid_set;
value line/getUid;
id string:${field_id}_cb_${line/getUid}" />
<tal:block tal:condition="python: line.isSummary() or line.getObject() is None"></tal:block>
</td>
<tal:block tal:repeat="value line/render">
<td tal:define="html python: value[0];
original_value python: value[1];
error python: value[2]"
class="DataA" align="left"
tal:attributes="class python: error and (css + 'Error') or css;
align python: isinstance(original_value, (float, int, long)) and 'right' or 'left'"
tal:content="structure html" />
</tal:block>
</tr>
</tal:block>
<tr tal:condition="here/showStat" id="listbox_stat_line"
tal:attributes="id string:${field_id}_stat_line">
<td tal:condition="is_report_tree_mode" class="Data">&nsbp;</td>
<td tal:condition="show_select_column" class="Data">&nsbp;</td>
<tal:block tal:repeat="value here/getStatValueList">
<td class="Data" align="left"
tal:define="original_value python: value[0]; processed_value python: value[1]"
tal:attributes="align python: isinstance(original_value, (float, int, long)) and 'right' or 'left'"
tal:content="processed_value" />
</tal:block>
</tr>
</table>
</div>
</tal:block>
</tal:block>
</tal:block>
<!-- ListBox ends here. -->
</tal:block>
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