[IMP] web: action links from bits & pieces

Before this, the action manager only supported auto-triggering actions
from (model, method) or (action_name).

This adds support for providing all the action details via data
attributes:

* model (defaults to current action's)
* resid (defaults to none)
* views (defaults to list, form, unless resid is specified then
  defaults to just form)
* domain (defaults to [])
* context (defaults to {active_id, active_ids, active_model} from
  current action if the model has not changed, empty otherwise)

The action's name/title is either the link's title (?) or its textual
content.
This commit is contained in:
Xavier Morel
2019-01-29 10:22:17 +00:00
parent 42fbee83ad
commit 9db74611de
2 changed files with 47 additions and 18 deletions
@@ -421,38 +421,54 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* When a user clicks on an <a> link with type="action", we need to actually
* do the action. This kind of links is used a lot in no-content helpers.
*
* The <a> may have
* - a data-method and data-model attribute, in that case the corresponding
* rpc will be called. If that rpc returns an action it will be executed.
* - a data-reload-on-close attribute, in that case the view will be
* reloaded after the dialog has been closed.
* * if the link has both data-model and data-method attributes, the
* corresponding method is called, chained to any action it would
* return. An optional data-reload-on-close (set to a non-falsy value)
* also causes th underlying view to be reloaded after the dialog is
* closed.
* * if the link has a name attribute, invoke the action with that
* identifier (see :class:`ActionManager.doAction` to not get the
* details)
* * otherwise an *action descriptor* is built from the link's data-
* attributes (model, res-id, views, domain and context)
*
* @private
* @param {OdooEvent} ev
* @param ev
*/
_onActionClicked: function (ev) {
_onActionClicked: function (ev) { // FIXME: maybe this should also work on <button> tags?
var $target = $(ev.currentTarget);
var self = this;
var model = $target.data('model');
var method = $target.data('method');
var data = $target.data();
if (method !== undefined && model !== undefined) {
if (data.method !== undefined && data.model !== undefined) {
var options = {};
if ($target.data('reload-on-close')) {
if (data.reloadOnClose) {
options.on_close = function () {
self.trigger_up('reload');
};
}
this.dp.add(this._rpc({
model: model,
method: method,
model: data.model,
method: data.method,
})).then(function (action) {
if (action !== undefined) {
self.do_action(action, options);
}
});
} else {
} else if ($target.attr('name')) {
this.do_action($target.attr('name'));
} else {
this.do_action({
name: $target.attr('title') || _.str.strip($target.text()),
type: 'ir.actions.act_window',
res_model: data.model || this.modelName,
res_id: data.resId,
target: 'current', // TODO: make customisable?
views: data.views || (data.resId ? [[false, 'form']] : [[false, 'list'], [false, 'form']]),
domain: data.domain || [],
}, {
additional_context: _.extend({}, data.context)
});
}
},
/**
@@ -43,7 +43,7 @@ odoo.define("base.abstract_controller_tests", function(require) {
QUnit.test(
'click on a a[type="action"] child triggers the correct action',
function(assert) {
assert.expect(3);
assert.expect(7);
var html =
"<div>" +
@@ -51,6 +51,9 @@ odoo.define("base.abstract_controller_tests", function(require) {
'<a name="a2" type="action" class="with-child">' +
"<span>child</input>" +
"</a>" +
'<a type="action" data-model="foo" data-method="bar" class="method">method</a>' +
'<a type="action" data-model="foo" data-res-id="42" class="descr">descr</a>' +
'<a type="action" data-model="foo" class="descr2">descr2</a>' +
"</div>";
var view = createView({
@@ -59,14 +62,24 @@ odoo.define("base.abstract_controller_tests", function(require) {
model: "test_model",
arch: "<test/>",
intercepts: {
do_action: function(event) {
assert.step(event.data.action);
do_action: function (event) {
assert.step(event.data.action.name || event.data.action);
}
},
mockRPC: function (route, args) {
if (args.model === 'foo' && args.method === 'bar') {
assert.step("method");
return $.when({name: 'method'});
}
return this._super.apply(this, arguments);
}
});
testUtils.dom.click(view.$(".simple"));
testUtils.dom.click(view.$(".with-child span"));
assert.verifySteps(["a1", "a2"]);
testUtils.dom.click(view.$(".method"));
testUtils.dom.click(view.$(".descr"));
testUtils.dom.click(view.$(".descr2"));
assert.verifySteps(["a1", "a2", "method", "method", "descr", "descr2"]);
}
);
}