[FIX] web: focus on close button when before closing a modal

During the clickEverywhere test, when a modal is opened, the hide method
is called to bypass it. This is not realistic and does not work in some
cases.

For example in Point of sale, menu "Reporting/Sales Details", a modal is
opened with a DateTimePicker (tempus dominus) already opened.
When hiding or closing the modal, the DateTimePicker needs to perform
some cleanup. If the modal is simply hidden, the DateTimePicker is not
cleanly destroyed.

With this commit, a modal is closed by clicking on its close button and
before that, the focus is set on the close button to let the
datepicker widget do its stuff on losing focus.

Also, a more realistic click is done by trigerring more events (code
adapted from tour helper).

closes odoo/odoo#32038

Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
This commit is contained in:
Christophe Monniez
2019-03-22 10:28:15 +00:00
parent 3a56e34169
commit 39e71353c5
+30 -8
View File
@@ -100,7 +100,7 @@
}).then(function(){ }).then(function(){
// no effect in community // no effect in community
var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th"); var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th");
$homeMenu.click(); _click($homeMenu);
return new Promise(function(resolve){ return new Promise(function(resolve){
setTimeout(function(){ setTimeout(function(){
resolve(); resolve();
@@ -123,13 +123,16 @@
console.log("Testing menu", element.innerText.trim(), " ", element.dataset.menuXmlid); console.log("Testing menu", element.innerText.trim(), " ", element.dataset.menuXmlid);
testedMenus.push(element.dataset.menuXmlid); testedMenus.push(element.dataset.menuXmlid);
var startActionCount = clientActionCount; var startActionCount = clientActionCount;
element.click(); _click($(element));
var isModal = false; var isModal = false;
return waitForCondition(function() { return waitForCondition(function() {
// sometimes, the app is just a modal that needs to be closed // sometimes, the app is just a modal that needs to be closed
var $modal = $('.modal[role="dialog"][open="open"]'); var $modal = $('.modal[role="dialog"][open="open"]');
if ($modal.length > 0) { if ($modal.length > 0) {
$modal.modal('hide'); var $closeButton = $('header > button.close');
if ($closeButton.length > 0) {
_click($closeButton);
} else { $modal.modal('hide'); }
isModal = true; isModal = true;
return true; return true;
} }
@@ -178,7 +181,7 @@
setTimeout(function() { setTimeout(function() {
var $element = $("nav.o_cp_switch_buttons > button[data-view-type=" + viewType + "]"); var $element = $("nav.o_cp_switch_buttons > button[data-view-type=" + viewType + "]");
console.log('Clicking on: ', $element[0].dataset.viewType, ' view switcher'); console.log('Clicking on: ', $element[0].dataset.viewType, ' view switcher');
$element.click(); _click($element);
},250); },250);
var waitViewSwitch = waitForCondition(function(){ var waitViewSwitch = waitForCondition(function(){
return $('.o_action_manager> .o_action.o_view_controller').data('view-type') === viewType; return $('.o_action_manager> .o_action.o_view_controller').data('view-type') === viewType;
@@ -198,7 +201,7 @@
var $filters = $('.o_filters_menu > .o_menu_item'); var $filters = $('.o_filters_menu > .o_menu_item');
console.log("Testing " + $filters.length + " filters"); console.log("Testing " + $filters.length + " filters");
var filter_ids = _.compact(_.map($filters, function(f) { return f.dataset.id})); var filter_ids = _.compact(_.map($filters, function(f) { return f.dataset.id}));
_.each(filter_ids, function(filter_id){ filter_ids.forEach(function(filter_id){
filterProm = filterProm.then(function(){ filterProm = filterProm.then(function(){
var currentViewCount = viewUpdateCount; var currentViewCount = viewUpdateCount;
var $filter = $('.o_menu_item[data-id="' + filter_id + '"] a'); var $filter = $('.o_menu_item[data-id="' + filter_id + '"] a');
@@ -208,16 +211,16 @@
return Promise.resolve(); return Promise.resolve();
} }
console.log('Clicking on filter "', $filter.text().trim(), '"'); console.log('Clicking on filter "', $filter.text().trim(), '"');
$filter[0].click(); _click($filter);
setTimeout(function() { setTimeout(function() {
var $filterOption = $('.o_menu_item .o_item_option[data-item_id="' + filter_id + '"]:not(.selected) a'); var $filterOption = $('.o_menu_item .o_item_option[data-item_id="' + filter_id + '"]:not(.selected) a');
// In case the filter is a date filter, we need to click on the first filter option (like 'today','This week' ...) // In case the filter is a date filter, we need to click on the first filter option (like 'today','This week' ...)
if ($filterOption.length > 0) { if ($filterOption.length > 0) {
console.log('Clicking on filter option "', $filterOption[0], '"'); console.log('Clicking on filter option "', $filterOption[0], '"');
$filterOption[0].click(); _click($filterOption);
console.log('And now on filter again'); console.log('And now on filter again');
$filter = $('.o_menu_item[data-id="' + filter_id + '"] a'); $filter = $('.o_menu_item[data-id="' + filter_id + '"] a');
$filter[0].click(); // To avoid that the next view fold the options _click($filter); // To avoid that the next view fold the options
} }
}, 250); }, 250);
return waitForCondition(function() { return waitForCondition(function() {
@@ -277,5 +280,24 @@
} }
/*
* More realistic click action.
* @param {jQueryElement} $element the element on which to perform the click
*/
function _click($element) {
triggerMouseEvent($element, "mouseover");
triggerMouseEvent($element, "mouseenter");
triggerMouseEvent($element, "mousedown");
triggerMouseEvent($element, "mouseup");
triggerMouseEvent($element, "focus");
triggerMouseEvent($element, "click");
function triggerMouseEvent($el, type, count) {
var e = document.createEvent("MouseEvents");
e.initMouseEvent(type, true, true, window, count || 0, 0, 0, 0, 0, false, false, false, false, 0, $el[0]);
$el[0].dispatchEvent(e);
}
}
exports.clickEverywhere = clickEverywhere; exports.clickEverywhere = clickEverywhere;
})(window); })(window);