Commit 25ebd6b6 authored by Sebastien Robin's avatar Sebastien Robin

erp5_web_renderjs_ui: enable keyboard to navigate relation field menu

Also, manually handle mouseover for highlighting relation field menu lines instead
of using css. Indeed, we have to manually handle possibility that highlight could
be done either by mouse or by keyboard.
parent 6c50713a
...@@ -1315,8 +1315,7 @@ div[data-gadget-scope='header'] .ui-header ul { ...@@ -1315,8 +1315,7 @@ div[data-gadget-scope='header'] .ui-header ul {
.relation-input ul li::before { .relation-input ul li::before {
padding-right: 6pt; padding-right: 6pt;
} }
.relation-input ul li:hover, .relation-input ul .active {
.relation-input ul li:active {
background-color: #1F1F1F; background-color: #1F1F1F;
} }
.relation-input .ui-icon-warning { .relation-input .ui-icon-warning {
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
SimpleQuery, ComplexQuery, Query, QueryFactory, document, XMLHttpRequest, SimpleQuery, ComplexQuery, Query, QueryFactory, document, XMLHttpRequest,
console*/ console*/
(function (window, rJS, RSVP, URI, document, (function (window, rJS, RSVP, URI, document,
SimpleQuery, ComplexQuery, Query, QueryFactory, XMLHttpRequest, console) { SimpleQuery, ComplexQuery, Query, QueryFactory, XMLHttpRequest, console,
MouseEvent) {
"use strict"; "use strict";
function displayNonEditableLink(gadget) { function displayNonEditableLink(gadget) {
...@@ -509,7 +510,6 @@ ...@@ -509,7 +510,6 @@
data_explore, data_explore,
new_state = {}, new_state = {},
tag_name = evt.target.tagName.toLowerCase(); tag_name = evt.target.tagName.toLowerCase();
if (tag_name === 'button') { if (tag_name === 'button') {
// Go to the search listbox // Go to the search listbox
return redirectToTheSearchListbox(gadget); return redirectToTheSearchListbox(gadget);
...@@ -548,6 +548,82 @@ ...@@ -548,6 +548,82 @@
} }
} }
}, false, false) }, false, false)
.onEvent('keydown', function (evt) {
var gadget = this,
i,
next_event,
active_index,
ul = gadget.element.querySelector(".search_ul");
if (evt.key === "ArrowDown" || evt.key === "ArrowUp") {
if (ul.childNodes.length > 0) {
for (i = 0; i < ul.childNodes.length; i += 1) {
if (ul.childNodes[i].className.endsWith('active')) {
active_index = i;
}
}
if (active_index === undefined) {
if (evt.key === "ArrowDown") {
active_index = 0;
} else if (evt.key === "ArrowUp") {
active_index = ul.childNodes.length - 1;
}
} else {
if (evt.key === "ArrowDown") {
active_index = active_index + 1;
} else if (evt.key === "ArrowUp") {
active_index = active_index - 1;
}
if (active_index >= ul.childNodes.length) {
active_index = 0;
}
else if (active_index === -1) {
active_index = ul.childNodes.length - 1;
}
}
for (i = 0; i < ul.childNodes.length; i += 1) {
if (i === active_index) {
if (!ul.childNodes[i].className.endsWith("active")) {
ul.childNodes[i].className = ul.childNodes[i].className +
" active";
}
} else {
if (ul.childNodes[i].className.endsWith("active")) {
ul.childNodes[i].className = ul.childNodes[i].className.replace(
" active", "");
}
}
}
evt.preventDefault();
}
} else if (evt.key === "Enter") {
for (i = 0; i < ul.childNodes.length; i += 1) {
if (ul.childNodes[i].className.endsWith('active')) {
next_event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
ul.childNodes[i].dispatchEvent(next_event);
evt.preventDefault();
}
}
}
}, true, false)
.onEvent('mouseover', function (evt) {
// Do not use li:hover css syntax, since we have to disable manually
// the highlightnment when keyboard is used
var gadget = this,
i,
ul = gadget.element.querySelector(".search_ul");
if (evt.target.tagName.toLowerCase() === 'li') {
for (i = 0; i < ul.childNodes.length; i += 1) {
ul.childNodes[i].className = ul.childNodes[i].className.replace(
" active", "");
}
evt.target.className = evt.target.className + " active";
}
}, true, false)
.declareAcquiredMethod("notifyBlur", "notifyBlur") .declareAcquiredMethod("notifyBlur", "notifyBlur")
.onEvent('blur', function (evt) { .onEvent('blur', function (evt) {
...@@ -647,4 +723,5 @@ ...@@ -647,4 +723,5 @@
}, true, false); }, true, false);
}(window, rJS, RSVP, URI, document, }(window, rJS, RSVP, URI, document,
SimpleQuery, ComplexQuery, Query, QueryFactory, XMLHttpRequest, console)); SimpleQuery, ComplexQuery, Query, QueryFactory, XMLHttpRequest, console,
\ No newline at end of file MouseEvent));
\ 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>testRelationFieldArrowKeys</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>${base_url}/foo_module/ListBoxZuite_reset</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Reset Successfully.</td>
<td></td>
</tr>
<!-- 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" />
<tr>
<td>assertTextPresent</td>
<td>Save</td>
<td></td>
</tr>
<tr>
<td>assertTextPresent</td>
<td>Quantity</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/go_to_foo_relation_field_view" />
<tr>
<td>waitForElementPresent</td>
<td>//input[@name='field_my_foo_category_title']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@name='field_my_foo_category_title']</td>
<td></td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() { selenium.browserbot.getCurrentWindow().document.getElementById("field_my_foo_category_title").value = "Qua%"; return true;})()
<td>true</td>
</tr>
<tr>
<td>fireEvent</td>
<td>//input[@name='field_my_foo_category_title']</td>
<td>input</td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//li[@data-relative-url='portal_categories/divergence_scope/quantity']</td>
<td></td>
</tr>
<!-- We have class "active" for every line that should be highlighted -->
<!-- Initially, no lines are highlighted -->
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[0].className.endsWith("active")})()
<td>false</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[1].className.endsWith("active")})()
<td>false</td>
</tr>
<!-- We do Arrow down key, then first line should be highlighted -->
<tr>
<td>assertEval</td>
<td>var e = new KeyboardEvent('keydown', {'key':'ArrowDown'});
selenium.browserbot.getDocument().querySelector("input[name='field_my_foo_category_title']").dispatchEvent(e)</td>
<td>true</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[0].className.endsWith("active")})()
<td>true</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[1].className.endsWith("active")})()
<td>false</td>
</tr>
<!-- We do Arrow down key again, then second line should be highlighted -->
<tr>
<td>assertEval</td>
<td>var e = new KeyboardEvent('keydown', {'key':'ArrowDown'});
selenium.browserbot.getDocument().querySelector("input[name='field_my_foo_category_title']").dispatchEvent(e)</td>
<td>true</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[0].className.endsWith("active")})()
<td>false</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[1].className.endsWith("active")})()
<td>true</td>
</tr>
<!-- We do Arrow up key, then first line should be highlighted -->
<tr>
<td>assertEval</td>
<td>var e = new KeyboardEvent('keydown', {'key':'ArrowUp'});
selenium.browserbot.getDocument().querySelector("input[name='field_my_foo_category_title']").dispatchEvent(e)</td>
<td>true</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[1].className.endsWith("active")})()
<td>false</td>
</tr>
<tr>
<td>assertEval</td>
<td>(function() {return selenium.browserbot.getCurrentWindow().document.querySelector("input[name='field_my_foo_category_title']").parentNode.querySelectorAll('li')[0].className.endsWith("active")})()
<td>true</td>
</tr>
<!-- Make sure Enter key allows to validate the selected line and disable the list of choice -->
<tr>
<td>assertEval</td>
<td>var e = new KeyboardEvent('keydown', {'key':'Enter'});
selenium.browserbot.getDocument().querySelector("input[name='field_my_foo_category_title']").dispatchEvent(e)</td>
<td>true</td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//li[@data-relative-url='portal_categories/divergence_scope/quantity']</td>
<td></td>
</tr>
<tr>
<td>assertValue</td>
<td>//input[@name='field_my_foo_category_title']</td>
<td>Quantity</td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment