From fc8a4b5edec1c0cc4f7efa9a8d9fd9a7ed861d12 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 15 Jan 2016 16:31:32 +0100 Subject: [PATCH] [FIX] web: view manager: overlapping switches between views The problem occured when the user quickly clicked several times on the view switcher or the breadcrumbs. The function switch_mode() of the view manager was called once per click. This function's role is to prepare the requested view, and once it is ready, to remove the former one from the DOM and insert the new one instead. It is thus asynchronous as it waits for the fields_view_get and search_read RPCs' response. Unfortunately, when those calls to switch_mode() overlapped, the former view reference was lost and it was thus never removed, producing a weird situation where two views were displayed one above the other. This may happen when a view takes a while to load, or simply when the user double-clicks on the breadcrumbs or view switcher. This rev. makes sure that calls to switch_mode() can never overlap by refusing any other call when there is still one processing. We also added a protection against breadcrumbs and view switcher double-clicks. opw 658924 --- addons/web/static/src/js/action_manager.js | 4 ++-- addons/web/static/src/js/view_manager.js | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/js/action_manager.js b/addons/web/static/src/js/action_manager.js index 9f435bf2c6b..2337583b7f9 100644 --- a/addons/web/static/src/js/action_manager.js +++ b/addons/web/static/src/js/action_manager.js @@ -228,9 +228,9 @@ var ActionManager = Widget.extend({ this.main_control_panel = new ControlPanel(this); // Listen to event "on_breadcrumb_click" trigerred on the control panel when // clicking on a part of the breadcrumbs. Call select_action for this breadcrumb. - this.main_control_panel.on("on_breadcrumb_click", this, function(action, index) { + this.main_control_panel.on("on_breadcrumb_click", this, _.debounce(function(action, index) { this.select_action(action, index); - }); + }, 200, true)); // Append the main control panel to the DOM (inside the ActionManager jQuery element) this.main_control_panel.appendTo(this.$el); diff --git a/addons/web/static/src/js/view_manager.js b/addons/web/static/src/js/view_manager.js index e720db2475b..2ae53aabb22 100644 --- a/addons/web/static/src/js/view_manager.js +++ b/addons/web/static/src/js/view_manager.js @@ -130,8 +130,10 @@ var ViewManager = Widget.extend(ControlPanelMixin, { var view = this.views[view_type]; var old_view = this.active_view; - if (!view) { + if (!view || this.currently_switching) { return $.Deferred().reject(); + } else { + this.currently_switching = true; // prevent overlapping switches } if (view.multi_record) { @@ -169,6 +171,9 @@ var ViewManager = Widget.extend(ControlPanelMixin, { self.active_view = old_view; self.view_stack.pop(); }); + switched.always(function () { + self.currently_switching = false; + }); return switched; }, _display_view: function (view_options, old_view) { @@ -248,7 +253,6 @@ var ViewManager = Widget.extend(ControlPanelMixin, { }, select_view: function (index) { var view_type = this.view_stack[index].type; - this.view_stack.splice(index); return this.switch_mode(view_type); }, /** @@ -271,10 +275,10 @@ var ViewManager = Widget.extend(ControlPanelMixin, { }); // Add onclick event listener - this.control_elements.$switch_buttons.siblings('button').click(function(event) { + this.control_elements.$switch_buttons.siblings('button').click(_.debounce(function(event) { var view_type = $(event.target).data('view-type'); self.switch_mode(view_type); - }); + }, 200, true)); } }, /**