Commit 3cd1b20e authored by Tristan Cavelier's avatar Tristan Cavelier Committed by Romain Courteaud

[erp5_web_renderjs_ui] Add "Equal to (at least one)" operator in filter editor

- the "Equal to (at least one)" operator is displayed in the same listbox as "Equal to" and "Contains" ;
- this filter item can have multiple input value field ;
- one input value field has to be filled (required) like on the other filter items ;
- when extended_search is `title: ( "One" OR "Two" )`, behavior changed :

    ________before________  ______________now______________

         Filter Editor               Filter Editor
    [ At least one (OR) v]  [ All criterions (AND)______ v]
    [-][ Title_________ v]  [-][ Title__________________ v]
       [ Equal to______ v]     [ Equal to (at least one) v]
       [ One___________ x]     [ One____________________ x]
    [-][ Title_________ v]     [ Two____________________ x]
       [ Equal to______ v]     [ _______________________  ]
       [ Two___________ x]  [+]
    [+]

         Search bar                  Search bar
    [One][Two][ _______  ]  [One][Two][ ________________  ]
parent e22aebf1
......@@ -5,6 +5,7 @@
data-i18n=At least one (OR)
data-i18n=Contains
data-i18n=Equal to
data-i18n=Equal to (at least one)
data-i18n=Greater than
data-i18n=Less than
data-i18n=Less than or Equal to
......@@ -47,7 +48,13 @@
{{/each}}
</select>
{{else}}
{{#if input_list}}
{{#each input_list}}
<input type="{{type}}" value="{{value}}" {{required}}></input>
{{/each}}
{{else}}
<input type="{{input_type}}" value="{{input_value}}" required></input>
{{/if}}
{{/if}}
</div>
</script>
......
......@@ -232,7 +232,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>970.21317.37622.46984</string> </value>
<value> <string>971.30474.16448.375</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -250,7 +250,7 @@
</tuple>
<state>
<tuple>
<float>1537370335.59</float>
<float>1550073322.86</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -20,6 +20,7 @@
],
OTHER = [
["Equal to", "exact_match"],
["Equal to (at least one)", "at_least_one_exact_match"],
["Contains", "keyword"]
],
DOMAIN = [
......@@ -39,31 +40,185 @@
value.indexOf('quantity') !== -1 ||
value.indexOf('price') !== -1;
}
function getComparisonOptionList(value) {
if (value.indexOf(PREFIX_COLUMN) === 0) {
if (isNumericComparison(value)) {
return NUMERIC;
}
return OTHER;
}
if (value.indexOf(PREFIX_DOMAIN) === 0) {
return DOMAIN;
}
return DEFAULT;
}
function makeFilterItemInput(param) {
var input = document.createElement("input");
input.type = param.type;
input.value = param.value;
return input;
}
function appendInputToFilterItem(item_element) {
item_element.appendChild(makeFilterItemInput({
type: "search",
value: ""
}));
}
function getFilterItemElementFromEvent(event, gadget_element) {
var element = event.target;
while (!element.classList.contains("filter_item")) {
element = element.parentElement;
if (!element || element === gadget_element) { return null; }
}
return element;
}
function updateFilterDOM(gadget) {
var item_list = gadget.element.querySelectorAll(".filter_item"),
input_list = null,
i = 0,
j = 0;
for (i = 0; i < item_list.length; i += 1) {
if ("at_least_one_exact_match" ===
item_list[i].querySelectorAll("select")[1].value) {
// remove empty inputs except last one and focused one
input_list = item_list[i].querySelectorAll("input");
for (j = input_list.length - 2; j >= 0; j -= 1) {
if (!input_list[j].value &&
input_list[j] !== document.activeElement) {
input_list[j].remove();
}
}
// remove last input if the one before the last is empty
input_list = item_list[i].querySelectorAll("input");
if (input_list.length >= 2 &&
!input_list[input_list.length - 1].value &&
!input_list[input_list.length - 2].value) {
input_list[input_list.length - 1].remove();
}
// append input if last one is not empty
input_list = item_list[i].querySelectorAll("input");
if (input_list[input_list.length - 1].value) {
appendInputToFilterItem(item_list[i]);
}
// put field required if there is no filled input
input_list = item_list[i].querySelectorAll("input");
if (input_list.length === 1) {
input_list[0].required = true;
}
} else {
// keep first input only
input_list = item_list[i].querySelectorAll("input");
for (j = input_list.length - 1; j > 0; j -= 1) {
input_list[j].remove();
}
}
}
}
function detectAtleastoneexactmatchComplexQuery(query) {
var i = 0, key = "", operator = "", difference_count = 0, value_list = [];
if (query.type !== "complex" || query.operator !== "OR") { return null; }
for (i = 0; i < query.query_list.length; i += 1) {
if (difference_count === 1) {
if (key !== (query.query_list[i].key || "") ||
operator !== (query.query_list[i].operator || "")) {
return null;
}
} else if (difference_count === 0) {
key = query.query_list[i].key || "";
operator = query.query_list[i].operator || "";
difference_count = 1;
}
}
return {key: key, operator: operator, value_list: value_list};
}
function createFilterItemTemplate(gadget, query_dict) {
var operator_default_list = DEFAULT,
operator_option_list = [],
column_option_list = [],
input_list = [],
input_type = "search",
i,
is_selected,
query_detail_dict,
domain_list,
domain_option_list;
if (query_dict.key.indexOf(PREFIX_COLUMN) === 0) {
if (isNumericComparison(query_dict.key)) {
operator_default_list = NUMERIC;
if (query_dict.key.indexOf("date") !== -1) {
input_type = "date";
} else {
input_type = "number";
}
query_detail_dict = detectAtleastoneexactmatchComplexQuery(query_dict);
if (query_detail_dict) {
operator_default_list = getComparisonOptionList(query_detail_dict.key);
if (operator_default_list !== OTHER) {
query_dict = query_dict.query_list[0] || {
type: "simple",
key: query_detail_dict.key,
value: query_detail_dict.value_list[0] || ""
};
query_detail_dict = null;
}
} else {
operator_default_list = getComparisonOptionList(query_dict.key);
}
if (query_detail_dict) {
is_selected = false;
for (i = 0; i < gadget.state.search_column_list.length; i += 1) {
is_selected = is_selected ||
(query_detail_dict.key === gadget.state.search_column_list[i][0]);
column_option_list.push({
text: gadget.state.search_column_list[i][1],
value: gadget.state.search_column_list[i][0],
selected: (query_detail_dict.key === gadget.state.search_column_list[i][0])
});
}
if (!is_selected) {
throw new Error('SearchEditor: no key found for: ' + query_detail_dict.key);
}
is_selected = false;
for (i = 0; i < operator_default_list.length; i += 1) {
is_selected = is_selected ||
("at_least_one_exact_match" === operator_default_list[i][1]);
operator_option_list.push({
text: operator_default_list[i][0],
value: operator_default_list[i][1],
selected: ("at_least_one_exact_match" === operator_default_list[i][1])
});
}
if (!is_selected) {
throw new Error('SearchEditor: no operator found for: at_least_one_exact_match');
}
for (i = 0; i < query_dict.query_list.length; i += 1) {
input_list.push({
type: "search",
value: query_dict.query_list[i].value,
required: ""
});
}
input_list.push({
type: "search",
value: "",
required: ""
});
return filter_item_template({
option: column_option_list,
operator_option: operator_option_list,
input_list: input_list,
domain_option: domain_option_list
});
}
if (operator_default_list === NUMERIC) {
if (query_dict.key.indexOf("date") !== -1) {
input_type = "date";
} else {
operator_default_list = OTHER;
input_type = "number";
}
} else if (query_dict.key.indexOf(PREFIX_DOMAIN) === 0) {
} else if (operator_default_list === DOMAIN) {
is_selected = false;
operator_default_list = DOMAIN;
input_type = "select";
domain_option_list = [];
domain_list = gadget.state.domain_dict[query_dict.key.slice(PREFIX_DOMAIN.length)];
......@@ -144,6 +299,31 @@
});
}
function getValueListFromElementList(element_list) {
var i = 0, value_list = [];
for (i = 0; i < element_list.length; i += 1) {
if (element_list[i].value) {
value_list.push(element_list[i].value);
}
}
return value_list;
}
function makeComplexQueryFromValueList(key, value_list, operator, logical_operator) {
var query_list = [],
complex = {type: "complex", operator: logical_operator, query_list: query_list},
i = 0;
for (i = 0; i < value_list.length; i += 1) {
query_list.push({
type: "simple",
key: key,
operator: operator,
value: value_list[i]
});
}
return complex;
}
function getQueryStateFromDOM(gadget) {
var operator_select = gadget.element.querySelector("select"),
state = {
......@@ -153,25 +333,69 @@
i,
filter_item_list = gadget.element.querySelectorAll(".filter_item"),
select_list,
key,
operator,
value;
for (i = 0; i < filter_item_list.length; i += 1) {
select_list = filter_item_list[i].querySelectorAll("select");
key = select_list[0][select_list[0].selectedIndex].value;
operator = select_list[1][select_list[1].selectedIndex].value;
if (select_list.length === 3) {
value = select_list[2][select_list[2].selectedIndex].value;
} else {
if (operator === "at_least_one_exact_match") {
value = getValueListFromElementList(
filter_item_list[i].querySelectorAll("input")
);
if (value.length > 1) {
state.query_list.push(makeComplexQueryFromValueList(key, value, "", "OR"));
/*jslint continue: true */
continue;
}
/*jslint continue: false */
}
value = filter_item_list[i].querySelector("input").value;
}
state.query_list.push({
type: "simple",
value: value,
operator: select_list[1][select_list[1].selectedIndex].value,
key: select_list[0][select_list[0].selectedIndex].value
operator: operator,
key: key
});
}
return state;
}
function queryRemovePrefixInDeep(query) {
var i = 0;
if (query.type === "simple") {
if (query.key.indexOf(PREFIX_COLUMN) === 0) {
query.key = query.key.slice(PREFIX_COLUMN.length);
} else if (query.key.indexOf(PREFIX_DOMAIN) === 0) {
query.key = query.key.slice(PREFIX_DOMAIN.length);
} else {
query.key = '';
}
} else {
for (i = 0; i < query.query_list.length; i += 1) {
queryRemovePrefixInDeep(query.query_list[i]);
}
}
}
function querySetKeyInDeep(query, key) {
var i = 0;
if (query.type === "complex") {
for (i = 0; i < query.query_list.length; i += 1) {
querySetKeyInDeep(query.query_list[i], key);
}
} else {
query.key = key;
}
}
function getElementIndex(node) {
var index = -1;
while (node) {
......@@ -199,6 +423,8 @@
jio_query,
len,
sub_jio_query,
sub_jio_query_dict,
sub_jio_query_detail_dict,
search_column_list = [],
search_column_dict = {},
search_domain_dict = {};
......@@ -265,6 +491,16 @@
} else if (jio_query instanceof ComplexQuery) {
operator = jio_query.operator;
sub_jio_query_dict = jio_query.toJSON();
sub_jio_query_detail_dict =
detectAtleastoneexactmatchComplexQuery(sub_jio_query_dict);
if (sub_jio_query_detail_dict &&
search_column_dict.hasOwnProperty(sub_jio_query_detail_dict.key)) {
querySetKeyInDeep(sub_jio_query_dict, PREFIX_COLUMN + sub_jio_query_detail_dict.key);
query_list.push(sub_jio_query_dict);
operator = "AND";
jio_query = {query_list: []}; // This line acts like a "go to end of this function"
}
len = jio_query.query_list.length;
for (i = 0; i < len; i += 1) {
......@@ -296,10 +532,22 @@
});
}
} else {
query_list.push({
key: PREFIX_RAW,
value: Query.objectToSearchText(sub_jio_query)
});
sub_jio_query_dict = sub_jio_query.toJSON();
sub_jio_query_detail_dict =
detectAtleastoneexactmatchComplexQuery(sub_jio_query_dict);
if (sub_jio_query_detail_dict &&
search_column_dict.hasOwnProperty(sub_jio_query_detail_dict.key)) {
querySetKeyInDeep(
sub_jio_query_dict,
PREFIX_COLUMN + sub_jio_query_detail_dict.key
);
query_list.push(sub_jio_query_dict);
} else {
query_list.push({
key: PREFIX_RAW,
value: Query.objectToSearchText(sub_jio_query)
});
}
}
}
}
......@@ -318,11 +566,12 @@
domain_dict: options.domain_dict,
// and/or
operator: operator,
focus_on: options.focus_on
focus_on: options.focus_on,
update_filter_dom: 0
});
})
.onStateChange(function onStateChange() {
.onStateChange(function onStateChange(modification_dict) {
var gadget = this,
container = gadget.element.querySelector(".container"),
div = document.createElement("div"),
......@@ -331,6 +580,12 @@
filter_item_container,
i;
if (modification_dict.update_filter_dom !== undefined &&
Object.keys(modification_dict).length === 1) {
updateFilterDOM(this);
return;
}
div.innerHTML = filter_template();
operator_select = div.querySelector("select");
......@@ -359,6 +614,10 @@
});
})
.declareJob('updateFilterDOM', function updateFilterDOM() {
return this.changeState({update_filter_dom: this.state.update_filter_dom + 1});
})
.declareJob('focusOnLastInput', function focusOnLastInput(index) {
var input_list = this.element.querySelectorAll('input');
if (index === undefined) {
......@@ -381,35 +640,34 @@
for (i = 0; i < len; i += 1) {
query = query_list[i];
if (query.operator === 'keyword') {
query.value = '%' + query.value + '%';
query.operator = '';
} else if (["", ">", "<", "<=", ">="].indexOf(query.operator) === -1) {
query.operator = '';
}
if (query.key === PREFIX_RAW) {
try {
jio_query_list.push(QueryFactory.create(query.value));
} catch (ignore) {
// If the value can not be parsed by jio, drop it
}
if (query.type === "complex") {
queryRemovePrefixInDeep(query);
jio_query_list.push(new ComplexQuery(query));
} else {
if (query.key.indexOf(PREFIX_COLUMN) === 0) {
query.key = query.key.slice(PREFIX_COLUMN.length);
} else if (query.key.indexOf(PREFIX_DOMAIN) === 0) {
query.key = query.key.slice(PREFIX_DOMAIN.length);
} else {
query.key = '';
if (query.operator === 'keyword') {
query.value = '%' + query.value + '%';
query.operator = '';
} else if (["", ">", "<", "<=", ">="].indexOf(query.operator) === -1) {
query.operator = '';
}
jio_query_list.push(new SimpleQuery({
key: query.key,
operator: query.operator,
type: "simple",
value: query.value
}));
if (query.key === PREFIX_RAW) {
try {
jio_query_list.push(QueryFactory.create(query.value));
} catch (ignore) {
// If the value can not be parsed by jio, drop it
}
} else {
queryRemovePrefixInDeep(query);
jio_query_list.push(new SimpleQuery({
key: query.key,
operator: query.operator,
type: "simple",
value: query.value
}));
}
}
}
......@@ -464,13 +722,28 @@
}
}, false, false)
.onEvent('input', function input(evt) {
var filter_item_element = getFilterItemElementFromEvent(evt, this.element);
if (filter_item_element) {
if (filter_item_element.querySelectorAll("select")[1].value ===
"at_least_one_exact_match") {
// This "if" exists only for performance reason,
// in order to run updateFilterDOM only if necessary.
this.updateFilterDOM();
}
}
}, false, false)
.onEvent('change', function change(evt) {
this.updateFilterDOM();
if (evt.target.classList.contains('column')) {
// Reset the operator when user change the column/key
evt.preventDefault();
var new_state = getQueryStateFromDOM(this),
index = getElementIndex(evt.target.parentElement.parentElement);
delete new_state.query_list[index].operator;
if (new_state.query_list[index].type !== "complex") {
delete new_state.query_list[index].operator;
}
return this.changeState(new_state);
}
}, false, false);
......
......@@ -228,7 +228,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>972.18557.43984.10752</string> </value>
<value> <string>973.42226.24018.7099</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -246,7 +246,7 @@
</tuple>
<state>
<tuple>
<float>1546525761.18</float>
<float>1550070921.26</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -135,6 +135,27 @@
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_id', 'value': '0', 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/add_new_filter_section" />
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_title', 'operator': 'at_least_one_exact_match', 'value': ['Title 0', 'Title 1'], 'index': 1}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_filter" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="parsed_query python: '( id:&nbsp; &#34;0&#34; AND title: (&nbsp; &#34;Title 0&#34; OR&nbsp; &#34;Title 1&#34; ) )';
search_query python: ''">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_title', 'operator': 'at_least_one_exact_match', 'value': ['Title 0', 'Title 1'], 'index': 1}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_filter_section" />
</tal:block>
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -94,12 +94,17 @@
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@class='filter_item_container']/div[1]//select[2]//option[2][@value='keyword' and text()='Contains']</td>
<td>//div[@class='filter_item_container']/div[1]//select[2]//option[2][@value='at_least_one_exact_match' and text()='Equal to (at least one)']</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@class='filter_item_container']/div[1]//select[2]//option[3][@value='keyword' and text()='Contains']</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[@class='filter_item_container']/div[1]//select[2]//option[3]</td>
<td>//div[@class='filter_item_container']/div[1]//select[2]//option[4]</td>
<td></td>
</tr>
<tr>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testFilterMultiValuedOperator</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" />
<!-- Clean Up -->
<tr>
<td>open</td>
<td>&#36;{base_url}/bar_module/ListBoxZuite_reset</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Reset Successfully.</td>
<td></td>
</tr>
<tr>
<td>open</td>
<td>&#36;{base_url}/foo_module/FooModule_createObjects</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Created Successfully.</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/wait_for_activities" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>&#36;{base_url}/web_site_module/renderjs_runner/#/bar_module</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n='Previous']</td>
<td></td>
</tr>
<!-- Prepare panel with a multi-valued operator -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_title', 'operator': 'at_least_one_exact_match', 'value': ['a', 'b'], 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<!-- Select a non-multi-valued operator -->
<tal:block tal:define="filter_section_configuration python: {'operator': 'keyword', 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<!-- Check if the multi-valued fields are gone and submit -->
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_title', 'value': ['a', None], 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_filter" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<!-- Prepare panel with a multi-valued operator -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_title', 'operator': 'at_least_one_exact_match', 'value': ['a', 'b'], 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<!-- Select a non-multi-valued operator -->
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_id', 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<!-- Check if the multi-valued fields are still present and submit -->
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_id', 'value': ['a', 'b'], 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_filter" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
</tbody></table>
</body>
</html>
\ No newline at end of file
......@@ -55,7 +55,7 @@
<!-- Open the panel and submit it. Check that the new query string is not to much changed -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'RAW', 'value': 'id: (&nbsp; &#34;2&#34; OR&nbsp; &#34;3&#34; )', 'index': 0}">
<tal:block tal:define="filter_section_configuration python: {'key': 'COLUMN_id', 'value': ['2', '3'], 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'key': 'TEXT', 'value': 'title', 'index': 1}">
......
......@@ -73,6 +73,36 @@
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'RAW', 'value': 'foo: (&nbsp; &#34;31085&#34; OR&nbsp; &#34;31086&#34; )', 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_filter" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="parsed_query python: 'foo: (&nbsp; &#34;31085&#34; OR&nbsp; &#34;31086&#34; )';
search_query python: ''">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_or" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/change_filter_to_and" />
<tal:block tal:define="filter_section_configuration python: {'key': 'RAW', 'value': 'bar:&nbsp; &#34;31084&#34;', 'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'key': 'RAW', 'value': 'foo: (&nbsp; &#34;31085&#34; OR&nbsp; &#34;31086&#34; )', 'index': 1}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/set_filter_section" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_filter" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="parsed_query python: '( bar:&nbsp; &#34;31084&#34; AND foo: (&nbsp; &#34;31085&#34; OR&nbsp; &#34;31086&#34; ) )';
search_query python: ''">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'index': 1}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
......
......@@ -124,17 +124,8 @@
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_or" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/triggle_filter_and" />
<tal:block tal:define="filter_section_configuration python: {'index': 3}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'index': 2}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'index': 1}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
<tal:block tal:define="filter_section_configuration python: {'index': 0}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/remove_filter_section" />
</tal:block>
......
......@@ -66,7 +66,7 @@
<tr>
<td>verifySelectOptions</td>
<td>//div[@class="filter_item_container"]/div[1]//select[2]</td>
<td>dengyu,baohang</td>
<td>dengyu,dengyu(zhishaoyige),baohang</td>
</tr>
......
......@@ -5,6 +5,7 @@ param_dict = [
{ 'message': 'Proceed', 'translation': 'jixu', 'language': 'wo'},
{ 'message': 'Title', 'translation': 'biaoti', 'language': 'wo'},
{ 'message': 'Equal to', 'translation': 'dengyu', 'language': 'wo'},
{ 'message': 'Equal to (at least one)', 'translation': 'dengyu(zhishaoyige)', 'language': 'wo'},
{ 'message': 'Contains', 'translation': 'baohang', 'language': 'wo'},
{ 'message': 'Search', 'translation': 'soushuo', 'language': 'wo'},
{ 'message': 'Next', 'translation': 'houyige', 'language': 'wo'},
......
......@@ -921,23 +921,38 @@
<tal:block metal:define-macro="set_filter_section">
<tr>
<td colspan="3"><b tal:content="python: 'Set the filter section %(index)i to %(key)s - %(value)s' % filter_section_configuration"></b></td>
<td colspan="3"><b tal:content="python: 'Set the filter section %i to %s %s %s' % (filter_section_configuration.get('index', '?'), filter_section_configuration.get('key', '-'), filter_section_configuration.get('operator', '-'), filter_section_configuration.get('value', '-'))"></b></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select' % (filter_section_configuration['index'] + 1)"></td>
<td></td>
</tr>
<tr>
<tr tal:condition="python: filter_section_configuration.get('key')">
<td>select</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select[@class=\'column\']' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: 'value=%s' % filter_section_configuration['key']"></td>
</tr>
<tr tal:condition="python: filter_section_configuration.get('operator')">
<td>select</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select[2]' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: 'value=%s' % filter_section_configuration['operator']"></td>
</tr>
<tal:block tal:condition="python: 'value' in filter_section_configuration">
<tal:block tal:define="_set_filter_section_value_list python: filter_section_configuration['value'] if isinstance(filter_section_configuration['value'], (tuple, list)) else [filter_section_configuration['value']]"
tal:repeat="_set_filter_section_index python: range(len(_set_filter_section_value_list))">
<tr>
<td>waitForElementPresent</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input[%i]' % (filter_section_configuration['index'] + 1, _set_filter_section_index + 1)"></td>
<td></td>
</tr>
<tr>
<td>type</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: filter_section_configuration['value']"></td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input[%i]' % (filter_section_configuration['index'] + 1, _set_filter_section_index + 1)"></td>
<td tal:content="python: _set_filter_section_value_list[_set_filter_section_index]"></td>
</tr>
</tal:block>
</tal:block>
<tr>
<td colspan="3"><p></p></td>
</tr>
......@@ -957,6 +972,30 @@
</tr>
</tal:block>
<tal:block metal:define-macro="change_filter_to_and">
<tr>
<td colspan="3"><b>Change the filter to AND mode</b></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_search_editor.html')]//select[@name='heard_about']</td>
<td></td>
</tr>
<tr>
<td>select</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_search_editor.html')]//select[@name='heard_about']</td>
<td>index=0</td>
</tr>
<tr>
<td>verifyValue</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_search_editor.html')]//select[@name='heard_about']</td>
<td>AND</td>
</tr>
<tr>
<td colspan="3"><p></p></td>
</tr>
</tal:block>
<tal:block metal:define-macro="change_filter_to_or">
<tr>
<td colspan="3"><b>Change the filter to OR mode</b></td>
......@@ -1017,14 +1056,27 @@
</tr>
<tr>
<td>verifyValue</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select[@class=\'column\']' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: filter_section_configuration['key']"></td>
</tr>
<tr>
<tr tal:condition="python: filter_section_configuration.get('operator')">
<td>verifyValue</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: filter_section_configuration['value']"></td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//select[2]' % (filter_section_configuration['index'] + 1)"></td>
<td tal:content="python: filter_section_configuration['operator']"></td>
</tr>
<tal:block tal:define="_check_filter_section_value_list python: filter_section_configuration['value'] if isinstance(filter_section_configuration['value'], (tuple, list)) else [filter_section_configuration['value']]"
tal:repeat="_check_filter_section_index python: range(len(_check_filter_section_value_list))">
<tr tal:condition="python: _check_filter_section_value_list[_check_filter_section_index] is not None">
<td>verifyValue</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input[%i]' % (filter_section_configuration['index'] + 1, _check_filter_section_index + 1)"></td>
<td tal:content="python: _check_filter_section_value_list[_check_filter_section_index]"></td>
</tr>
<tr tal:condition="python: _check_filter_section_value_list[_check_filter_section_index] is None">
<td>verifyElementNotPresent</td>
<td tal:content="python: '//div[contains(@data-gadget-url, \'gadget_erp5_search_editor.html\')]//div[@class=\'filter_item_container\']/div[%i]//input[%i]' % (filter_section_configuration['index'] + 1, _check_filter_section_index + 1)"></td>
<td></td>
</tr>
</tal:block>
<tr>
<td colspan="3"><p></p></td>
</tr>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment