Commit fced4e25 authored by Jérome Perrin's avatar Jérome Perrin

"Disable Node" option for categories

Since a89afa43 (Formulator: Support disabled items in all ItemWidget subclasses., 2014-04-02) we can include disabled items in listfields.
This was used for example in erp5_crm to show the services with their hierarchy as disabled items and was useful to display the hierarchy.

In some fields, we don't want user to select "nodes" categories, but only select "leaves" categories (ie. select the most precise category).
This always had a problem when using "Indented title" as display method for categories, because the user can not see the actual hierarchy. This is about making it possible to display hierarchy of categories in this case where we select only leaves, so that it displays like this:

![screenshot of a category with disabled items for hierarchy](/uploads/0f3e8ef68ab6e2ec424e4e8d42fc5e2a/image.png)

This required to:

 - introduce a new category API, `disable_node`, which is semantically very close to `filter_node` except that instead of filtering out node categories that are kept with `None` as related URL. Symmetrically, we also introduce `disable_leave`
 - make `ParallelListField` support disabled items. Even if this was properly supported in underlying fields, some parts in `ParallelListField` did not differentiate between `None` and `''`.
 - modify several forms to use `disable_node` instead of `filter_node`

See merge request !1199
parents d8ab59d1 4a6f3956
...@@ -27,11 +27,11 @@ if context.getSubordination(): ...@@ -27,11 +27,11 @@ if context.getSubordination():
function_value = subordination_value.getFunctionValue() function_value = subordination_value.getFunctionValue()
if function_value is not None: if function_value is not None:
result.extend(getattr(function_value, category_child_item_list_method_id)( result.extend(getattr(function_value, category_child_item_list_method_id)(
filter_node=1, local_sort_id=local_sort_id_list)) local_sort_id=local_sort_id_list, disable_node=True))
result.extend(getattr( result.extend(getattr(
portal.portal_categories.function, portal.portal_categories.function,
category_child_item_list_method_id)( category_child_item_list_method_id)(
filter_node=1, local_sort_id=local_sort_id_list)) local_sort_id=local_sort_id_list, disable_node=True))
return result return result
...@@ -480,7 +480,7 @@ def renderField(traversed_document, field, form, value=MARKER, meta_type=None, k ...@@ -480,7 +480,7 @@ def renderField(traversed_document, field, form, value=MARKER, meta_type=None, k
# Copy the dict, as some hashscript cache the result, # Copy the dict, as some hashscript cache the result,
# which should not in this case be modified # which should not in this case be modified
result.update({"subfield_list": [x.copy() for x in getattr(field, hash_script_id)( result.update({"subfield_list": [x.copy() for x in getattr(field, hash_script_id)(
[x for x in result['items'] if (x[1] and x[0])], [x for x in result['items'] if (x[1] != '' and x[0] != '')],
# Drop empty values # Drop empty values
result['default'], result['default'],
default_sub_field_property_dict={ default_sub_field_property_dict={
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>title</string>
<string>items</string> <string>items</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -71,6 +71,10 @@ ...@@ -71,6 +71,10 @@
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
...@@ -86,6 +90,12 @@ ...@@ -86,6 +90,12 @@
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
...@@ -108,7 +118,7 @@ ...@@ -108,7 +118,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories[field.getId().replace(\'my_\', \'\', 1).replace(\'_list\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', filter_node=1)</string> </value> <value> <string>python: getattr(here.portal_categories[field.getId().replace(\'my_\', \'\', 1).replace(\'_list\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', disable_node=True)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>items</string>
<string>title</string> <string>title</string>
</list> </list>
</value> </value>
...@@ -60,6 +61,12 @@ ...@@ -60,6 +61,12 @@
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -83,6 +90,12 @@ ...@@ -83,6 +90,12 @@
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
...@@ -97,4 +110,17 @@ ...@@ -97,4 +110,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories[field.getId().replace(\'my_\', \'\', 1).replace(\'_list\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', disable_node=True)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Resource_viewFieldLibrary</string> </value> <value> <string>Base_viewPDMFieldLibrary</string> </value>
</item> </item>
</dictionary> </dictionary>
</value> </value>
......
...@@ -9,9 +9,7 @@ ...@@ -9,9 +9,7 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list/>
<string>items</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -60,12 +58,6 @@ ...@@ -60,12 +58,6 @@
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -95,17 +87,4 @@ ...@@ -95,17 +87,4 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories[field.getId().replace(\'my_\', \'\', 1).replace(\'_list\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', filter_node=1)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
<?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>resource_quantity_unit</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>
<head><title>Test setting quantity unit</title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4">
Test setting quantity unit
</td></tr>
</thead>
<tbody tal:define="init_method string:PdmZuite_createDelivery?state=draft&delivery_type=Internal">
<tal:block metal:use-macro="here/PdmZuite_CommonTemplate/macros/init" />
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_quantity_unit_list_default:list"]</td>
<td>label=Unit/Piece</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//select[@name="subfield_field_my_quantity_unit_list_default:list"]/option[@disabled and text()="Mass"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_quantity_unit_list_default:list"])[2]/option[@disabled and text()="Mass"]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_quantity_unit_list_default:list"])[2]</td>
<td>label=</td>
</tr>
<tr>
<td>select</td>
<td>xpath=(//select[@name="subfield_field_my_quantity_unit_list_default:list"])[2]</td>
<td>label=Mass/Ton</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_quantity_unit_list_default:list"]</td>
<td>label=Unit/Piece</td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_quantity_unit_list_default:list"])[2]</td>
<td>label=Mass/Ton</td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_quantity_unit_list_default:list"])[3]</td>
<td>label=</td>
</tr>
<tr>
<td>open</td>
<td>${base_url}/foo_module/Zuite_waitForActivities</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Done.</td>
<td></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="Zuite" module="Products.Zelenium.zuite"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>parallel_list_field_zuite</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?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>testDisableNode_Base_getMultiListFieldPropertyDictList</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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test ParallelListField with Base_getMultiListFieldPropertyDictList and disable_node option of CMFCategory</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test ParallelListField with Base_getMultiListFieldPropertyDictList and disable_node option of CMFCategory</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/PTZuite_CommonTemplate/macros/init" />
<tr>
<td>open</td>
<td>${base_url}/foo_module/1/Foo_viewParallelListField</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@name="field_my_title" and @value="Base_getMultiListFieldPropertyDictList"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@name="field_my_reference" and @value="disable_node"]</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Empty value by default</b></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//select[@name="subfield_field_my_category_list_foo_big_category"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//select[@name="subfield_field_my_category_list_foo_big_category"]/option[@selected]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//select[@name="subfield_field_my_category_list_foo_category"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//select[@name="subfield_field_my_category_list_foo_category"]/option[@selected]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>disabled categories are not displayed</b> see <code>Base_getMultiListFieldPropertyDictList</code>, this script does not fully support disabled nodes. </td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]/option[text() = "a"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Set values</b></td>
</tr>
<tr>
<td>select</td>
<td>//select[@name="subfield_field_my_category_list_foo_big_category"]</td>
<td>label=c1</td>
</tr>
<tr>
<td>select</td>
<td>//select[@name="subfield_field_my_category_list_foo_category"]</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td>foo_big_category/c1 foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_category_list_foo_big_category"]</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_category_list_foo_category"]</td>
<td>label=a/a1</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>testDisableNode_Base_hashCategoryList</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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test ParallelListField with Base_hashCategoryList and disable_node option of CMFCategory</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test ParallelListField with Base_hashCategoryList and disable_node option of CMFCategory</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/PTZuite_CommonTemplate/macros/init" />
<tr>
<td>open</td>
<td>${base_url}/foo_module/1/Foo_viewParallelListField</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@name="field_my_title" and @value="Base_hashCategoryList"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@name="field_my_reference" and @value="disable_node"]</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Empty value by default</b></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Node categories appear has disabled</b></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Set first value</b></td>
</tr>
<tr>
<td>select</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]</td>
<td>label=c1</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td>foo_big_category/c1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//select[@name="subfield_field_my_category_list_default:list"]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[3]</td>
<td>/td>
</tr>
<tr>
<td colspan="3"><b>Set second value</b></td>
</tr>
<tr>
<td>select</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td>foo_big_category/c1 foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[1]</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[1]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[3]</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[3]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[4]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Remove first value</b></td>
</tr>
<tr>
<td>select</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[1]</td>
<td>label=</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//div[@class="field"]/label[normalize-space(text())="Categories"]/../div</td>
<td>foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[1]</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[1]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[2]/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>xpath=(//select[@name="subfield_field_my_category_list_default:list"])[3]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
<list> <list>
<string>my_title</string> <string>my_title</string>
<string>my_category_list</string> <string>my_category_list</string>
<string>my_reference</string>
</list> </list>
</value> </value>
</item> </item>
......
...@@ -130,7 +130,7 @@ ...@@ -130,7 +130,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: [item for sub_list in [here.portal_categories[base_category].getCategoryChildCompactLogicalPathItemList(base=1) for base_category in [\'foo_category\', \'foo_big_category\']] for item in sub_list]</string> </value> <value> <string>python: [item for sub_list in [here.portal_categories[base_category].getCategoryChildCompactLogicalPathItemList(base=1, disable_node=(here.getReference() == \'disable_node\')) for base_category in [\'foo_category\', \'foo_big_category\']] for item in sub_list]</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="RadioField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_reference</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>unknown_selection</string> </key>
<value> <string>You selected an item that was not in the list.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra_item</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>first_item</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list>
<tuple>
<string></string>
<string></string>
</tuple>
<tuple>
<string>disable_node</string>
<string>disable_node</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>orientation</string> </key>
<value> <string>vertical</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Extra Feature</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -35,6 +35,8 @@ portal_tests/ooo_import_zuite ...@@ -35,6 +35,8 @@ portal_tests/ooo_import_zuite
portal_tests/ooo_import_zuite/** portal_tests/ooo_import_zuite/**
portal_tests/page_templates_zuite portal_tests/page_templates_zuite
portal_tests/page_templates_zuite/** portal_tests/page_templates_zuite/**
portal_tests/parallel_list_field_zuite
portal_tests/parallel_list_field_zuite/**
portal_tests/planning_box_field_zuite portal_tests/planning_box_field_zuite
portal_tests/planning_box_field_zuite/** portal_tests/planning_box_field_zuite/**
portal_tests/proxy_field_zuite portal_tests/proxy_field_zuite
......
<?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>testDisableNode_Base_getMultiListFieldPropertyDictList</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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS UI</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/foo_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<!-- Go to test form -->
<tal:block tal:define="click_configuration python: {'text': 'Parallel List Field'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_panel_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>click</td>
<td>//label[contains(text(), 'Base_getMultiListFieldPropertyDictList')]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//label[contains(text(), 'disable_node')]</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td colspan="3"><b>Empty value by default</b></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_3']</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>disabled categories are not displayed</b> see <code>Base_getMultiListFieldPropertyDictList</code>, this script does not fully support disabled nodes. </td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select/option[text() = "a"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Set values</b></td>
</tr>
<tr>
<td>select</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=c1</td>
</tr>
<tr>
<td>select</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=a/a1</td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td>foo_big_category/c1 foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_2']</td>
<td></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>testDisableNode_Base_hashCategoryList</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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test RenderJS UI</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test RenderJS UI</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/foo_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<!-- Go to test form -->
<tal:block tal:define="click_configuration python: {'text': 'Parallel List Field'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_panel_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>click</td>
<td>//label[contains(text(), 'Base_hashCategoryList')]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//label[contains(text(), 'disable_node')]</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td colspan="3"><b>Empty value by default</b></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']</td>
<td></td>
</tr>
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Node categories appear has disabled</b></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Set first value</b></td>
</tr>
<tr>
<td>select</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=c1</td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td>foo_big_category/c1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_2']</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Set second value</b></td>
</tr>
<tr>
<td>select</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=a/a1</td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td>foo_big_category/c1 foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=c1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_2']//select</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_2']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_3']//select</td>
<td></td>
</tr>
<tr>
<td colspan="3"><b>Remove first value</b></td>
</tr>
<tr>
<td>select</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=</td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td>assertText</td>
<td>//p[@id="field_category_list"]</td>
<td>foo_category/a/a1</td>
</tr>
<tr>
<td>assertSelected</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select</td>
<td>label=a/a1</td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_0']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_1']//select/option[@disabled and text() = "a"]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@data-gadget-scope='field_my_category_list']//div[@data-gadget-scope='PARALLEL_SUB_FIELD_2']</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
...@@ -64,32 +64,26 @@ class Filter(Implicit): ...@@ -64,32 +64,26 @@ class Filter(Implicit):
self.filter_node = filter_node self.filter_node = filter_node
self.filter_leave = filter_leave self.filter_leave = filter_leave
def _isNode(self, context):
return bool(context.contentIds(filter={'portal_type' : 'Category'}))
def test(self, context): def test(self, context):
""" """
Test filter on a context Test filter on a context
""" """
#LOG('Filter test', 0, 'context = %s' % repr(context)) if self.filter_node and self._isNode(context):
is_node = None return False
if self.filter_node: if self.filter_leave and not self._isNode(context):
is_node = len(context.contentIds(filter={'portal_type' : 'Category'})) return False
if is_node:
return 0
if self.filter_leave:
if is_node is None:
# Only recalculate is_node if not already done
is_node = len(context.contentIds(filter={'portal_type' : 'Category'}))
if not is_node:
return 0
for k, v in self.filter_dict.items(): for k, v in self.filter_dict.items():
#LOG('Filter test', 0, "k = %s, v = %s" % (repr(k), repr(v)))
if type(v) in (type([]), type(())): if type(v) in (type([]), type(())):
if context.getProperty(k) not in v: if context.getProperty(k) not in v:
return 0 return False
elif context.getProperty(k) != v: elif context.getProperty(k) != v:
return 0 return False
if self.filter_method is not None: if self.filter_method is not None:
return self.filter_method(context) return self.filter_method(context)
return 1 return True
def asDict(self): def asDict(self):
......
...@@ -43,7 +43,8 @@ class Renderer(Filter): ...@@ -43,7 +43,8 @@ class Renderer(Filter):
def __init__(self, spec = None, filter = None, portal_type = None, def __init__(self, spec = None, filter = None, portal_type = None,
display_id = None, sort_id = None, display_id = None, sort_id = None,
display_method = None, sort_method = None, filter_method = None, display_method = None, sort_method = None, filter_method = None,
filter_node=0, filter_leave=0, filter_node=0, disable_node=0,
filter_leave=0, disable_leave=0,
is_right_display = 0, translate_display = 0, is_right_display = 0, translate_display = 0,
translatation_domain = None, display_base_category = 0, translatation_domain = None, display_base_category = 0,
base_category = None, base = 1, base_category = None, base = 1,
...@@ -58,8 +59,12 @@ class Renderer(Filter): ...@@ -58,8 +59,12 @@ class Renderer(Filter):
- *filter_node*: do not keep node categories - *filter_node*: do not keep node categories
- *disable_node*: return node categories as disabled (ie. None instead of their relative URL)
- *filter_leave*: do not keep leave categories - *filter_leave*: do not keep leave categories
- *disable_leave*: return leave categories as disabled (ie. None instead of their relative URL)
- *sort_id*: the id of the attribute to "call" to calculate the value used for sorting. - *sort_id*: the id of the attribute to "call" to calculate the value used for sorting.
Sorting is only applied to default ItemList items. Sorting is only applied to default ItemList items.
...@@ -99,7 +104,8 @@ class Renderer(Filter): ...@@ -99,7 +104,8 @@ class Renderer(Filter):
""" """
Filter.__init__(self, spec=spec, filter=filter, Filter.__init__(self, spec=spec, filter=filter,
portal_type=portal_type, filter_method=filter_method, portal_type=portal_type, filter_method=filter_method,
filter_node=filter_node, filter_leave=filter_leave) filter_node=filter_node and not disable_node,
filter_leave=filter_leave and not disable_leave)
self.display_id = display_id self.display_id = display_id
self.sort_id = sort_id self.sort_id = sort_id
self.display_method = display_method self.display_method = display_method
...@@ -111,6 +117,8 @@ class Renderer(Filter): ...@@ -111,6 +117,8 @@ class Renderer(Filter):
self.base_category = base_category self.base_category = base_category
self.base = base self.base = base
self.display_none_category = display_none_category self.display_none_category = display_none_category
self.disable_node = disable_node
self.disable_leave = disable_leave
def getObjectList(self, value_list): def getObjectList(self, value_list):
new_value_list = [] new_value_list = []
...@@ -222,6 +230,11 @@ class Renderer(Filter): ...@@ -222,6 +230,11 @@ class Renderer(Filter):
bc_title = getattr(bc, base_category_display_method_id)() bc_title = getattr(bc, base_category_display_method_id)()
label = '%s/%s' % (bc_title, label) label = '%s/%s' % (bc_title, label)
if self.disable_node and self._isNode(value):
url = None
if self.disable_leave and not self._isNode(value):
url = None
if self.is_right_display: if self.is_right_display:
item = [url, label] item = [url, label]
else: else:
......
...@@ -755,6 +755,58 @@ class TestCMFCategory(ERP5TypeTestCase): ...@@ -755,6 +755,58 @@ class TestCMFCategory(ERP5TypeTestCase):
whitespace_number = self.portal.portal_preferences.getPreferredWhitespaceNumberForChildItemIndentation() whitespace_number = self.portal.portal_preferences.getPreferredWhitespaceNumberForChildItemIndentation()
self.assertEqual(NBSP_UTF8 * whitespace_number + 'The Sub Title', sub_cat.getIndentedTitle()) self.assertEqual(NBSP_UTF8 * whitespace_number + 'The Sub Title', sub_cat.getIndentedTitle())
def test_CategoryChildTitleItemListFilterNodeFilterLeave(self):
base_cat = self.getCategoryTool().newContent(portal_type='Base Category')
base_cat.newContent(
portal_type='Category',
id='the_id',
title='The Title'
).newContent(
portal_type='Category',
id='the_sub_id',
title='The Sub Title')
self.assertEqual(
base_cat.getCategoryChildTitleItemList(filter_node=True),
[
['', ''],
['The Sub Title', 'the_id/the_sub_id'],
]
)
self.assertEqual(
base_cat.getCategoryChildTitleItemList(filter_leave=True),
[
['', ''],
['The Title', 'the_id'],
]
)
def test_CategoryChildTitleItemListDisableNodeDisableLeave(self):
base_cat = self.getCategoryTool().newContent(portal_type='Base Category')
base_cat.newContent(
portal_type='Category',
id='the_id',
title='The Title'
).newContent(
portal_type='Category',
id='the_sub_id',
title='The Sub Title')
self.assertEqual(
base_cat.getCategoryChildTitleItemList(disable_node=True),
[
['', ''],
['The Title', None],
['The Sub Title', 'the_id/the_sub_id'],
]
)
self.assertEqual(
base_cat.getCategoryChildTitleItemList(disable_leave=True),
[
['', ''],
['The Title', 'the_id'],
['The Sub Title', None],
]
)
def test_20_CategoryChildTitleAndIdItemList(self): def test_20_CategoryChildTitleAndIdItemList(self):
"""Tests getCategoryChildTitleAndIdItemList.""" """Tests getCategoryChildTitleAndIdItemList."""
base_cat = self.getCategoryTool().newContent(portal_type='Base Category') base_cat = self.getCategoryTool().newContent(portal_type='Base Category')
......
...@@ -10,7 +10,15 @@ maximum_list_size = 5 ...@@ -10,7 +10,15 @@ maximum_list_size = 5
for item in item_list: for item in item_list:
# Get value of the item # Get value of the item
item_value = item[int(not is_right_display)] item_value = item[int(not is_right_display)]
# Hash key from item_value
# Hash key from item_value (the relative_url), so that different base categories
# appear as multiple multi list fields.
# The item_list can contain entries with None as relative_url, like when using
# disable_node option of CMFCategory. This case is not supported by this script,
# because heuristics to put the None entry in one or another subfield group
# are not implemented here.
if item_value is None:
continue
item_split = item_value.split('/') item_split = item_value.split('/')
item_key = '/'.join(item_split[:split_depth]) item_key = '/'.join(item_split[:split_depth])
base_category = item_split[0] base_category = item_split[0]
......
...@@ -18,7 +18,7 @@ default_sub_field_property_dict.update(title='&nbsp;', ...@@ -18,7 +18,7 @@ default_sub_field_property_dict.update(title='&nbsp;',
field_type='ListField', field_type='ListField',
size=1, size=1,
item_list=[('', '')] + item_list, item_list=[('', '')] + item_list,
value=None) value='')
for value in value_list: for value in value_list:
new_dict = default_sub_field_property_dict.copy() new_dict = default_sub_field_property_dict.copy()
new_dict['value'] = value new_dict['value'] = value
......
...@@ -229,7 +229,7 @@ class ParallelListField(ZMIField): ...@@ -229,7 +229,7 @@ class ParallelListField(ZMIField):
def generateSubForm(self, value, REQUEST): def generateSubForm(self, value, REQUEST):
item_list = [x for x in self.get_value('items', REQUEST=REQUEST) item_list = [x for x in self.get_value('items', REQUEST=REQUEST)
if x[0] != '' and x[1]] if x[0] != '' and x[1] != '']
value_list = value value_list = value
if not isinstance(value_list, (list, tuple)): if not isinstance(value_list, (list, tuple)):
......
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