summaryrefslogtreecommitdiff
path: root/addons/web
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2017-03-20 15:23:19 +0100
committerAaron Bohy <aab@odoo.com>2017-04-11 19:44:38 +0200
commit2106e3dd2ecd61096d7c7531c2f18b00fb30aeea (patch)
tree1e41a2e698ba993d9d74b6fddd699adb15642001 /addons/web
parent749d10e8b55dce94828290d7e4d6b2b6f741e9bd (diff)
[REF] web, *: simplify our RPC system (in JS)
The RPC system was not completely satisfactory, we decided to prepare the future and do it properly. This commit introduces the new rpc system, which replace the previous new one. We now simply have a method, this._rpc, which takes a dictionary of parameters. The idea is that depending on the parameters, it is able to add correct default value when necessary. For situations where we don't have the this._rpc method, we can use the rpc.query method, which takes the same arguments, but directly calls ajax.rpc instead of triggering up some events.
Diffstat (limited to 'addons/web')
-rw-r--r--addons/web/static/src/js/apps.js7
-rw-r--r--addons/web/static/src/js/chrome/action_manager.js18
-rw-r--r--addons/web/static/src/js/chrome/search_inputs.js26
-rw-r--r--addons/web/static/src/js/chrome/sidebar.js13
-rw-r--r--addons/web/static/src/js/chrome/user_menu.js12
-rw-r--r--addons/web/static/src/js/chrome/web_client.js23
-rw-r--r--addons/web/static/src/js/core/mixins.js10
-rw-r--r--addons/web/static/src/js/core/rpc.js332
-rw-r--r--addons/web/static/src/js/core/session.js7
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js61
-rw-r--r--addons/web/static/src/js/fields/upgrade_fields.js9
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js253
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_controller.js16
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_model.js48
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_quick_create.js10
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_renderer.js16
-rw-r--r--addons/web/static/src/js/views/graph/graph_model.js16
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_controller.js10
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js17
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_model.js32
-rw-r--r--addons/web/static/src/js/widgets/change_password.js9
-rw-r--r--addons/web/static/src/js/widgets/data_export.js43
-rw-r--r--addons/web/static/src/js/widgets/debug_manager.js54
-rw-r--r--addons/web/static/src/js/widgets/model_field_selector.js13
-rw-r--r--addons/web/static/src/js/widgets/switch_company_menu.js8
-rw-r--r--addons/web/static/test/core/rpc_tests.js301
-rw-r--r--addons/web/static/test/fields/relational_fields_tests.js6
-rw-r--r--addons/web/static/test/helpers/mock_server.js35
-rw-r--r--addons/web/static/test/helpers/test_utils.js2
29 files changed, 656 insertions, 751 deletions
diff --git a/addons/web/static/src/js/apps.js b/addons/web/static/src/js/apps.js
index 8e9818f67d6..fcf21852d2c 100644
--- a/addons/web/static/src/js/apps.js
+++ b/addons/web/static/src/js/apps.js
@@ -40,8 +40,7 @@ var Apps = Widget.extend({
if (apps_client) {
return check_client_available(apps_client);
} else {
- return this._rpc('ir.module.module', 'get_apps_server')
- .exec()
+ return this._rpc({model: 'ir.module.module', method: 'get_apps_server'})
.then(function(u) {
var link = $(_.str.sprintf('<a href="%s"></a>', u))[0];
var host = _.str.sprintf('%s//%s', link.protocol, link.host);
@@ -90,9 +89,7 @@ var Apps = Widget.extend({
});
},
'Model': function(m) {
- return this._rpc(m.model, m.method)
- .args(m.args)
- .exec()
+ return this._rpc({model: m.model, method: m.method, args: m.args})
.then(function(r) {
var w = self.$ifr[0].contentWindow;
w.postMessage({id: m.id, result: r}, client.origin);
diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js
index fdfc33f74f5..9221561f2d9 100644
--- a/addons/web/static/src/js/chrome/action_manager.js
+++ b/addons/web/static/src/js/chrome/action_manager.js
@@ -559,9 +559,10 @@ var ActionManager = Widget.extend({
if (warm) {
this.null_action();
}
- action_loaded = this._rpc('/web/session/get_session_action')
- .params({key: state.sa})
- .exec()
+ action_loaded = this._rpc({
+ route: '/web/session/get_session_action',
+ params: {key: state.sa},
+ })
.then(function(action) {
if (action) {
return self.do_action(action);
@@ -835,12 +836,13 @@ var ActionManager = Widget.extend({
},
ir_actions_server: function (action, options) {
var self = this;
- return this._rpc('/web/action/run')
- .params({
- action_id: action.id,
- context: action.context || {}
+ return this._rpc({
+ route: '/web/action/run',
+ params: {
+ action_id: action.id,
+ context: action.context || {}
+ },
})
- .exec()
.then(function (action) {
return self.do_action(action, options);
});
diff --git a/addons/web/static/src/js/chrome/search_inputs.js b/addons/web/static/src/js/chrome/search_inputs.js
index aa02f9fe950..2a265ff0fdd 100644
--- a/addons/web/static/src/js/chrome/search_inputs.js
+++ b/addons/web/static/src/js/chrome/search_inputs.js
@@ -427,14 +427,16 @@ var ManyToOneField = CharField.extend({
args = [];
}
}
- return this._rpc(this.attrs.relation, 'name_search')
- .kwargs({
- name: needle,
- args: args,
- limit: 8,
- context: context
+ return this._rpc({
+ model: this.attrs.relation,
+ method: 'name_search',
+ kwargs: {
+ name: needle,
+ args: args,
+ limit: 8,
+ context: context
+ },
})
- .exec()
.then(function (results) {
if (_.isEmpty(results)) { return null; }
return _(results).map(function (result) {
@@ -459,10 +461,12 @@ var ManyToOneField = CharField.extend({
}
var context = pyeval.eval('contexts', [this.searchview.dataset.get_context()]);
- return this._rpc(this.attrs.relation, 'name_get')
- .args([value])
- .withContext(context)
- .exec()
+ return this._rpc({
+ model: this.attrs.relation,
+ method: 'name_get',
+ args: [value],
+ context: context,
+ })
.then(function (names) {
if (_(names).isEmpty()) { return null; }
return facet_from(self, names[0]);
diff --git a/addons/web/static/src/js/chrome/sidebar.js b/addons/web/static/src/js/chrome/sidebar.js
index 41e45b6e148..3cd17334e9e 100644
--- a/addons/web/static/src/js/chrome/sidebar.js
+++ b/addons/web/static/src/js/chrome/sidebar.js
@@ -148,13 +148,14 @@ var Sidebar = Widget.extend({
new Context(
sidebar_eval_context, active_ids_context));
- self._rpc("/web/action/load")
- .params({
- action_id: item.action.id,
- context: new Context(
- dataset.get_context(), active_ids_context).eval()
+ self._rpc({
+ route: '/web/action/load',
+ params: {
+ action_id: item.action.id,
+ context: new Context(
+ dataset.get_context(), active_ids_context).eval()
+ },
})
- .exec()
.done(function(result) {
result.context = new Context(
result.context || {}, active_ids_context)
diff --git a/addons/web/static/src/js/chrome/user_menu.js b/addons/web/static/src/js/chrome/user_menu.js
index 21ecac479b1..5e1691c6640 100644
--- a/addons/web/static/src/js/chrome/user_menu.js
+++ b/addons/web/static/src/js/chrome/user_menu.js
@@ -59,8 +59,7 @@ var UserMenu = Widget.extend({
var self = this;
this.trigger_up('clear_uncommitted_changes', {
callback: function () {
- self._rpc('/web/session/account')
- .exec()
+ self._rpc({route: '/web/session/account'})
.then(function (url) {
framework.redirect(url);
})
@@ -93,11 +92,12 @@ var UserMenu = Widget.extend({
var session = this.getSession();
this.trigger_up('clear_uncommitted_changes', {
callback: function () {
- self._rpc("/web/action/load")
- .params({
- action_id: "base.action_res_users_my",
+ self._rpc({
+ route: "/web/action/load",
+ params: {
+ action_id: "base.action_res_users_my",
+ },
})
- .exec()
.done(function (result) {
result.res_id = session.uid;
self.do_action(result);
diff --git a/addons/web/static/src/js/chrome/web_client.js b/addons/web/static/src/js/chrome/web_client.js
index 48666e2bd16..800277cfae8 100644
--- a/addons/web/static/src/js/chrome/web_client.js
+++ b/addons/web/static/src/js/chrome/web_client.js
@@ -65,13 +65,16 @@ return AbstractWebClient.extend({
logo_edit: function(ev) {
var self = this;
ev.preventDefault();
- this._rpc("res.users", "read")
- .args([[session.uid], ["company_id"]])
- .exec()
+ this._rpc({
+ model: 'res.users',
+ method: 'read',
+ args: [[session.uid], ['company_id']],
+ })
.then(function(data) {
- self._rpc("/web/action/load")
- .params({ action_id: "base.action_res_company_form" })
- .exec()
+ self._rpc({
+ route: '/web/action/load',
+ params: { action_id: 'base.action_res_company_form' },
+ })
.done(function(result) {
result.res_id = data[0].company_id[0];
result.target = "new";
@@ -99,9 +102,11 @@ return AbstractWebClient.extend({
var state = $.bbq.getState(true);
if (_.isEmpty(state) || state.action === "login") {
self.menu.is_bound.done(function() {
- self._rpc("res.users", "read")
- .args([[session.uid], ["action_id"]])
- .exec()
+ self._rpc({
+ model: 'res.users',
+ method: 'read',
+ args: [[session.uid], ['action_id']],
+ })
.done(function(result) {
var data = result[0];
if(data.action_id) {
diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js
index 71ce5e28f7f..8a5038557c2 100644
--- a/addons/web/static/src/js/core/mixins.js
+++ b/addons/web/static/src/js/core/mixins.js
@@ -453,13 +453,9 @@ var ServicesMixin = {
* @param {string} method if a model is given, this argument is a method
* @returns {RPCBuilder}
*/
- _rpc: function (arg1, method) {
- return rpc.query({
- method: method,
- model: method && arg1,
- parent: this,
- route: !method && arg1,
- });
+ _rpc: function (params, options) {
+ var query = rpc.buildQuery(params);
+ return this.call('ajax', 'rpc', query.route, query.params, options);
},
loadFieldView: function (dataset, view_id, view_type, options) {
return this.loadViews(dataset.model, dataset.get_context(), [[view_id, view_type]], options).then(function (result) {
diff --git a/addons/web/static/src/js/core/rpc.js b/addons/web/static/src/js/core/rpc.js
index bb1b6740048..573041301e8 100644
--- a/addons/web/static/src/js/core/rpc.js
+++ b/addons/web/static/src/js/core/rpc.js
@@ -2,199 +2,88 @@ odoo.define('web.rpc', function (require) {
"use strict";
var ajax = require('web.ajax');
-var Class = require('web.Class');
-var BaseRPCBuilder = Class.extend({
+return {
/**
- * @param {Widget} parent the rpc will go through this widget
- * @param {Object} params
- * @param {string} [params.model]
- * @param {string} [params.method]
- * @param {string} [params.route]
- */
- init: function (parent, params) {
- this.parent = parent;
- this._route = params.route;
- if (!this._route) {
- this._route = '/web/dataset/call_kw/' + params.model + '/' + params.method;
+ * Perform a RPC. Please note that this is not the preferred way to do a
+ * rpc if you are in the context of a widget. In that case, you should use
+ * the this._rpc method.
+ *
+ * @param {Object} params @see buildQuery for a description
+ * @param {Object} options
+ * @returns {Deferred<any>}
+ */
+ query: function (params, options) {
+ var query = this.buildQuery(params);
+ return ajax.rpc(query.route, query.params, options);
+ },
+ /**
+ * @param {Object} options
+ * @param {any[]} [options.args]
+ * @param {Object} [options.context]
+ * @param {any[]} [options.domain]
+ * @param {string[]} [options.fields]
+ * @param {string[]} [options.groupBy]
+ * @param {Object} [options.kwargs]
+ * @param {integer|false} [options.limit]
+ * @param {string} [options.method]
+ * @param {string} [options.model]
+ * @param {integer} [options.offset]
+ * @param {string[]} [options.orderBy]
+ * @param {Object} [options.params]
+ * @param {string} [options.route]
+ * @returns {Object} with 2 keys: route and params
+ */
+ buildQuery: function (options) {
+ var route;
+ var params = options.params || {};
+ if (options.route) {
+ route = options.route;
+ } else if (options.model && options.method) {
+ route = '/web/dataset/call_kw/' + options.model + '/' + options.method;
}
- this._model = params.model;
- this._method = params.method;
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * @param {Array} args
- * @returns {BaseRPCBuilder}
- */
- args: function (args) {
- if (!(args instanceof Array)) {
- throw new Error("Arguments should be an array");
+ if (options.method) {
+ params.args = options.args || [];
+ params.model = options.model;
+ params.method = options.method;
+ params.kwargs = options.kwargs || {};
+ params.kwargs.context = options.context || params.kwargs.context;
}
- this._args = args;
- return this;
- },
- /**
- * @param {Object} [params]
- * @param {string} [params.type=event] if type=event, the rpc will be done
- * by triggering an event. It will work if the parent is in a component
- * tree with a component with a ServiceProvider somewhere up. If
- * type=ajax, then it will instead perform directly an ajax call. This is
- * discouraged, if possible.
- * @param {Object} [params.options] options that will be sent to the low
- * level ajax call. Typically, shadow=true.
- * @return {Deferred<*>}
- */
- exec: function (params) {
- var route = this._getRoute();
- var options = (params && params.options) ? params.options : {};
- var type = (params && params.type) ? params.type : 'event';
- if (type === 'event') {
- return this.parent.call('ajax', 'rpc', route, this._getParams(), options);
- } else if (type === 'ajax') {
- return ajax.rpc(route, this._getParams(), options);
+ if (options.method === 'read_group') {
+ params.kwargs.groupby = options.groupBy || params.kwargs.groupby || [];
+ params.kwargs.domain = options.domain || params.kwargs.domain || [];
+ params.kwargs.fields = options.fields || params.kwargs.fields || [];
+ params.kwargs.lazy = options.lazy || params.kwargs.lazy;
+ var orderBy = options.orderBy || params.orderBy;
+ params.kwargs.orderby = orderBy ? this._serializeSort(orderBy) : false;
}
- },
- /**
- * @param {Object} kwargs
- * @returns {BaseRPCBuilder}
- */
- kwargs: function (kwargs) {
- this._kwargs = kwargs;
- return this;
- },
- /**
- * @param {Object} params
- * @returns {BaseRPCBuilder}
- */
- params: function (params) {
- this._params = params;
- return this;
- },
- /**
- * @param {Object} context
- * @returns {BaseRPCBuilder}
- */
- withContext: function (context) {
- this._context = context;
- return this;
- },
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @returns {Object}
- */
- _getParams: function () {
- var kwargs = _.extend({}, this._kwargs);
- if (this._context) {
- kwargs.context = this._context;
+ if (options.method === 'search_read') {
+ // call the model method
+ params.args = [
+ options.domain || [],
+ options.fields || false,
+ options.offset || 0,
+ options.limit || false,
+ this._serializeSort(options.orderBy || params.orderBy || []),
+ ];
}
- var params = {
- method: this._method,
- model: this._model,
- args: this._args || (this._method ? [] : undefined),
- kwargs: this._method ? kwargs : undefined,
- };
- return _.defaults(params, this._params);
- },
- /**
- * @private
- * @returns {string}
- */
- _getRoute: function () {
- return this._route;
- },
-});
-var SearchRPCBuilder = BaseRPCBuilder.extend({
- init: function () {
- this._super.apply(this, arguments);
- this._route = '/web/dataset/search_read';
- this._orderBy = false;
- this._domain = [];
- this._fields = false;
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * @param {Object[]} orderBy
- * @returns {BaseRPCBuilder}
- */
- orderBy: function (orderBy) {
- // todo: serialize properly this
- this._orderBy = this._serializeSort(orderBy);
- return this;
- },
- /**
- * @param {Object} context
- * @returns {BaseRPCBuilder}
- */
- withContext: function (context) {
- this._context = context;
- return this;
- },
- /**
- * @param {Object} domain
- * @returns {BaseRPCBuilder}
- */
- withDomain: function (domain) {
- this._domain = domain;
- return this;
- },
- /**
- * @param {string[]} fields
- * @returns {BaseRPCBuilder}
- */
- withFields: function (fields) {
- this._fields = fields;
- return this;
- },
- /**
- * @param {Object} limit
- * @returns {BaseRPCBuilder}
- */
- withLimit: function (limit) {
- this._limit = limit;
- return this;
- },
- /**
- * @param {Object} offset
- * @returns {BaseRPCBuilder}
- */
- withOffset: function (offset) {
- this._offset = offset;
- return this;
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ if (options.route === '/web/dataset/search_read') {
+ // specifically call the controller
+ params.model = options.model || params.model;
+ params.domain = options.domain || params.domain || [];
+ params.fields = options.fields || params.fields || false;
+ params.limit = options.limit || params.limit;
+ params.offset = options.offset || params.offset ;
+ params.sort = this._serializeSort(options.orderBy || params.orderBy || []);
+ params.context = options.context || params.context || {};
+ }
- /**
- * @override
- * @private
- * @returns {Object}
- */
- _getParams: function () {
return {
- context: this._context || {},
- domain: this._domain,
- fields: this._fields,
- limit: this._limit,
- model: this._model,
- offset: this._offset,
- sort: this._orderBy
+ route: route,
+ params: JSON.parse(JSON.stringify(params)),
};
},
/**
@@ -212,85 +101,6 @@ var SearchRPCBuilder = BaseRPCBuilder.extend({
return order.name + (order.asc !== false ? ' ASC' : ' DESC');
}).join(', ');
},
-});
-
-var ReadGroupRPCBuilder = SearchRPCBuilder.extend({
- init: function () {
- this._super.apply(this, arguments);
- this._route = '/web/dataset/call_kw/' + this._model + '/read_group';
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * We need to make sure that arguments are properly set.
- * @override
- * @returns {Deferred<*>}
- */
- exec: function () {
- if (!this._groupBy) {
- throw new Error("read_group must have a group_by argument");
- }
- return this._super.apply(this, arguments);
- },
- /**
- * @param {string[]} groupBy
- * @returns {BaseRPCBuilder}
- */
- groupBy: function (groupBy) {
- // todo: serialize properly this
- this._groupBy = groupBy;
- return this;
- },
- /**
- * @param {boolean} lazy
- * @returns {BaseRPCBuilder}
- */
- lazy: function (lazy) {
- // todo: serialize properly this
- this._lazy = lazy;
- return this;
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * @override
- * @private
- * @returns {Object}
- */
- _getParams: function () {
- var kwargs = _.defaults({}, this._kwargs, {
- context: this._context || {},
- domain: this._domain || [],
- fields: this._fields,
- groupby: this._groupBy,
- lazy: !!this._lazy,
- orderby: this._orderBy,
- });
- return {
- args: this._args || [],
- kwargs: kwargs,
- method: 'read_group',
- model: this._model,
- };
- },
-});
-
-return {
- builders: {
- default: BaseRPCBuilder,
- search_read: SearchRPCBuilder,
- read_group: ReadGroupRPCBuilder,
- },
- query: function (params) {
- var Builder = this.builders[params.method] || this.builders.default;
- return new Builder(params.parent, params);
- },
};
});
diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js
index 6cc5529e34f..0bd9dc19ad4 100644
--- a/addons/web/static/src/js/core/session.js
+++ b/addons/web/static/src/js/core/session.js
@@ -99,9 +99,10 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
}
return $.when(
deferred,
- self.rpc('/web/webclient/bootstrap_translations', {mods: self.module_list}).then(function (trans) {
- _t.database.set_bundle(trans);
- })
+ self.rpc('/web/webclient/bootstrap_translations', {mods: self.module_list})
+ .then(function (trans) {
+ _t.database.set_bundle(trans);
+ })
);
});
},
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index 923e8400b1e..ef463338338 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -197,10 +197,12 @@ var FieldMany2One = AbstractField.extend({
var self = this;
var slowCreate = this._searchCreatePopup.bind(this, "form", false, this._createContext(name));
if (this.nodeOptions.quick_create) {
- this._rpc(this.field.relation, "name_create")
- .args([name])
- .kwargs({context: this.record.getContext({fieldName: this.name})})
- .exec()
+ this._rpc({
+ model: this.field.relation,
+ method: 'name_create',
+ args: [name],
+ context: this.record.getContext({fieldName: this.name})
+ })
.then(function (result) {
if (self.mode === "edit") {
self.reinitialize({id: result[0], display_name: result[1]});
@@ -267,15 +269,16 @@ var FieldMany2One = AbstractField.extend({
domain.push(['id', 'not in', blacklisted_ids]);
}
- this._rpc(this.field.relation, "name_search")
- .kwargs({
+ this._rpc({
+ model: this.field.relation,
+ method: "name_search",
+ kwargs: {
name: search_val,
args: domain,
operator: "ilike",
limit: this.limit + 1,
context: context,
- })
- .exec()
+ }})
.then(function (result) {
// possible selections for the m2o
var values = _.map(result, function (x) {
@@ -294,16 +297,18 @@ var FieldMany2One = AbstractField.extend({
values.push({
label: _t("Search More..."),
action: function () {
- self._rpc(self.field.relation, "name_search")
- .kwargs({
- name: search_val,
- args: domain,
- operator: "ilike",
- limit: 160,
- context: context,
- })
- .exec()
- .then(self._searchCreatePopup.bind(self, "search"));
+ self._rpc({
+ model: self.field.relation,
+ method: 'name_search',
+ kwargs: {
+ name: search_val,
+ args: domain,
+ operator: "ilike",
+ limit: 160,
+ context: context,
+ },
+ })
+ .then(self._searchCreatePopup.bind(self, "search"));
},
classname: 'o_m2o_dropdown_option',
});
@@ -385,10 +390,12 @@ var FieldMany2One = AbstractField.extend({
if (this.mode === 'readonly' && !this.nodeOptions.no_open) {
event.preventDefault();
event.stopPropagation();
- this._rpc(this.field.relation, 'get_formview_action')
- .args([[this.value.res_id]])
- .withContext(this.record.getContext({fieldName: this.name}))
- .exec()
+ this._rpc({
+ model: this.field.relation,
+ method: 'get_formview_action',
+ args: [[this.value.res_id]],
+ context: this.record.getContext({fieldName: this.name}),
+ })
.then(function (action) {
self.trigger_up('do_action', {action: action});
});
@@ -404,10 +411,12 @@ var FieldMany2One = AbstractField.extend({
}
var self = this;
var context = this.record.getContext({fieldName: this.name});
- this._rpc(this.field.relation, 'get_formview_id')
- .args([[this.value.res_id]])
- .withContext(context)
- .exec()
+ this._rpc({
+ model: this.field.relation,
+ method: 'get_formview_id',
+ args: [[this.value.res_id]],
+ context: context,
+ })
.then(function (view_id) {
new dialogs.FormViewDialog(self, {
res_model: self.field.relation,
diff --git a/addons/web/static/src/js/fields/upgrade_fields.js b/addons/web/static/src/js/fields/upgrade_fields.js
index a4246983dd1..66d6d2b2903 100644
--- a/addons/web/static/src/js/fields/upgrade_fields.js
+++ b/addons/web/static/src/js/fields/upgrade_fields.js
@@ -36,10 +36,11 @@ var AbstractFieldUpgrade = {
* @returns {Deferred}
*/
_confirmUpgrade: function () {
- var args = [[["share", "=", false]]];
- return this._rpc('res.users', 'search_count')
- .args(args)
- .exec()
+ return this._rpc({
+ model: 'res.users',
+ method: 'search_count',
+ args: [[["share", "=", false]]],
+ })
.then(function (data) {
framework.redirect("https://www.odoo.com/odoo-enterprise/upgrade?num_users=" + data);
});
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index deb14b8bf83..e3455658d50 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -194,10 +194,12 @@ var BasicModel = AbstractModel.extend({
deleteRecords: function (recordIds, modelName, parentID) {
var self = this;
var records = _.map(recordIds, function (id) { return self.localData[id]; });
- return this._rpc(modelName, 'unlink')
- .args([_.pluck(records, 'res_id')])
- .withContext(session.user_context) // todo: combine with view context
- .exec()
+ return this._rpc({
+ model: modelName,
+ method: 'unlink',
+ args: [_.pluck(records, 'res_id')],
+ context: session.user_context, // todo: combine with view context
+ })
.then(function () {
_.each(records, function (record) {
record.res_ids.splice(record.offset, 1)[0];
@@ -230,10 +232,12 @@ var BasicModel = AbstractModel.extend({
duplicateRecord: function (recordID) {
var self = this;
var record = this.localData[recordID];
- return this._rpc(record.model, 'copy')
- .args([record.data.id])
- .withContext(this._getContext(record))
- .exec()
+ return this._rpc({
+ model: record.model,
+ method: 'copy',
+ args: [record.data.id],
+ context: this._getContext(record),
+ })
.then(function (res_id) {
var index = record.res_ids.indexOf(record.res_id);
record.res_ids.splice(index + 1, 0, res_id);
@@ -439,10 +443,12 @@ var BasicModel = AbstractModel.extend({
var self = this;
var fields_key = _.without(params.fieldNames, '__last_update');
- return this._rpc(modelName, 'default_get')
- .args([fields_key])
- .withContext(params.context)
- .exec()
+ return this._rpc({
+ model: modelName,
+ method: 'default_get',
+ args: [fields_key],
+ context: params.context,
+ })
.then(function (result) {
// fill default values for missing fields
for (var i = 0; i < params.fieldNames.length; i++) {
@@ -813,11 +819,12 @@ var BasicModel = AbstractModel.extend({
// in the case of a write, only perform the RPC if there are changes to save
if (method === 'create' || Object.keys(changes).length) {
var args = method === 'write' ? [[record.data.id], changes] : [changes];
- return self._rpc(record.model, method)
- .args(args)
- .withContext(session.user_context) // todo: combine with view context
- .exec()
- .then(function (id) {
+ return self._rpc({
+ model: record.model,
+ method: method,
+ args: args,
+ context: session.user_context // todo: combine with view context
+ }).then(function (id) {
if (method === 'create') {
record.res_id = id; // create returns an id, write returns a boolean
record.data.id = id;
@@ -911,9 +918,11 @@ var BasicModel = AbstractModel.extend({
var resIDs = _.map(recordIDs, function (recordID) {
return self.localData[recordID].res_id;
});
- return this._rpc(parent.model, 'write')
- .args([resIDs, { active: value }])
- .exec()
+ return this._rpc({
+ model: parent.model,
+ method: 'write',
+ args: [resIDs, { active: value }],
+ })
.then(this.reload.bind(this, parentID));
},
@@ -969,10 +978,12 @@ var BasicModel = AbstractModel.extend({
var def;
if (rel_data.display_name === undefined) {
var field = record.fields[fieldName];
- def = this._rpc(field.relation, 'name_get')
- .args([data.id])
- .withContext(record.context)
- .exec()
+ def = this._rpc({
+ model: field.relation,
+ method: 'name_get',
+ args: [data.id],
+ context: record.context,
+ })
.then(function (result) {
rel_data.display_name = result[0][1];
});
@@ -1022,9 +1033,11 @@ var BasicModel = AbstractModel.extend({
fields = fields[0];
}
return this.mutex.exec(function () {
- return self._rpc(record.model, 'onchange')
- .args([idList, currentData, fields, onchange_spec, context])
- .exec()
+ return self._rpc({
+ model: record.model,
+ method: 'onchange',
+ args: [idList, currentData, fields, onchange_spec, context],
+ })
.then(function (result) {
if (result.warning) {
self.trigger_up('warning', {
@@ -1176,9 +1189,11 @@ var BasicModel = AbstractModel.extend({
// _changes so this is a very specific case)
// this could be optimized by registering the fetched records in the list's _cache
// so that if a record is removed and then re-added, it won't be fetched twice
- var def = this._rpc(list.model, 'read')
- .args([_.pluck(data, 'id'), list.fieldNames])
- .exec()
+ var def = this._rpc({
+ model: list.model,
+ method: 'read',
+ args: [_.pluck(data, 'id'), list.fieldNames]
+ })
.then(function (records) {
_.each(records, function (record) {
list_records[record.id].data = record;
@@ -1262,10 +1277,12 @@ var BasicModel = AbstractModel.extend({
_fetchMany2OneGroup: function (group) {
var ids = _.uniq(_.pluck(group, 'res_id'));
- return this._rpc(group[0].model, 'name_get')
- .args([ids])
- .withContext(group[0].context)
- .exec()
+ return this._rpc({
+ model: group[0].model,
+ method: 'name_get',
+ args: [ids],
+ context: group[0].context
+ })
.then(function (name_gets) {
_.each(group, function (record) {
var nameGet = _.find(name_gets, function (n) { return n[0] === record.res_id;});
@@ -1286,10 +1303,12 @@ var BasicModel = AbstractModel.extend({
model = many2oneRecord.model;
return many2oneRecord.res_id;
});
- return this._rpc(model, 'name_get')
- .args([ids])
- .withContext(list.context)
- .exec()
+ return this._rpc({
+ model: model,
+ method: 'name_get',
+ args: [ids],
+ context: list.context,
+ })
.then(function (name_gets) {
for (var i = 0; i < name_gets.length; i++) {
records[i].data.display_name = name_gets[i][1];
@@ -1307,10 +1326,12 @@ var BasicModel = AbstractModel.extend({
_fetchRecord: function (record, fieldNames) {
var self = this;
fieldNames = fieldNames || _.uniq(record.fieldNames.concat(['display_name']));
- return this._rpc(record.model, 'read')
- .args([[record.res_id], fieldNames])
- // .withContext({ bin_size: true }) // FIXME: when editing a subrecord in the partner form view, it tries to write the bin_size on the image field
- .exec()
+ return this._rpc({
+ model: record.model,
+ method: 'read',
+ args: [[record.res_id], fieldNames],
+ // context: {bin_size: true} // FIXME: when editing a subrecord in the partner form view, it tries to write the bin_size on the image field
+ })
.then(function (result) {
result = result[0];
record.data = _.extend({}, record.data, result);
@@ -1436,25 +1457,29 @@ var BasicModel = AbstractModel.extend({
}
var self = this;
- return this._rpc(field.relation, 'search_read')
- .withFields(["id"].concat(fieldsToRead || []))
- .withContext(context)
- .withDomain(domain)
- .exec()
- .then(function (result) {
- var ids = _.pluck(result.records, 'id');
- return self._rpc(field.relation, 'name_get')
- .args([ids])
- .withContext(context)
- .exec()
+ return this._rpc({
+ model: field.relation,
+ method: 'search_read',
+ fields: ["id"].concat(fieldsToRead || []),
+ context: context,
+ domain: domain,
+ })
+ .then(function (records) {
+ var ids = _.pluck(records, 'id');
+ return self._rpc({
+ model: field.relation,
+ method: 'name_get',
+ args: [ids],
+ context: context,
+ })
.then(function (name_gets) {
- _.each(result.records, function (rec) {
+ _.each(records, function (rec) {
var name_get = _.find(name_gets, function (n) {
return n[0] === rec.id;
});
rec.display_name = name_get[1];
});
- return result.records;
+ return records;
});
});
},
@@ -1488,10 +1513,12 @@ var BasicModel = AbstractModel.extend({
return $.when();
}
- return this._rpc(field.relation, "name_search")
- .args(["", domain])
- .withContext(context)
- .exec();
+ return this._rpc({
+ model: field.relation,
+ method: 'name_search',
+ args: ["", domain],
+ context: context
+ });
},
/**
* Fetches all the m2o records associated to the given fieldName. If the
@@ -1550,10 +1577,12 @@ var BasicModel = AbstractModel.extend({
var def = $.Deferred();
- this._rpc(domainModel, "search_count")
- .args([Domain.prototype.stringToArray(domainValue)])
- .withContext(context)
- .exec()
+ this._rpc({
+ model: domainModel,
+ method: 'search_count',
+ args: [Domain.prototype.stringToArray(domainValue)],
+ context: context
+ })
.then(_.identity, function (error, e) {
e.preventDefault(); // prevent traceback (the search_count might be intended to break)
return false;
@@ -1670,10 +1699,12 @@ var BasicModel = AbstractModel.extend({
}
// step 2: fetch data from server
- return this._rpc(field.relation, 'read')
- .args([ids, _.keys(fieldInfo.relatedFields)])
- .withContext({}) // FIXME
- .exec()
+ return this._rpc({
+ model: field.relation,
+ method: 'read',
+ args: [ids, _.keys(fieldInfo.relatedFields)],
+ context: {}, // FIXME
+ })
.then(function (results) {
// step 3: assign values to correct datapoints
var dataPoints = _.map(results, function (result) {
@@ -2038,10 +2069,12 @@ var BasicModel = AbstractModel.extend({
if (options.always_reload) {
if (record.fields[name].type === 'many2one' && record.data[name]) {
var element = self.localData[record.data[name]];
- defs.push(self._rpc(field.relation, 'name_get')
- .args([element.data.id])
- .withContext(self._getContext(record, {fieldName: name}))
- .exec()
+ defs.push(self._rpc({
+ model: field.relation,
+ method: 'name_get',
+ args: [element.data.id],
+ context: self._getContext(record, {fieldName: name}),
+ })
.then(function (result) {
element.data.display_name = result[0][1];
}));
@@ -2066,13 +2099,15 @@ var BasicModel = AbstractModel.extend({
_readGroup: function (list) {
var self = this;
var fields = _.uniq(list.fieldNames.concat(list.groupedBy));
- return this._rpc(list.model, 'read_group')
- .withFields(fields)
- .withDomain(list.domain)
- .withContext(list.context)
- .groupBy(list.groupedBy)
- .lazy(true)
- .exec()
+ return this._rpc({
+ model: list.model,
+ method: 'read_group',
+ fields: fields,
+ domain: list.domain,
+ context: list.context,
+ groupBy: list.groupedBy,
+ lazy: true,
+ })
.then(function (groups) {
var rawGroupBy = list.groupedBy[0].split(':')[0];
var previousGroups = _.map(list.data, function (groupID) {
@@ -2158,10 +2193,12 @@ var BasicModel = AbstractModel.extend({
}
}
if (missingIds.length) {
- def = this._rpc(list.model, 'read')
- .args([missingIds, list.fieldNames])
- .withContext({}) // FIXME
- .exec();
+ def = this._rpc({
+ model: list.model,
+ method: 'read',
+ args: [missingIds, list.fieldNames],
+ context: {} // FIXME
+ });
} else {
def = $.when();
}
@@ -2219,33 +2256,35 @@ var BasicModel = AbstractModel.extend({
*/
_searchReadUngroupedList: function (list) {
var self = this;
- return this._rpc(list.model, 'search_read')
- .withFields(list.fieldNames)
- .withDomain(list.domain || [])
- .withLimit(list.limit)
- .withOffset(list.offset)
- .orderBy(list.orderedBy)
- .exec()
- .then(function (result) {
- list.count = result.length;
- var data = _.map(result.records, function (record) {
- var dataPoint = self._makeDataPoint({
- data: record,
- fields: list.fields,
- fieldNames: list.fieldNames,
- fieldsInfo: list.fieldsInfo,
- modelName: list.model,
- parentID: list.id,
- });
-
- // add many2one records
- self._parseServerData(list.fieldNames, dataPoint.fields, dataPoint.data);
- return dataPoint.id;
+ return this._rpc({
+ route: '/web/dataset/search_read',
+ model: list.model,
+ fields: list.fieldNames,
+ domain: list.domain || [],
+ limit: list.limit,
+ offset: list.offset,
+ orderBy: list.orderedBy,
+ })
+ .then(function (result) {
+ list.count = result.length;
+ var data = _.map(result.records, function (record) {
+ var dataPoint = self._makeDataPoint({
+ data: record,
+ fields: list.fields,
+ fieldNames: list.fieldNames,
+ fieldsInfo: list.fieldsInfo,
+ modelName: list.model,
+ parentID: list.id,
});
- list.data = data;
- list.res_ids = _.pluck(result.records, 'id');
- return list;
+
+ // add many2one records
+ self._parseServerData(list.fieldNames, dataPoint.fields, dataPoint.data);
+ return dataPoint.id;
});
+ list.data = data;
+ list.res_ids = _.pluck(result.records, 'id');
+ return list;
+ });
},
/**
* Change the offset of a record. Note that this does not reload the data.
diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js
index 4e0ace6926b..0efb196ebcf 100644
--- a/addons/web/static/src/js/views/calendar/calendar_controller.js
+++ b/addons/web/static/src/js/views/calendar/calendar_controller.js
@@ -103,9 +103,11 @@ var CalendarController = AbstractController.extend({
_updateRecord: function (record) {
// Cannot modify actual name yet
var data = _.omit(this.model.calendarEventToRecord(record), 'name');
- this._rpc(this.model.modelName, 'write')
- .args([record.id, data])
- .exec()
+ this._rpc({
+ model: this.model.modelName,
+ method: 'write',
+ args: [record.id, data],
+ })
.then(this.reload.bind(this));
},
@@ -231,9 +233,11 @@ var CalendarController = AbstractController.extend({
click: function () {
Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), {
confirm_callback: function () {
- self._rpc(self.modelName, 'unlink')
- .args([id])
- .exec()
+ self._rpc({
+ model: self.modelName,
+ method: 'unlink',
+ args: [id],
+ })
.then(function () {
self.dialog.destroy();
self.reload();
diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js
index 07327616097..34723e63995 100644
--- a/addons/web/static/src/js/views/calendar/calendar_model.js
+++ b/addons/web/static/src/js/views/calendar/calendar_model.js
@@ -127,10 +127,12 @@ return AbstractModel.extend({
* @returns
*/
deleteRecords: function (ids, model) {
- return this._rpc(model, 'unlink')
- .args([ids])
- .withContext(session.user_context) // todo: combine with view context
- .exec();
+ return this._rpc({
+ model: model,
+ method: 'unlink',
+ args: [ids],
+ context: session.user_context, // todo: combine with view context
+ });
},
/**
* @override
@@ -168,8 +170,8 @@ return AbstractModel.extend({
if (!this.preload_def) {
this.preload_def = $.Deferred();
$.when(
- this._rpc(this.modelName, 'check_access_rights').args(["write", false]).exec(),
- this._rpc(this.modelName, 'check_access_rights').args(["create", false]).exec())
+ this._rpc({model: this.modelName, method: 'check_access_rights', args: ["write", false]}),
+ this._rpc({model: this.modelName, method: 'check_access_rights', args: ["create", false]}))
.then(function (write, create) {
self.write_right = write;
self.create_right = create;
@@ -364,13 +366,15 @@ return AbstractModel.extend({
var defs = _.map(this.data.filters, this._loadFilter.bind(this));
return $.when.apply($, defs).then(function () {
- return self._rpc(self.modelName, 'search_read')
- .withContext(self.data.context)
- .withFields(self.fieldNames)
- .withDomain(self.data.domain.concat(self._getRangeDomain()).concat(self._getFilterDomain()))
- .exec()
+ return self._rpc({
+ model: self.modelName,
+ method: 'search_read',
+ context: self.data.context,
+ fields: self.fieldNames,
+ domain: self.data.domain.concat(self._getRangeDomain()).concat(self._getFilterDomain())
+ })
.then(function (events) {
- self.data.data = _.map(events.records, self._recordToCalendarEvent.bind(self));
+ self.data.data = _.map(events, self._recordToCalendarEvent.bind(self));
return $.when(
self._loadColors(self.data, self.data.data),
self._loadRecordsToFilters(self.data, self.data.data)
@@ -404,12 +408,14 @@ return AbstractModel.extend({
}
var field = this.fields[filter.fieldName];
- return this._rpc(filter.write_model, 'search_read')
- .withDomain([["user_id", "=", session.uid]])
- .withFields([filter.write_field])
- .exec()
+ return this._rpc({
+ model: filter.write_model,
+ method: 'search_read',
+ domain: [["user_id", "=", session.uid]],
+ fields: [filter.write_field],
+ })
.then(function (res) {
- var records = _.map(res.records, function (record) {
+ var records = _.map(res, function (record) {
var _value = record[filter.write_field];
var value = _.isArray(_value) ? _value[0] : _value;
var f = _.find(filter.filters, function (f) {return f.value === value;});
@@ -511,9 +517,11 @@ return AbstractModel.extend({
var defs = [];
_.each(to_read, function (ids, model) {
- defs.push(self._rpc(model, 'name_get')
- .args([_.uniq(ids)])
- .exec()
+ defs.push(self._rpc({
+ model: model,
+ method: 'name_get',
+ args: [_.uniq(ids)],
+ })
.then(function (res) {
to_read[model] = _.object(res);
}));
diff --git a/addons/web/static/src/js/views/calendar/calendar_quick_create.js b/addons/web/static/src/js/views/calendar/calendar_quick_create.js
index 008f2d74e04..8bf2bc8235a 100644
--- a/addons/web/static/src/js/views/calendar/calendar_quick_create.js
+++ b/addons/web/static/src/js/views/calendar/calendar_quick_create.js
@@ -122,10 +122,12 @@ var QuickCreate = Dialog.extend({
*/
_quickCreate: function (data, options) {
var self = this;
- return this._rpc(this.modelName, 'create')
- .args([$.extend({}, this.data_template, data)])
- .withContext(_.pick(options, 'context'))
- .exec()
+ return this._rpc({
+ model: this.modelName,
+ method: 'create',
+ args: [$.extend({}, this.data_template, data)],
+ context: _.pick(options, 'context'),
+ })
.then(function (id) {
self.trigger('added', id);
self.$input.val("");
diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js
index 9095e5c13f7..7a38a0d4348 100644
--- a/addons/web/static/src/js/views/calendar/calendar_renderer.js
+++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js
@@ -92,9 +92,11 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
var self = this;
event.stopPropagation();
var value = event.data.changes[this.write_field].id;
- this._rpc(this.write_model, 'create')
- .args([{'user_id': session.uid,'partner_id': value,}])
- .exec()
+ this._rpc({
+ model: this.write_model,
+ method: 'create',
+ args: [{'user_id': session.uid,'partner_id': value,}],
+ })
.then(function () {
self.trigger_up('changeFilter', {
'fieldName': self.fieldName,
@@ -119,9 +121,11 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
var $filter = $(e.currentTarget).closest('.o_calendar_filter_item');
Dialog.confirm(this, _t("Do you really want to delete this filter from favorites ?"), {
confirm_callback: function () {
- self._rpc(self.write_model, 'unlink')
- .args([[$filter.data('id')]])
- .exec()
+ self._rpc({
+ model: self.write_model,
+ method: 'unlink',
+ args: [[$filter.data('id')]],
+ })
.then(function () {
self.trigger_up('changeFilter', {
'fieldName': self.fieldName,
diff --git a/addons/web/static/src/js/views/graph/graph_model.js b/addons/web/static/src/js/views/graph/graph_model.js
index 7bf9757a255..c14c698331d 100644
--- a/addons/web/static/src/js/views/graph/graph_model.js
+++ b/addons/web/static/src/js/views/graph/graph_model.js
@@ -130,13 +130,15 @@ return AbstractModel.extend({
if (this.chart.measure !== '__count__') {
fields = fields.concat(this.chart.measure);
}
- return this._rpc(this.modelName, 'read_group')
- .withContext(this.chart.context)
- .withDomain(this.chart.domain)
- .withFields(fields)
- .groupBy(this.chart.groupedBy)
- .lazy(false)
- .exec()
+ return this._rpc({
+ model: this.modelName,
+ method: 'read_group',
+ context: this.chart.context,
+ domain: this.chart.domain,
+ fields: fields,
+ groupBy: this.chart.groupedBy,
+ lazy: false,
+ })
.then(this._processData.bind(this));
},
/**
diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js
index c74f06d1de1..5d48fde2cca 100644
--- a/addons/web/static/src/js/views/kanban/kanban_controller.js
+++ b/addons/web/static/src/js/views/kanban/kanban_controller.js
@@ -308,10 +308,12 @@ var KanbanController = BasicController.extend({
var context = columnState.getContext();
context['default_' + state.groupedBy[0]] = columnState.res_id;
- this._rpc(state.model, "name_create")
- .args([name])
- .withContext(context)
- .exec()
+ this._rpc({
+ model: state.model,
+ method: 'name_create',
+ args: [name],
+ context: context,
+ })
.then(add_record)
.fail(function (error, event) {
event.preventDefault();
diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js
index 394ff80b234..ff8b357a6ac 100644
--- a/addons/web/static/src/js/views/kanban/kanban_model.js
+++ b/addons/web/static/src/js/views/kanban/kanban_model.js
@@ -53,10 +53,12 @@ var KanbanModel = BasicModel.extend({
if (!groupByField || groupByField.type !== 'many2one') {
return $.Deferred().reject(); // only supported when grouped on m2o
}
- return this._rpc(groupByField.relation, 'name_create')
- .args([name])
- .withContext(parent.context) // todo: combine with view context
- .exec()
+ return this._rpc({
+ model: groupByField.relation,
+ method: 'name_create',
+ args: [name],
+ context: parent.context, // todo: combine with view context
+ })
.then(function (result) {
var newGroup = self._makeDataPoint({
modelName: parent.model,
@@ -154,9 +156,10 @@ var KanbanModel = BasicModel.extend({
}
var self = this;
var data = this.localData[parentID];
- return this._rpc('/web/dataset/resequence')
- .params({model: modelName, ids: resIDs})
- .exec()
+ return this._rpc({
+ route: '/web/dataset/resequence',
+ params: {model: modelName, ids: resIDs},
+ })
.then(function () {
data.data = _.sortBy(data.data, function (d) {
return _.indexOf(resIDs, self.localData[d].res_id);
diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js
index f1998e01e1a..969a4d5ee82 100644
--- a/addons/web/static/src/js/views/pivot/pivot_model.js
+++ b/addons/web/static/src/js/views/pivot/pivot_model.js
@@ -82,13 +82,15 @@ var PivotModel = AbstractModel.extend({
}
return $.when.apply(null, groupbys.map(function (groupBy) {
- return self._rpc(self.modelName, 'read_group')
- .withContext(self.data.context)
- .withDomain(header.domain.length ? header.domain : self.data.domain)
- .withFields(_.map(fields, function (field) { return field.split(':')[0]; }))
- .groupBy(groupBy)
- .lazy(false)
- .exec();
+ return self._rpc({
+ model: self.modelName,
+ method: 'read_group',
+ context: self.data.context,
+ domain: header.domain.length ? header.domain : self.data.domain,
+ fields: _.map(fields, function (field) { return field.split(':')[0]; }),
+ groupBy: groupBy,
+ lazy: false,
+ });
})).then(function () {
var data = Array.prototype.slice.call(arguments);
var datapt, attrs, j, l, row, col, cell_value, groupBys;
@@ -513,13 +515,15 @@ var PivotModel = AbstractModel.extend({
}
return $.when.apply(null, groupBys.map(function (groupBy) {
- return self._rpc(self.modelName, 'read_group')
- .withContext(self.data.context)
- .withDomain(self.data.domain)
- .withFields(_.map(fields, function (field) { return field.split(':')[0]; }))
- .groupBy(groupBy)
- .lazy(false)
- .exec();
+ return self._rpc({
+ model: self.modelName,
+ method: 'read_group',
+ context: self.data.context,
+ domain: self.data.domain,
+ fields: _.map(fields, function (field) { return field.split(':')[0]; }),
+ groupBy: groupBy,
+ lazy: false,
+ });
})).then(function () {
var data = Array.prototype.slice.call(arguments);
if (data[0][0].__count === 0) {
diff --git a/addons/web/static/src/js/widgets/change_password.js b/addons/web/static/src/js/widgets/change_password.js
index c1c9c4dddea..b71ae4aaf4b 100644
--- a/addons/web/static/src/js/widgets/change_password.js
+++ b/addons/web/static/src/js/widgets/change_password.js
@@ -31,11 +31,12 @@ var ChangePassword = Widget.extend({
self.$el.parents('.modal').modal('hide');
});
$button.eq(0).click(function () {
- self._rpc('/web/session/change_password')
- .params({
- fields: $('form[name=change_password_form]').serializeArray()
+ self._rpc({
+ route: '/web/session/change_password',
+ params: {
+ fields: $('form[name=change_password_form]').serializeArray()
+ }
})
- .exec()
.done(function (result) {
if (result.error) {
self._display_error(result);
diff --git a/addons/web/static/src/js/widgets/data_export.js b/addons/web/static/src/js/widgets/data_export.js
index dbe4c4d3d3c..f8c622bf5e8 100644
--- a/addons/web/static/src/js/widgets/data_export.js
+++ b/addons/web/static/src/js/widgets/data_export.js
@@ -218,18 +218,19 @@ var DataExport = Dialog.extend({
this.$fields_list = this.$('.o_fields_list');
this.$import_compat_radios = this.$('.o_import_compat input');
- waitFor.push(this._rpc('/web/export/formats').exec().then(do_setup_export_formats));
+ waitFor.push(this._rpc({route: '/web/export/formats'}).then(do_setup_export_formats));
var got_fields = new $.Deferred();
this.$import_compat_radios.change(function(e) {
self.$('.o_field_tree_structure').remove();
- self._rpc("/web/export/get_fields")
- .params({
- model: self.dataset.model,
- import_compat: !!$(e.target).val(),
+ self._rpc({
+ route: '/web/export/get_fields',
+ params: {
+ model: self.dataset.model,
+ import_compat: !!$(e.target).val(),
+ },
})
- .exec()
.done(function (records) {
var compatible_fields = _.map(records, function (record) {return record.id});
self.$fields_list
@@ -299,12 +300,13 @@ var DataExport = Dialog.extend({
self.$fields_list.empty();
var export_id = self.$('.o_exported_lists_select option:selected').val();
if(export_id) {
- self._rpc('/web/export/namelist')
- .params({
- model: self.dataset.model,
- export_id: parseInt(export_id, 10),
+ self._rpc({
+ route: '/web/export/namelist',
+ params: {
+ model: self.dataset.model,
+ export_id: parseInt(export_id, 10),
+ },
})
- .exec()
.then(do_load_export_field);
}
});
@@ -347,16 +349,17 @@ var DataExport = Dialog.extend({
if(!record.loaded) {
var self = this;
- this._rpc("/web/export/get_fields")
- .params({
- model: model,
- prefix: prefix,
- parent_name: name,
- import_compat: !!this.$import_compat_radios.filter(':checked').val(),
- parent_field_type : record['field_type'],
- exclude: exclude_fields
+ this._rpc({
+ route: '/web/export/get_fields',
+ params: {
+ model: model,
+ prefix: prefix,
+ parent_name: name,
+ import_compat: !!this.$import_compat_radios.filter(':checked').val(),
+ parent_field_type : record['field_type'],
+ exclude: exclude_fields
+ },
})
- .exec()
.done(function(results) {
record.loaded = true;
self.on_show_data(results, record.id);
diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js
index 697572257f8..fba49f71ade 100644
--- a/addons/web/static/src/js/widgets/debug_manager.js
+++ b/addons/web/static/src/js/widgets/debug_manager.js
@@ -63,13 +63,17 @@ var DebugManager = Widget.extend({
// whether the current user is an administrator
this._is_admin = session.is_system;
return $.when(
- this._rpc('res.users', 'check_access_rights')
- .kwargs({operation: 'write', raise_exception: false})
- .exec(),
+ this._rpc({
+ model: 'res.users',
+ method: 'check_access_rights',
+ kwargs: {operation: 'write', raise_exception: false},
+ }),
session.user_has_group('base.group_no_one'),
- this._rpc('ir.model.data', 'xmlid_to_res_id')
- .kwargs({xmlid: 'base.group_no_one'})
- .exec(),
+ this._rpc({
+ model: 'ir.model.data',
+ method: 'xmlid_to_res_id',
+ kwargs: {xmlid: 'base.group_no_one'},
+ }),
this._super()
).then(function (can_write_user, has_group_no_one, group_no_one_id) {
this._features_group = can_write_user && group_no_one_id;
@@ -165,11 +169,13 @@ var DebugManager = Widget.extend({
title: _t('Select a view'),
disable_multiple_selection: true,
on_selected: function (element_ids) {
- self._rpc('ir.ui.view', 'search_read')
- .withDomain([['id', '=', element_ids[0]]])
- .withFields(['name', 'model', 'type'])
- .withLimit(1)
- .exec()
+ self._rpc({
+ model: 'ir.ui.view',
+ method: 'search_read',
+ domain: [['id', '=', element_ids[0]]],
+ fields: ['name', 'model', 'type'],
+ limit: 1,
+ })
.then(function (view) {
self.do_action({
type: 'ir.actions.act_window',
@@ -228,11 +234,13 @@ DebugManager.include({
get_view_fields: function () {
var self = this;
var model = this._action.res_model;
- this._rpc(model, 'fields_get')
- .kwargs({
- attributes: ['string', 'searchable', 'required', 'readonly', 'type', 'store', 'sortable', 'relation', 'help']
+ this._rpc({
+ model: model,
+ method: 'fields_get',
+ kwargs: {
+ attributes: ['string', 'searchable', 'required', 'readonly', 'type', 'store', 'sortable', 'relation', 'help']
+ },
})
- .exec()
.done(function (fields) {
new Dialog(self, {
title: _.str.sprintf(_t("Fields of %s"), model),
@@ -266,9 +274,11 @@ DebugManager.include({
});
},
translate: function() {
- this._rpc("ir.translation", 'get_technical_translations')
- .args([this._action.res_model])
- .exec()
+ this._rpc({
+ model: 'ir.translation',
+ method: 'get_technical_translations',
+ args: [this._action.res_model],
+ })
.then(this.do_action);
}
});
@@ -283,9 +293,11 @@ DebugManager.include({
this._can_edit_views = false;
return $.when(
this._super(),
- this._rpc('ir.ui.view', 'check_access_rights')
- .kwargs({operation: 'write', raise_exception: false})
- .exec()
+ this._rpc({
+ model: 'ir.ui.view',
+ method: 'check_access_rights',
+ kwargs: {operation: 'write', raise_exception: false},
+ })
.then(function (ar) {
this._can_edit_views = ar;
}.bind(this))
diff --git a/addons/web/static/src/js/widgets/model_field_selector.js b/addons/web/static/src/js/widgets/model_field_selector.js
index 41433253499..ebe190b5b44 100644
--- a/addons/web/static/src/js/widgets/model_field_selector.js
+++ b/addons/web/static/src/js/widgets/model_field_selector.js
@@ -317,11 +317,14 @@ var ModelFieldSelector = Widget.extend({
_getModelFieldsFromCache: function (model, filters) {
var def = modelFieldsCache.cacheDefs[model];
if (!def) {
- def = modelFieldsCache.cacheDefs[model] = this._rpc(model, "fields_get")
- .args([
- false,
- ["store", "searchable", "type", "string", "relation", "selection", "related"]])
- .exec()
+ def = modelFieldsCache.cacheDefs[model] = this._rpc({
+ model: model,
+ method: 'fields_get',
+ args: [
+ false,
+ ["store", "searchable", "type", "string", "relation", "selection", "related"]
+ ]
+ })
.then((function (fields) {
modelFieldsCache.cache[model] = sortFields(fields);
}).bind(this));
diff --git a/addons/web/static/src/js/widgets/switch_company_menu.js b/addons/web/static/src/js/widgets/switch_company_menu.js
index 1f5f0733938..8bea91a5a97 100644
--- a/addons/web/static/src/js/widgets/switch_company_menu.js
+++ b/addons/web/static/src/js/widgets/switch_company_menu.js
@@ -18,9 +18,11 @@ var SwitchCompanyMenu = Widget.extend({
this.$el.on('click', '.dropdown-menu li a[data-menu]', _.debounce(function(ev) {
ev.preventDefault();
var company_id = $(ev.currentTarget).data('company-id');
- self._rpc('res.users', 'write')
- .args([[session.uid], {'company_id': company_id}])
- .exec()
+ self._rpc({
+ model: 'res.users',
+ method: 'write',
+ args: [[session.uid], {'company_id': company_id}],
+ })
.then(function() {
location.reload();
});
diff --git a/addons/web/static/test/core/rpc_tests.js b/addons/web/static/test/core/rpc_tests.js
index 053cace7ce6..bafe008089b 100644
--- a/addons/web/static/test/core/rpc_tests.js
+++ b/addons/web/static/test/core/rpc_tests.js
@@ -2,254 +2,215 @@ odoo.define('web.rpc_tests', function (require) {
"use strict";
var rpc = require('web.rpc');
-var testUtils = require('web.test_utils');
-var Widget = require('web.Widget');
-
-function createQuery (params) {
- var widget = new Widget();
-
- if (params.mockRPC) {
- testUtils.intercept(widget, 'call_service', function (event) {
- if (event.data.service === 'ajax') {
- params.mockRPC(event.data.args[0], JSON.parse(JSON.stringify(event.data.args[1])));
- }
- });
-
- }
-
- return rpc.query({
- method: params.method,
- model: params.model,
- route: params.route,
- parent: widget,
- });
-}
QUnit.module('core', {}, function () {
QUnit.module('RPC Builder');
QUnit.test('basic rpc (route)', function (assert) {
- assert.expect(3);
- var query = createQuery({
+ assert.expect(1);
+
+ var query = rpc.buildQuery({
route: '/my/route',
- mockRPC: function (route, params) {
- assert.strictEqual(route, '/my/route',
- "should call the proper route");
- assert.notOk('args' in params,
- "rpc on routes should not have any args by default");
- assert.notOk('kwargs' in params,
- "rpc on routes should not have any kwargs by default");
- },
});
- query.exec();
+ assert.strictEqual(query.route, '/my/route', "should have the proper route");
});
QUnit.test('rpc on route with parameters', function (assert) {
assert.expect(1);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
route: '/my/route',
- mockRPC: function (route, params) {
- assert.deepEqual(params, {hey: 'there', model: 'test'},
- "should transfer the proper parameters");
- },
+ params: {hey: 'there', model: 'test'},
});
- query.params({hey: 'there', model: 'test'}).exec();
+
+ assert.deepEqual(query.params, {hey: 'there', model: 'test'},
+ "should transfer the proper parameters");
});
QUnit.test('basic rpc, with no context', function (assert) {
assert.expect(1);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'test',
- mockRPC: function (route, params) {
- assert.notOk('context' in params.kwargs,
- "does not automatically add a context");
- }
+ kwargs: {},
});
- query.kwargs({}).exec();
+ assert.notOk(query.params.kwargs.context,
+ "does not automatically add a context");
});
QUnit.test('basic rpc, with context', function (assert) {
assert.expect(1);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'test',
- mockRPC: function (route, args) {
- assert.deepEqual(args.kwargs.context, {a: 1},
- "properly transfer the context");
- }
+ context: {a: 1},
});
- query.withContext({a: 1}).exec();
+
+ assert.deepEqual(query.params.kwargs.context, {a: 1},
+ "properly transfer the context");
});
QUnit.test('basic rpc, with context, part 2', function (assert) {
assert.expect(1);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'test',
- mockRPC: function (route, args) {
- assert.deepEqual(args.kwargs.context, {a: 1},
- "properly transfer the context");
- }
+ kwargs: {context: {a: 1}},
});
- query.kwargs({context: {a: 1}}).exec();
+
+ assert.deepEqual(query.params.kwargs.context, {a: 1},
+ "properly transfer the context");
+
});
QUnit.test('basic rpc (method of model)', function (assert) {
assert.expect(3);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'test',
- mockRPC: function (route, args) {
- assert.strictEqual(route, '/web/dataset/call_kw/partner/test',
- "should call the proper route");
- assert.strictEqual(args.model, 'partner',
- "should correctly specify the model");
- assert.strictEqual(args.method, 'test',
- "should correctly specify the method");
- }
+ kwargs: {context: {a: 1}},
});
- query.exec();
+
+ assert.strictEqual(query.route, '/web/dataset/call_kw/partner/test',
+ "should call the proper route");
+ assert.strictEqual(query.params.model, 'partner',
+ "should correctly specify the model");
+ assert.strictEqual(query.params.method, 'test',
+ "should correctly specify the method");
});
QUnit.test('rpc with args and kwargs', function (assert) {
assert.expect(4);
- var query = createQuery({
+ var query = rpc.buildQuery({
model: 'partner',
method: 'test',
- mockRPC: function (route, args) {
- assert.strictEqual(route, '/web/dataset/call_kw/partner/test',
- "should call the proper route");
- assert.strictEqual(args.args[0], 'arg1',
- "should call with correct args");
- assert.strictEqual(args.args[1], 2,
- "should call with correct args");
- assert.strictEqual(args.kwargs.k, 78,
- "should call with correct kargs");
- }
+ args: ['arg1', 2],
+ kwargs: {k: 78},
});
- query
- .args(['arg1', 2])
- .kwargs({k: 78})
- .exec();
+
+ assert.strictEqual(query.route, '/web/dataset/call_kw/partner/test',
+ "should call the proper route");
+ assert.strictEqual(query.params.args[0], 'arg1',
+ "should call with correct args");
+ assert.strictEqual(query.params.args[1], 2,
+ "should call with correct args");
+ assert.strictEqual(query.params.kwargs.k, 78,
+ "should call with correct kargs");
});
- QUnit.test('rpc with context', function (assert) {
+ QUnit.test('search_read controller', function (assert) {
assert.expect(1);
- var query = createQuery({
+ var query = rpc.buildQuery({
+ route: '/web/dataset/search_read',
model: 'partner',
- method: 'test',
- mockRPC: function (route, args) {
- assert.deepEqual(args.kwargs.context, { a: 'hello' },
- "should have correct context");
- },
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ limit: 32,
+ offset: 2,
+ orderBy: [{name: 'yop', asc: true}, {name: 'aa', asc: false}],
});
- query
- .withContext({a: 'hello'})
- .exec();
+ assert.deepEqual(query.params, {
+ context: {},
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ limit: 32,
+ offset: 2,
+ model: 'partner',
+ sort: 'yop ASC, aa DESC',
+ }, "should have correct args");
});
- QUnit.test('search_read', function (assert) {
+ QUnit.test('search_read method', function (assert) {
assert.expect(1);
- var query = createQuery({
+ var query = rpc.buildQuery({
model: 'partner',
method: 'search_read',
- mockRPC: function (route, args) {
- assert.deepEqual(args, {
- context: {},
- domain: ['a', '=', 1],
- fields: ['name'],
- limit: 32,
- offset: 2,
- model: 'partner',
- sort: 'yop ASC, aa DESC',
- }, "should have correct args");
- },
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ limit: 32,
+ offset: 2,
+ orderBy: [{name: 'yop', asc: true}, {name: 'aa', asc: false}],
});
- query
- .withDomain(['a', '=', 1])
- .withFields(['name'])
- .withLimit(32)
- .withOffset(2)
- .orderBy([{name: 'yop', asc: true}, {name: 'aa', asc: false}])
- .exec();
+ assert.deepEqual(query.params, {
+ args: [['a', '=', 1], ['name'], 2, 32, 'yop ASC, aa DESC'],
+ kwargs: {},
+ method: 'search_read',
+ model: 'partner'
+ }, "should have correct args");
});
QUnit.test('read_group', function (assert) {
assert.expect(2);
- var query = createQuery({
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'read_group',
- mockRPC: function (route, args) {
- assert.deepEqual(args, {
- args: [],
- kwargs: {
- context: {abc: 'def'},
- domain: ['a', '=', 1],
- fields: ['name'],
- groupby: ['product_id'],
- lazy: true,
- orderby: false,
- },
- method: 'read_group',
- model: 'partner',
- }, "should have correct args");
- assert.equal(route, '/web/dataset/call_kw/partner/read_group',
- "should call correct route");
- },
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ groupBy: ['product_id'],
+ context: {abc: 'def'},
+ lazy: true,
});
- query
- .withDomain(['a', '=', 1])
- .withFields(['name'])
- .groupBy(['product_id'])
- .withContext({abc: 'def'})
- .lazy(true)
- .exec();
+
+ assert.deepEqual(query.params, {
+ args: [],
+ kwargs: {
+ context: {abc: 'def'},
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ groupby: ['product_id'],
+ lazy: true,
+ orderby: false,
+ },
+ method: 'read_group',
+ model: 'partner',
+ }, "should have correct args");
+ assert.equal(query.route, '/web/dataset/call_kw/partner/read_group',
+ "should call correct route");
});
QUnit.test('read_group with kwargs', function (assert) {
- assert.expect(2);
- var query = createQuery({
+ assert.expect(1);
+
+ var query = rpc.buildQuery({
model: 'partner',
method: 'read_group',
- mockRPC: function (route, args) {
- assert.deepEqual(args, {
- args: [],
- kwargs: {
- context: {abc: 'def'},
- domain: ['a', '=', 1],
- fields: ['name'],
- groupby: ['product_id'],
- lazy: true,
- orderby: false,
- },
- method: 'read_group',
- model: 'partner',
- }, "should have correct args");
- assert.equal(route, '/web/dataset/call_kw/partner/read_group',
- "should call correct route");
- },
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ groupBy: ['product_id'],
+ lazy: true,
+ kwargs: {context: {abc: 'def'}}
});
- query
- .withDomain(['a', '=', 1])
- .withFields(['name'])
- .groupBy(['product_id'])
- .kwargs({context: {abc: 'def'}})
- .lazy(true)
- .exec();
+
+ assert.deepEqual(query.params, {
+ args: [],
+ kwargs: {
+ context: {abc: 'def'},
+ domain: ['a', '=', 1],
+ fields: ['name'],
+ groupby: ['product_id'],
+ lazy: true,
+ orderby: false,
+ },
+ method: 'read_group',
+ model: 'partner',
+ }, "should have correct args");
});
QUnit.test('search_read with no domain, nor fields', function (assert) {
assert.expect(2);
- createQuery({
+ var query = rpc.buildQuery({
model: 'partner',
- method: 'search_read',
- mockRPC: function (route, args) {
- assert.deepEqual(args.domain, [], "should have [] as default domain");
- assert.strictEqual(args.fields, false, "should have false as default fields");
- },
- }).exec();
+ route: '/web/dataset/search_read',
+ });
+
+ assert.deepEqual(query.params.domain, [], "should have [] as default domain");
+ assert.strictEqual(query.params.fields, false, "should have false as default fields");
});
});
diff --git a/addons/web/static/test/fields/relational_fields_tests.js b/addons/web/static/test/fields/relational_fields_tests.js
index 93104bbd516..38287c2503d 100644
--- a/addons/web/static/test/fields/relational_fields_tests.js
+++ b/addons/web/static/test/fields/relational_fields_tests.js
@@ -2531,9 +2531,9 @@ QUnit.module('relational_fields', {
'<field name="timmy" invisible="1"/>' +
'</form>',
mockRPC: function (route, args) {
- if (route === '/web/dataset/search_read') {
+ if (args.method === 'search_read') {
count++;
- nb_fields_fetched = args.fields.length;
+ nb_fields_fetched = args.args[1].length;
}
return this._super.apply(this, arguments);
},
@@ -2687,7 +2687,7 @@ QUnit.module('relational_fields', {
'<field name="foo"/>' +
'</form>',
mockRPC: function (route, args) {
- if (route === '/web/dataset/search_read') {
+ if (args.method === 'search_read') {
rpcCount++;
}
return this._super.apply(this, arguments);
diff --git a/addons/web/static/test/helpers/mock_server.js b/addons/web/static/test/helpers/mock_server.js
index 247562dbb96..77107acfdaa 100644
--- a/addons/web/static/test/helpers/mock_server.js
+++ b/addons/web/static/test/helpers/mock_server.js
@@ -649,7 +649,7 @@ var MockServer = Class.extend({
return this._getRecords(model, args[0]).length;
},
/**
- * Simulate a 'search_read' operation
+ * Simulate a 'search_read' operation on a model
*
* @private
* @param {Object} args
@@ -661,7 +661,33 @@ var MockServer = Class.extend({
* @param {string[]} [args.sort]
* @returns {Object}
*/
- _mockSearchRead: function (args) {
+ _mockSearchRead: function (model, args, kwargs) {
+ var result = this._mockSearchReadController({
+ model: model,
+ domain: args[0],
+ fields: args[1],
+ offset: args[2],
+ limit: args[3],
+ sort: args[4],
+ context: kwargs.context,
+ });
+ return result.records;
+ },
+ /**
+ * Simulate a 'search_read' operation, from the controller point of view
+ *
+ * @private
+ * @private
+ * @param {Object} args
+ * @param {Array} args.domain
+ * @param {string} args.model
+ * @param {Array} [args.fields] defaults to the list of all fields
+ * @param {integer} [args.limit]
+ * @param {integer} [args.offset=0]
+ * @param {string[]} [args.sort]
+ * @returns {Object}
+ */
+ _mockSearchReadController: function (args) {
var self = this;
var records = this._getRecords(args.model, args.domain);
var fields = args.fields || _.keys(this.data[args.model].fields);
@@ -765,7 +791,7 @@ var MockServer = Class.extend({
return $.when(this._mockLoadAction(args));
case '/web/dataset/search_read':
- return $.when(this._mockSearchRead(args));
+ return $.when(this._mockSearchReadController(args));
}
if (route.indexOf('/web/image/') === 0) {
return $.when();
@@ -804,6 +830,9 @@ var MockServer = Class.extend({
case 'search_count':
return $.when(this._mockSearchCount(args.model, args.args));
+ case 'search_read':
+ return $.when(this._mockSearchRead(args.model, args.args, args.kwargs));
+
case 'unlink':
return $.when(this._mockUnlink(args.model, args.args));
diff --git a/addons/web/static/test/helpers/test_utils.js b/addons/web/static/test/helpers/test_utils.js
index 3d274996ebd..257a3f41a29 100644
--- a/addons/web/static/test/helpers/test_utils.js
+++ b/addons/web/static/test/helpers/test_utils.js
@@ -424,7 +424,7 @@ function removeSrcAttribute($el, widget) {
if (src[0] !== '#') {
$(this).attr('src', '#test:' + $(this).attr('src'));
if (widget) {
- widget._rpc(src).exec();
+ widget._rpc({route: src});
}
}
});