summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/action_manager.js
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2016-04-08 14:53:34 +0200
committerGéry Debongnie <ged@odoo.com>2016-04-21 15:21:39 +0200
commit977db823c7c84e9edc7c8cf8384eb9cf47275b3a (patch)
treec3312f745baf11d51f976a60d6e285480f557d4c /addons/web/static/src/js/action_manager.js
parente1bfd3fbda97ac7a64a585b07be161d5be606cf9 (diff)
[REF] web: stop duplicating web
Avoid duplicating web addon in enterprise by extracting a common basis. Enterprise features stay in enterprise, but use that common basis. Mainly: - JS refactoring and linting - Conversion of .sass into .less split into multiple files - Templates cleaning and DOM simplification - Re-generation of web.pot, and update of .po files
Diffstat (limited to 'addons/web/static/src/js/action_manager.js')
-rw-r--r--addons/web/static/src/js/action_manager.js212
1 files changed, 112 insertions, 100 deletions
diff --git a/addons/web/static/src/js/action_manager.js b/addons/web/static/src/js/action_manager.js
index 359b174a28d..be5e6c6c996 100644
--- a/addons/web/static/src/js/action_manager.js
+++ b/addons/web/static/src/js/action_manager.js
@@ -23,24 +23,17 @@ var Action = core.Class.extend({
this.title = action.display_name || action.name;
},
/**
- * Not implemented for client actions
- * @return {Deferred} a rejected Deferred
- */
- appendTo: function() {
- return $.Deferred().reject();
- },
- /**
* This method should restore this previously loaded action
- * Calls on_reverse_breadcrumb callback if defined
+ * Calls on_reverse_breadcrumb_callback if defined
* @return {Deferred} resolved when widget is enabled
*/
restore: function() {
- if (this.on_reverse_breadcrumb) {
- return this.on_reverse_breadcrumb();
+ if (this.on_reverse_breadcrumb_callback) {
+ return this.on_reverse_breadcrumb_callback();
}
},
/**
- * Not implemented for functions
+ * There is nothing to detach in the case of a client function
*/
detach: function() {
},
@@ -50,11 +43,16 @@ var Action = core.Class.extend({
destroy: function() {
},
/**
- * Sets the on_reverse_breadcrumb callback to be called when coming back to that action
- * @param {Function} [on_reverse_breadcrumb] the callback
+ * Sets the on_reverse_breadcrumb_callback to be called when coming back to that action
+ * @param {Function} [callback] the callback
+ */
+ set_on_reverse_breadcrumb: function(callback) {
+ this.on_reverse_breadcrumb_callback = callback;
+ },
+ /**
+ * Not implemented for client actions
*/
- set_on_reverse_breadcrumb: function(on_reverse_breadcrumb) {
- this.on_reverse_breadcrumb = on_reverse_breadcrumb;
+ set_scrollTop: function() {
},
/**
* Stores the DOM fragment of the action
@@ -65,8 +63,10 @@ var Action = core.Class.extend({
},
/**
* Not implemented for client actions
+ * @return {int} the number of pixels the webclient is scrolled when leaving the action
*/
- set_is_in_DOM: function() {
+ get_scrollTop: function() {
+ return 0;
},
/**
* @return {Object} the description of the action
@@ -113,16 +113,6 @@ var WidgetAction = Action.extend({
});
},
/**
- * Wraps the action's widget in a container and appends it to el
- * @param {DocumentFragment} [el] where to append the widget
- * @return {Deferred} resolved when the widget is appended
- */
- appendTo: function(el) {
- this.$client_action_container = $('<div>').addClass('oe_client_action');
- this.$client_action_container.appendTo(el);
- return this.widget.appendTo(this.$client_action_container);
- },
- /**
* Restores WidgetAction by calling do_show on its widget
*/
restore: function() {
@@ -132,18 +122,20 @@ var WidgetAction = Action.extend({
});
},
/**
- * Detaches the client action's container from the DOM
- * @return {jQuery} the action's container
+ * Detaches the action's widget from the DOM
+ * @return the widget's $el
*/
detach: function() {
- return this.$client_action_container.detach();
+ // Hack to remove badly inserted nvd3 tooltips ; should be removed when upgrading nvd3 lib
+ $('body > .nvtooltip').remove();
+
+ return framework.detach([{widget: this.widget}]);
},
/**
* Destroys the widget
*/
destroy: function() {
this.widget.destroy();
- this.detach();
},
});
/**
@@ -151,14 +143,6 @@ var WidgetAction = Action.extend({
*/
var ViewManagerAction = WidgetAction.extend({
/**
- * Appends the action's widget to el
- * @param {DocumentFragment} [el] where to append the widget
- * @return {Deferred} resolved when the widget is appended
- */
- appendTo: function(el) {
- return this.widget.appendTo(el);
- },
- /**
* Restores a ViewManagerAction
* Switches to the requested view by calling select_view on the ViewManager
* @param {int} [view_index] the index of the view to select
@@ -170,27 +154,27 @@ var ViewManagerAction = WidgetAction.extend({
});
},
/**
- * Sets is_in_DOM on this.widget
- * @param {Boolean} [is_in_DOM] true iff the widget is attached in the DOM
+ * Sets the on_reverse_breadcrumb_callback and the scrollTop to apply when
+ * coming back to that action
+ * @param {Function} [callback] the callback
+ * @param {int} [scrollTop] the number of pixels to scroll
*/
- set_is_in_DOM: function(is_in_DOM) {
- this.widget.is_in_DOM = is_in_DOM;
+ set_on_reverse_breadcrumb: function(callback, scrollTop) {
+ this._super(callback);
+ this.set_scrollTop(scrollTop);
},
/**
- * Detaches the view_manager from the DOM
- * @return {jQuery} the view_manager's $el
+ * Sets the scroll position of the widgets's active_view
+ * @param {int} [scrollTop] the number of pixels to scroll
*/
- detach: function() {
- // Hack to remove badly inserted nvd3 tooltips ; should be removed when upgrading nvd3 lib
- $('body > .nvtooltip').remove();
-
- return this.widget.$el.detach();
+ set_scrollTop: function(scrollTop) {
+ this.widget.active_view.controller.set_scrollTop(scrollTop);
},
/**
- * Destroys the widget
+ * @return {int} the number of pixels the webclient is scrolled when leaving the action
*/
- destroy: function() {
- this.widget.destroy();
+ get_scrollTop: function() {
+ return this.widget.active_view.controller.get_scrollTop();
},
/**
* @return {Array} array of Objects that will be interpreted to display the breadcrumbs
@@ -214,13 +198,31 @@ var ViewManagerAction = WidgetAction.extend({
});
var ActionManager = Widget.extend({
- template: "ActionManager",
- init: function(parent) {
+ template: 'ActionManager',
+ /**
+ * Called each time the action manager is attached into the DOM
+ */
+ on_attach_callback: function() {
+ this.is_in_DOM = true;
+ if (this.inner_widget && this.inner_widget.on_attach_callback) {
+ this.inner_widget.on_attach_callback();
+ }
+ },
+ /**
+ * Called each time the action manager is detached from the DOM
+ */
+ on_detach_callback: function() {
+ this.is_in_DOM = false;
+ if (this.inner_widget && this.inner_widget.on_detach_callback) {
+ this.inner_widget.on_detach_callback();
+ }
+ },
+ init: function(parent, options) {
this._super(parent);
this.action_stack = [];
this.inner_action = null;
this.inner_widget = null;
- this.webclient = parent;
+ this.webclient = options && options.webclient;
this.dialog = null;
this.dialog_widget = null;
this.on('history_back', this, this.proxy('history_back'));
@@ -236,8 +238,15 @@ var ActionManager = Widget.extend({
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);
+ // Listen to event "DOM_updated" to restore the scroll position
+ core.bus.on('DOM_updated', this, function() {
+ if (this.inner_action) {
+ this.trigger_up('scrollTo', {offset: this.inner_action.get_scrollTop() || 0});
+ }
+ });
+
+ // Insert the main control panel into the DOM
+ return this.main_control_panel.insertBefore(this.$el);
},
dialog_stop: function (reason) {
if (this.dialog) {
@@ -256,9 +265,9 @@ var ActionManager = Widget.extend({
*/
push_action: function(widget, action_descr, options) {
var self = this;
- var old_widget = this.inner_widget;
- var old_action = this.inner_action;
var old_action_stack = this.action_stack;
+ var old_action = this.inner_action;
+ var old_widget = this.inner_widget;
options = options || {};
// Empty action_stack if requested
@@ -277,8 +286,8 @@ var ActionManager = Widget.extend({
}
// Set on_reverse_breadcrumb callback on previous inner_action
- if (old_action) {
- old_action.set_on_reverse_breadcrumb(options.on_reverse_breadcrumb);
+ if (this.webclient && old_action) {
+ old_action.set_on_reverse_breadcrumb(options.on_reverse_breadcrumb, this.webclient.get_scrollTop());
}
// Update action_stack (must be done before appendTo to properly
@@ -295,25 +304,19 @@ var ActionManager = Widget.extend({
// render the inner_widget in a fragment, and append it to the
// document only when it's ready
var new_widget_fragment = document.createDocumentFragment();
- return $.when(this.inner_action.appendTo(new_widget_fragment)).done(function() {
+ return $.when(this.inner_widget.appendTo(new_widget_fragment)).done(function() {
// Detach the fragment of the previous action and store it within the action
if (old_action) {
old_action.set_fragment(old_action.detach());
- old_action.set_is_in_DOM(false);
}
if (!widget.need_control_panel) {
// Hide the main ControlPanel for widgets that do not use it
self.main_control_panel.do_hide();
}
-
- framework.append(self.$el, new_widget_fragment, true);
- self.inner_action.set_is_in_DOM(true);
-
- // Hide the old_widget as it will be removed from the DOM when it
- // is destroyed
- if (old_widget) {
- old_widget.do_hide();
- }
+ framework.append(self.$el, new_widget_fragment, {
+ in_DOM: self.is_in_DOM,
+ callbacks: [{widget: self.inner_widget}],
+ });
if (options.clear_breadcrumbs) {
self.clear_action_stack(old_action_stack);
}
@@ -325,6 +328,11 @@ var ActionManager = Widget.extend({
self.inner_widget = old_widget;
});
},
+ set_scrollTop: function(scrollTop) {
+ if (this.inner_action) {
+ this.inner_action.set_scrollTop(scrollTop);
+ }
+ },
get_breadcrumbs: function () {
return _.flatten(_.map(this.action_stack, function (action) {
return action.get_breadcrumbs();
@@ -368,7 +376,9 @@ var ActionManager = Widget.extend({
},
select_action: function(action, index) {
var self = this;
- return this.webclient.clear_uncommitted_changes().then(function() {
+ var def = this.webclient && this.webclient.clear_uncommitted_changes() || $.when();
+
+ return def.then(function() {
// Set the new inner_action/widget and update the action stack
var old_action = self.inner_action;
var action_index = self.action_stack.indexOf(action);
@@ -376,19 +386,21 @@ var ActionManager = Widget.extend({
self.inner_action = action;
self.inner_widget = action.widget;
- // Hide the ControlPanel if the widget doesn't use it
- if (!self.inner_widget.need_control_panel) {
- self.main_control_panel.do_hide();
- }
-
return $.when(action.restore(index)).done(function() {
+ // Hide the ControlPanel if the widget doesn't use it
+ if (!self.inner_widget.need_control_panel) {
+ self.main_control_panel.do_hide();
+ }
+ // Attach the DOM of the action and restore the scroll position only if necessary
if (action !== old_action) {
// Clear the action stack (this also removes the current action from the DOM)
self.clear_action_stack(to_destroy);
// Append the fragment of the action to restore to self.$el
- framework.append(self.$el, action.get_fragment(), true);
- self.inner_action.set_is_in_DOM(true);
+ framework.append(self.$el, action.get_fragment(), {
+ in_DOM: self.is_in_DOM,
+ callbacks: [{widget: action.widget}],
+ });
}
});
}).fail(function() {
@@ -406,7 +418,7 @@ var ActionManager = Widget.extend({
}
},
do_push_state: function(state) {
- if (!this.webclient || !this.webclient.do_push_state || this.dialog) {
+ if (!this.webclient || this.dialog) {
return;
}
state = state || {};
@@ -491,13 +503,6 @@ var ActionManager = Widget.extend({
res_id: state.id,
view_type: state.view_type,
});
- $.when(action_loaded || null).done(function() {
- self.webclient.menu.is_bound.done(function() {
- if (self.inner_action && self.inner_action.get_action_descr().id) {
- self.webclient.menu.open_action(self.inner_action.get_action_descr().id);
- }
- });
- });
}
}
} else if (state.model && state.id) {
@@ -524,9 +529,9 @@ var ActionManager = Widget.extend({
});
}
- $.when(action_loaded || null).done(function() {
+ return $.when(action_loaded || null).done(function() {
if (self.inner_widget && self.inner_widget.do_load_state) {
- self.inner_widget.do_load_state(state, warm);
+ return self.inner_widget.do_load_state(state, warm);
}
});
},
@@ -628,7 +633,9 @@ var ActionManager = Widget.extend({
});
}
- return this[type](action, options);
+ return $.when(this[type](action, options)).then(function() {
+ return action;
+ });
},
null_action: function() {
this.dialog_stop();
@@ -645,6 +652,7 @@ var ActionManager = Widget.extend({
* @return {*}
*/
ir_actions_common: function(executor, options) {
+ var self = this;
if (executor.action.target === 'new') {
var pre_dialog = (this.dialog && !this.dialog.isDestroyed()) ? this.dialog : null;
if (pre_dialog){
@@ -693,13 +701,16 @@ var ActionManager = Widget.extend({
this.dialog_widget.set_cp_bus(new core.Bus());
}
this.dialog_widget.setParent(this.dialog);
- this.dialog.open();
-
- return this.dialog_widget.appendTo(this.dialog.$el);
+
+ var fragment = document.createDocumentFragment();
+ return this.dialog_widget.appendTo(fragment).then(function() {
+ self.dialog.open().$el.append(fragment);
+ if(options.state && self.dialog_widget.do_load_state) {
+ return self.dialog_widget.do_load_state(options.state);
+ }
+ }).then(function () { return executor.action; });
}
- // Clear uncommitted changes on the current inner widget if there is one
- var self = this;
- var def = (this.inner_widget && this.webclient.clear_uncommitted_changes()) || $.when();
+ var def = this.inner_action && this.webclient && this.webclient.clear_uncommitted_changes() || $.when();
return def.then(function() {
self.dialog_stop(executor.action);
return self.push_action(executor.widget(), executor.action, options);
@@ -764,11 +775,11 @@ var ActionManager = Widget.extend({
},
ir_actions_server: function (action, options) {
var self = this;
- this.rpc('/web/action/run', {
+ return this.rpc('/web/action/run', {
action_id: action.id,
context: action.context || {}
- }).done(function (action) {
- self.do_action(action, options);
+ }).then(function (action) {
+ return self.do_action(action, options);
});
},
ir_actions_report_xml: function(action, options) {
@@ -818,6 +829,7 @@ var ActionManager = Widget.extend({
if (action.target === 'self') {
framework.redirect(url);
+ return $.Deferred(); // The action is finished only when the redirection is done
} else {
window.open(url, '_blank');
}