diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index d049abaa8ec..5c0ee9260e0 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -450,9 +450,6 @@ var ActionManager = Widget.extend({ action.controllerID = controllerID; var prom = this._executeAction(action, options); prom.then(function () { - // AAB: this should be done automatically in AbstractAction, so that - // it can be overridden by actions that have specific stuff to push - // (e.g. Discuss, Views) self._pushState(controllerID, {}); }); return prom; @@ -625,6 +622,7 @@ var ActionManager = Widget.extend({ state.active_ids = action.context.active_ids.join(','); } } + state = _.extend({}, controller.widget.getState(), state); return state; }, /** diff --git a/addons/web/static/src/js/chrome/action_manager_act_window.js b/addons/web/static/src/js/chrome/action_manager_act_window.js index 5f3368038f2..90f1a00091a 100644 --- a/addons/web/static/src/js/chrome/action_manager_act_window.js +++ b/addons/web/static/src/js/chrome/action_manager_act_window.js @@ -119,7 +119,6 @@ ActionManager.include({ return this.doAction(action, options); } return _super.apply(this, arguments); - }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/js/chrome/action_mixin.js b/addons/web/static/src/js/chrome/action_mixin.js index b4a02879154..1831f3998f8 100644 --- a/addons/web/static/src/js/chrome/action_mixin.js +++ b/addons/web/static/src/js/chrome/action_mixin.js @@ -141,6 +141,19 @@ var ActionMixin = { getTitle: function () { return this._title; }, + /** + * Returns a serializable state that will be pushed in the URL by + * the action manager, allowing the action to be restarted correctly + * upon refresh. This function should be overriden to add extra information. + * Note that some keys are reserved by the framework and will thus be + * ignored ('action', 'active_id', 'active_ids' and 'title', for all + * actions, and 'model' and 'view_type' for act_window actions). + * + * @returns {Object} + */ + getState: function () { + return {}; + }, /** * Gives the focus to the action */ diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js index 70cec99aa86..152d8c08071 100644 --- a/addons/web/static/src/js/views/abstract_controller.js +++ b/addons/web/static/src/js/views/abstract_controller.js @@ -331,13 +331,11 @@ var AbstractController = mvc.Controller.extend(ActionMixin, { * example with a new id. * * @private - * @param {Object} [state] information that will be pushed to the outside - * world */ - _pushState: function (state) { + _pushState: function () { this.trigger_up('push_state', { controllerID: this.controllerID, - state: state || {}, + state: this.getState(), }); }, /** diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 2a39742b206..ede9667bf0c 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -125,6 +125,17 @@ var FormController = BasicController.extend({ getTitle: function () { return this.model.getName(this.handle); }, + /** + * Add the current ID to the state pushed in the url. + * + * @override + */ + getState: function () { + const state = this._super.apply(this, arguments); + const env = this.model.get(this.handle, {env: true}); + state.id = env.currentId; + return state; + }, /** * Render buttons for the control panel. The form view can be rendered in * a dialog, and in that case, if we have buttons defined in the footer, we @@ -421,20 +432,6 @@ var FormController = BasicController.extend({ this._super.apply(this, arguments); } }, - /** - * We just add the current ID to the state pushed. This allows the web - * client to add it in the url, for example. - * - * @override method from AbstractController - * @private - * @param {Object} [state] - */ - _pushState: function (state) { - state = state || {}; - var env = this.model.get(this.handle, {env: true}); - state.id = env.currentId; - this._super(state); - }, /** * Overrides to reload the form when saving failed in readonly (e.g. after * a change on a widget like priority or statusbar). diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 226c8fb2b15..42abad111c5 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -1847,12 +1847,22 @@ QUnit.module('ActionManager', { }); QUnit.test('state is pushed for client actions', async function (assert) { - assert.expect(2); + assert.expect(3); - var ClientAction = AbstractAction.extend({}); - var actionManager = await createActionManager({ + const ClientAction = AbstractAction.extend({ + getTitle: function () { + return 'a title'; + }, + getState: function () { + return {foo: 'baz'}; + } + }); + const actionManager = await createActionManager({ intercepts: { - push_state: function () { + push_state: function (ev) { + const expectedState = {action: 'HelloWorldTest', foo: 'baz', title: 'a title'}; + assert.deepEqual(ev.data.state, expectedState, + "should include a complete state description, including custom state"); assert.step('push state'); }, },