From 23bb0fd8cbd2f46db02d07d5503a3c788a6c9d3d Mon Sep 17 00:00:00 2001 From: Yoshinori Okuji <yo@nexedi.com> Date: Fri, 23 Jun 2006 05:07:09 +0000 Subject: [PATCH] Heavy rewrite with Page Template. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@8147 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5Form/ListBox.py | 82 +++++- product/ERP5Form/www/ListBox_asHTML.zpt | 323 ++++++++++++++++++++++++ 2 files changed, 400 insertions(+), 5 deletions(-) create mode 100644 product/ERP5Form/www/ListBox_asHTML.zpt diff --git a/product/ERP5Form/ListBox.py b/product/ERP5Form/ListBox.py index 5dbc549ee7..ae1257be0d 100644 --- a/product/ERP5Form/ListBox.py +++ b/product/ERP5Form/ListBox.py @@ -50,6 +50,7 @@ from ZODB.POSException import ConflictError from Globals import InitializeClass, Persistent, Acquisition, get_request from Products.PythonScripts.Utility import allow_class +from Products.PageTemplates.PageTemplateFile import PageTemplateFile import random import md5 @@ -102,6 +103,8 @@ class ReportTree: else: self.domain_url = relative_url +allow_class(ReportTree) + class ReportSection: """This class describes a report section. """ @@ -335,11 +338,19 @@ class ListBoxWidget(Widget.Widget): list_action = fields.StringField('list_action', title='List Action', description=('The id of the object action' - 'to display the current list'), + ' to display the current list'), default='list', required=1) 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'): """ Render a ListBox in read-only. @@ -858,6 +869,13 @@ class ListBoxRenderer: getCheckedUidList = VolatileCachingMethod(getCheckedUidList) + def getCheckedUidSet(self): + """Return the set of checked uids. + """ + return set(self.getCheckedUidList()) + + getCheckedUidSet = VolatileCachingMethod(getCheckedUidSet) + def getSelectedColumnList(self): """Return the list of selected columns. """ @@ -1916,7 +1934,7 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine): error = sys.exc_info()) else: 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: pass @@ -1930,6 +1948,19 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine): 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): """This class implements HTML rendering for ListBox. @@ -1983,6 +2014,27 @@ class ListBoxHTMLRenderer(ListBoxRenderer): 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): """Render the data in HTML. """ @@ -1998,6 +2050,24 @@ class ListBoxHTMLRenderer(ListBoxRenderer): selection.edit(method_path = method_path, list_url = list_url) 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. line_list = self.query() @@ -2335,7 +2405,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer): if alias is not None: # 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) else: search_field_html = """<input name="%s" size="8" value="%s" />""" % (alias, cgi.escape(param)) @@ -2356,7 +2426,7 @@ class ListBoxHTMLRenderer(ListBoxRenderer): # Add data lines. selection = self.getSelection() - checked_uid_set = set(self.getCheckedUidList()) + checked_uid_set = self.getCheckedUidSet() for i, line in enumerate(line_list): # Change the appearance of each line for visibility. @@ -2503,6 +2573,8 @@ class ListBoxHTMLRenderer(ListBoxRenderer): return ''.join(html_list) +allow_class(ListBoxHTMLRenderer) + class ListBoxListRenderer(ListBoxRenderer): """This class implements list rendering for ListBox. """ @@ -3047,7 +3119,7 @@ allow_class(ListBoxLine) # Psyco import psyco -psyco.bind(ListBoxWidget.render) +#psyco.bind(ListBoxWidget.render) psyco.bind(ListBoxValidator.validate) diff --git a/product/ERP5Form/www/ListBox_asHTML.zpt b/product/ERP5Form/www/ListBox_asHTML.zpt new file mode 100644 index 0000000000..cab22fe9fe --- /dev/null +++ b/product/ERP5Form/www/ListBox_asHTML.zpt @@ -0,0 +1,323 @@ +<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"> </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}">- <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}">+ <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"> + + <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" /> <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&sort_on=id" + tal:attributes="href string:portal_selections/setSelectionQuickSortOrder?selection_name=${selection_name}&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 '&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)"> <a href="?selection_name=default&selection_index=0&report_depth:int=0" + tal:attributes="href string:${url}?selection_name=${requested_selection_name}${index}&report_depth:int=${i}" + tal:content="i">0</a></tal:block> - <a href="?selection_name=default&selection_index=0&is_report_opened:int=0" + tal:attributes="href string:${url}?selection_name=${requested_selection_name}${index}&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&form_id=form&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}&form_id=${form_id}&list_selection_name=${selection_name}" + tal:content="structure python: '%s%s %s' % (' ' * 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> -- 2.30.9