diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index d3cb227d7d1..d93aef6526c 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -227,6 +227,8 @@ def module_installed_bypass_session(dbname):
return sorted_modules
def module_boot(req):
+ return [m for m in req.config.server_wide_modules if m in openerpweb.addons_manifest]
+ # TODO the following will be enabled once we separate the module code and translation loading
serverside = []
dbside = []
for i in req.config.server_wide_modules:
@@ -531,6 +533,20 @@ def parse_context(context, session):
except ValueError:
return common.nonliterals.Context(session, context)
+
+def _local_web_translations(trans_file):
+ messages = []
+ try:
+ with open(trans_file) as t_file:
+ po = babel.messages.pofile.read_po(t_file)
+ except Exception:
+ return
+ for x in po:
+ if x.id and x.string and "openerp-web" in x.auto_comments:
+ messages.append({'id': x.id, 'string': x.string})
+ return messages
+
+
#----------------------------------------------------------
# OpenERP Web web Controllers
#----------------------------------------------------------
@@ -576,6 +592,7 @@ class Home(openerpweb.Controller):
def login(self, req, db, login, key):
return login_and_redirect(req, db, login, key)
+
class WebClient(openerpweb.Controller):
_cp_path = "/web/webclient"
@@ -658,41 +675,53 @@ class WebClient(openerpweb.Controller):
last_modified, checksum)
@openerpweb.jsonrequest
- def translations(self, req, mods, lang):
- lang_model = req.session.model('res.lang')
- ids = lang_model.search([("code", "=", lang)])
- if ids:
- lang_obj = lang_model.read(ids[0], ["direction", "date_format", "time_format",
- "grouping", "decimal_point", "thousands_sep"])
- else:
- lang_obj = None
+ def bootstrap_translations(self, req, mods):
+ """ Load local translations from *.po files, as a temporary solution
+ until we have established a valid session. This is meant only
+ for translating the login page and db management chrome, using
+ the browser's language. """
+ lang = req.httprequest.accept_languages.best or 'en'
+ # For performance reasons we only load a single translation, so for
+ # sub-languages (that should only be partially translated) we load the
+ # main language PO instead - that should be enough for the login screen.
+ if '-' in lang: # RFC2616 uses '-' separators for sublanguages
+ lang = lang.split('-')[0]
- if "_" in lang:
- separator = "_"
- else:
- separator = "@"
- langs = lang.split(separator)
- langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)]
-
- transs = {}
+ translations_per_module = {}
for addon_name in mods:
- transl = {"messages":[]}
- transs[addon_name] = transl
addons_path = openerpweb.addons_manifest[addon_name]['addons_path']
- for l in langs:
- f_name = os.path.join(addons_path, addon_name, "i18n", l + ".po")
- if not os.path.exists(f_name):
- continue
- try:
- with open(f_name) as t_file:
- po = babel.messages.pofile.read_po(t_file)
- except Exception:
- continue
- for x in po:
- if x.id and x.string and "openerp-web" in x.auto_comments:
- transl["messages"].append({'id': x.id, 'string': x.string})
- return {"modules": transs,
- "lang_parameters": lang_obj}
+ f_name = os.path.join(addons_path, addon_name, "i18n", lang + ".po")
+ if not os.path.exists(f_name):
+ continue
+ translations_per_module[addon_name] = {'messages': _local_web_translations(f_name)}
+
+ return {"modules": translations_per_module,
+ "lang_parameters": None}
+
+ @openerpweb.jsonrequest
+ def translations(self, req, mods, lang):
+ res_lang = req.session.model('res.lang')
+ ids = res_lang.search([("code", "=", lang)])
+ lang_params = None
+ if ids:
+ lang_params = res_lang.read(ids[0], ["direction", "date_format", "time_format",
+ "grouping", "decimal_point", "thousands_sep"])
+
+ # Regional languages (ll_CC) must inherit/override their parent lang (ll), but this is
+ # done server-side when the language is loaded, so we only need to load the user's lang.
+ ir_translation = req.session.model('ir.translation')
+ translations_per_module = {}
+ messages = ir_translation.search_read([('module','in',mods),('lang','=',lang),
+ ('comments','like','openerp-web'),('value','!=',False),
+ ('value','!=','')],
+ ['module','src','value','lang'], order='module')
+ for mod, msg_group in itertools.groupby(messages, key=operator.itemgetter('module')):
+ translations_per_module.setdefault(mod,{'messages':[]})
+ translations_per_module[mod]['messages'].extend({'id': m['src'],
+ 'string': m['value']} \
+ for m in msg_group)
+ return {"modules": translations_per_module,
+ "lang_parameters": lang_params}
@openerpweb.jsonrequest
def version_info(self, req):
@@ -769,7 +798,7 @@ class Database(openerpweb.Controller):
{'fileToken': int(token)}
)
except xmlrpclib.Fault, e:
- return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]])
+ return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]])
@openerpweb.httprequest
def restore(self, req, db_file, restore_pwd, new_db):
@@ -1180,8 +1209,8 @@ class DataSet(openerpweb.Controller):
def call_button(self, req, model, method, args, domain_id=None, context_id=None):
action = self.call_common(req, model, method, args, domain_id, context_id)
if isinstance(action, dict) and action.get('type') != '':
- return {'result': clean_action(req, action)}
- return {'result': False}
+ return clean_action(req, action)
+ return False
@openerpweb.jsonrequest
def exec_workflow(self, req, model, id, signal):
@@ -1593,7 +1622,7 @@ class Action(openerpweb.Controller):
action = req.session.model(action_type).read([action_id], False, ctx)
if action:
value = clean_action(req, action[0], do_not_eval)
- return {'result': value}
+ return value
@openerpweb.jsonrequest
def run(self, req, action_id):
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index aa9d5eab36f..14496fe3522 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -1103,9 +1103,8 @@
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
}
.openerp .oe_menu > li > .oe_active {
- background: rgba(0, 0, 0, 0.2);
+ background: rgba(0, 0, 0, 0.3);
text-shadow: black 0px 0px 3px;
- font-weight: bold;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) inset;
@@ -1198,7 +1197,7 @@
color: white;
padding: 2px 4px;
margin: 1px 6px 0 0;
- border: 1px solid lightGray;
+ border: 1px solid lightgrey;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
@@ -1223,7 +1222,7 @@
transform: scale(1.1);
}
.openerp .oe_secondary_submenu .oe_active {
- border-top: 1px solid lightGray;
+ border-top: 1px solid lightgrey;
border-bottom: 1px solid #dedede;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2);
@@ -1865,6 +1864,13 @@
margin: 0;
white-space: nowrap;
}
+.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li:first-child .searchview_extended_prop_or {
+ visibility: hidden;
+}
+.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced .searchview_extended_prop_or {
+ opacity: 0.5;
+ margin-left: -14px;
+}
.openerp .oe_searchview .oe_searchview_drawer .oe_opened h4:before {
content: "▾ ";
position: relative;
@@ -2117,7 +2123,7 @@
}
.openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span {
font-size: 80%;
- color: darkGreen;
+ color: darkgreen;
vertical-align: top;
position: relative;
top: -4px;
@@ -2206,16 +2212,12 @@
min-width: 60px;
color: #1f1f1f;
}
-.openerp .oe_form textarea {
- height: 32px;
-}
.openerp .oe_form input[readonly], .openerp .oe_form select[readonly], .openerp .oe_form textarea[readonly], .openerp .oe_form input[disabled], .openerp .oe_form select[disabled] {
background: #e5e5e5 !important;
color: #666666;
}
.openerp .oe_form textarea[disabled] {
border: none;
- border-left: 8px solid #eeeeee;
padding-left: 8px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
@@ -2224,6 +2226,9 @@
-webkit-border-radius: 0px;
border-radius: 0px;
}
+.openerp .oe_form textarea.oe_inline[disabled] {
+ border-left: 8px solid #eeeeee;
+}
.openerp .oe_form .oe_form_field_url button img {
vertical-align: top;
}
@@ -2241,7 +2246,7 @@
.openerp .oe_form .oe_datepicker_root {
display: inline-block;
}
-.openerp .oe_form .oe_form_required input, .openerp .oe_form .oe_form_required select, .openerp .oe_form .oe_form_required textarea {
+.openerp .oe_form .oe_form_required input:not([disabled]):not([readonly]), .openerp .oe_form .oe_form_required select:not([disabled]):not([readonly]), .openerp .oe_form .oe_form_required textarea:not([disabled]):not([readonly]) {
background-color: #d2d2ff !important;
}
.openerp .oe_form .oe_form_invalid input, .openerp .oe_form .oe_form_invalid select, .openerp .oe_form .oe_form_invalid textarea {
@@ -2279,7 +2284,7 @@
position: relative;
overflow: hidden;
}
-.openerp .oe_form .oe_form_field_html {
+.openerp .oe_form .oe_form_embedded_html {
position: relative;
width: 600px;
margin-left: 130px;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index c56c4d6a3e9..784f93d94cf 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -891,9 +891,8 @@ $sheet-max-width: 860px
color: white
@include box-shadow(0 1px 2px rgba(0,0,0,0.4) inset)
> .oe_active
- background: rgba(0,0,0,0.2)
+ background: rgba(0,0,0,0.30)
text-shadow: black 0px 0px 3px
- font-weight: bold
@include box-shadow(0 1px 2px rgba(0,0,0,0.4) inset)
.oe_user_menu
@@ -1482,6 +1481,11 @@ $sheet-max-width: 860px
list-style: none
margin: 0
white-space: nowrap
+ &:first-child .searchview_extended_prop_or
+ visibility: hidden
+ .searchview_extended_prop_or
+ opacity: 0.5
+ margin-left: -14px
.oe_opened
h4:before
content: "▾ "
@@ -1753,17 +1757,16 @@ $sheet-max-width: 860px
background: white
min-width: 60px
color: #1f1f1f
- textarea
- height: 32px
input[readonly], select[readonly], textarea[readonly], input[disabled], select[disabled]
background: #E5E5E5 !important
color: #666
textarea[disabled]
border: none
- border-left: 8px solid #eee
padding-left: 8px
@include box-shadow(none)
@include radius(0px)
+ textarea.oe_inline[disabled]
+ border-left: 8px solid #eee
.oe_form_field_url button img
vertical-align: top
.oe_form_field_date,
@@ -1776,8 +1779,8 @@ $sheet-max-width: 860px
display: none
.oe_datepicker_root
display: inline-block
- .oe_form_required
- input, select, textarea
+ .oe_form_required
+ input:not([disabled]):not([readonly]), select:not([disabled]):not([readonly]), textarea:not([disabled]):not([readonly])
background-color: #D2D2FF !important
.oe_form_invalid
input, select, textarea
@@ -1808,7 +1811,7 @@ $sheet-max-width: 860px
> div
position: relative
overflow: hidden
- .oe_form_field_html
+ .oe_form_embedded_html
position: relative
width: 600px
margin-left: 130px
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index bed4a159535..80693d26e46 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -146,8 +146,8 @@ instance.web.Dialog = instance.web.Widget.extend({
this.$buttons = $('
');
this.$el.dialog("widget").append(this.$buttons);
}
- var res = this.start();
this.dialog_inited = true;
+ var res = this.start();
return res;
},
close: function() {
@@ -392,7 +392,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
do_create: function(form) {
var self = this;
var fields = $(form).serializeArray();
- self.rpc("/web/database/create", {'fields': fields}, function(result) {
+ self.rpc("/web/database/create", {'fields': fields}).then(function(result) {
var form_obj = self.to_object(fields);
var client_action = {
type: 'ir.actions.client',
@@ -418,7 +418,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
if (!db || !confirm("Do you really want to delete the database: " + db + " ?")) {
return;
}
- self.rpc("/web/database/drop", {'fields': fields}, function(result) {
+ self.rpc("/web/database/drop", {'fields': fields}).then(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -481,7 +481,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
var self = this;
self.rpc("/web/database/change_password", {
'fields': $(form).serializeArray()
- }, function(result) {
+ }).then(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -660,7 +660,7 @@ instance.web.ChangePassword = instance.web.Widget.extend({
submitHandler: function (form) {
self.rpc("/web/session/change_password",{
'fields': $(form).serializeArray()
- }, function(result) {
+ }).then(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -886,8 +886,8 @@ instance.web.UserMenu = instance.web.Widget.extend({
var self = this;
if (!this.getParent().has_uncommitted_changes()) {
self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }, function(result) {
- result.result.res_id = instance.session.uid;
- self.getParent().action_manager.do_action(result.result);
+ result.res_id = instance.session.uid;
+ self.getParent().action_manager.do_action(result);
});
}
},
@@ -1121,7 +1121,7 @@ instance.web.WebClient = instance.web.Client.extend({
var self = this;
return this.rpc("/web/action/load", { action_id: options.action_id })
.pipe(function (result) {
- var action = result.result;
+ var action = result;
if (options.needaction) {
action.context.search_default_needaction_pending = true;
}
@@ -1165,8 +1165,8 @@ instance.web.EmbeddedClient = instance.web.Client.extend({
var self = this;
return $.when(this._super()).pipe(function() {
return instance.session.session_authenticate(self.dbname, self.login, self.key, true).pipe(function() {
- return self.rpc("/web/action/load", { action_id: self.action_id }, function(result) {
- var action = result.result;
+ return self.rpc("/web/action/load", { action_id: self.action_id }).then(function(result) {
+ var action = result;
action.flags = _.extend({
//views_switcher : false,
search_view : false,
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index 62ac48f0c61..ff193605033 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -820,9 +820,10 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
* the action manager can be found amongst the ancestors of the current widget.
* If that's not the case this method will simply return `false`.
*/
- do_action: function(action, on_finished) {
- if (this.getParent()) {
- return this.getParent().do_action(action, on_finished);
+ do_action: function() {
+ var parent = this.getParent();
+ if (parent) {
+ return parent.do_action.apply(parent, arguments);
}
return false;
},
@@ -841,7 +842,7 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
rpc: function(url, data, success, error) {
var def = $.Deferred().then(success, error);
var self = this;
- instance.session.rpc(url, data). then(function() {
+ instance.session.rpc(url, data).then(function() {
if (!self.isDestroyed())
def.resolve.apply(def, arguments);
}, function() {
@@ -1299,7 +1300,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
* @param {Function} error_callback function to execute on RPC call failure
* @returns {jQuery.Deferred} jquery-provided ajax deferred
*/
- rpc: function(url, params, success_callback, error_callback) {
+ rpc: function(url, params) {
var self = this;
// url can be an $.ajax option object
if (_.isString(url)) {
@@ -1316,8 +1317,6 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
};
var deferred = $.Deferred();
this.trigger('request', url, payload);
- var aborter = params.aborter;
- delete params.aborter;
var request = this.rpc_function(url, payload).then(
function (response, textStatus, jqXHR) {
self.trigger('response', response);
@@ -1341,16 +1340,6 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
};
deferred.reject(error, $.Event());
});
- if (aborter) {
- aborter.abort_last = function () {
- if (!(request.isResolved() || request.isRejected())) {
- deferred.fail(function (error, event) {
- event.preventDefault();
- });
- request.abort();
- }
- };
- }
// Allow deferred user to disable on_rpc_error in fail
deferred.fail(function() {
deferred.fail(function(error, event) {
@@ -1358,7 +1347,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
self.on_rpc_error(error, event);
}
});
- }).then(success_callback, error_callback).promise();
+ });
return deferred;
},
/**
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index ea160d6faee..1f1112df2f2 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -19,9 +19,9 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
this.name = instance._session_id;
this.qweb_mutex = new $.Mutex();
},
- rpc: function(url, params, success_callback, error_callback) {
+ rpc: function(url, params) {
params.session_id = this.session_id;
- return this._super(url, params, success_callback, error_callback);
+ return this._super(url, params);
},
/**
* Setup a sessionm
@@ -57,7 +57,12 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
if(self.session_is_valid()) {
return deferred.pipe(function() { return self.load_modules(); });
}
- return deferred;
+ return $.when(
+ deferred,
+ self.rpc('/web/webclient/bootstrap_translations', {mods: instance._modules}).pipe(function(trans) {
+ instance.web._t.database.set_bundle(trans);
+ })
+ );
});
},
/**
@@ -537,13 +542,9 @@ instance.web.qweb.preprocess_node = function() {
if (translation && translation.value === 'off') {
return;
}
- var ts = _.str.trim(this.node.data);
- if (ts.length === 0) {
- return;
- }
- var tr = instance.web._t(ts);
- if (tr !== ts) {
- this.node.data = tr;
+ var match = /^(\s*)(.+?)(\s*)$/.exec(this.node.data);
+ if (match) {
+ this.node.data = match[1] + instance.web._t(match[2]) + match[3];
}
break;
case 1:
@@ -600,8 +601,7 @@ var messages_by_seconds = function() {
[120, _t("Don't leave yet,
it's still loading...")],
[300, _t("You may not believe it,
but the application is actually loading...")],
[420, _t("Take a minute to get a coffee,
because it's loading...")],
- [600, _t("It's loading...
By the way, did you tried the kitten mode?")],
- [3600, _t("Maybe you should consider pressing F5...")],
+ [3600, _t("Maybe you should consider reloading the application by pressing F5...")],
];
};
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index 2b82e618203..220d42737da 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -586,26 +586,8 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @param {Function} error_callback
* @returns {$.Deferred}
*/
- call: function (method, args, callback, error_callback) {
- return this._model.call(method, args).then(callback, error_callback);
- },
- /**
- * Calls an arbitrary method, with more crazy
- *
- * @param {String} method
- * @param {Array} [args]
- * @param {Number} [domain_index] index of a domain to evaluate in the args array
- * @param {Number} [context_index] index of a context to evaluate in the args array
- * @returns {$.Deferred}
- */
- call_and_eval: function (method, args, domain_index, context_index) {
- return instance.session.rpc('/web/dataset/call', {
- model: this.model,
- method: method,
- domain_id: domain_index == undefined ? null : domain_index,
- context_id: context_index == undefined ? null : context_index,
- args: args || []
- });
+ call: function (method, args) {
+ return this._model.call(method, args);
},
/**
* Calls a button method, usually returning some sort of action
diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js
index 29aea6362f7..b4beb4c3a58 100644
--- a/addons/web/static/src/js/data_export.js
+++ b/addons/web/static/src/js/data_export.js
@@ -5,7 +5,15 @@ instance.web.DataExport = instance.web.Dialog.extend({
template: 'ExportTreeView',
dialog_title: {toString: function () { return _t("Export Data"); }},
init: function(parent, dataset) {
- this._super(parent);
+ var self = this;
+ options = {
+ buttons : [
+ {text: _t("Close"), click: function() { self.close(); }},
+ {text: _t("Export To File"), click: function() { self.on_click_export_data(); }}
+ ],
+ close: function(event, ui){ self.close();}
+ }
+ this._super(parent, options);
this.records = {};
this.dataset = dataset;
this.exports = new instance.web.DataSetSearch(
@@ -14,13 +22,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
start: function() {
var self = this;
this._super.apply(this, arguments);
- this.open({
- buttons : [
- {text: _t("Close"), click: function() { self.close(); }},
- {text: _t("Export To File"), click: function() { self.on_click_export_data(); }}
- ],
- close: function(event, ui){ self.close();}
- });
+ this.open();
self.$el.removeClass('ui-dialog-content ui-widget-content');
self.$el.find('#add_field').click(function() {
if ($('#field-tree-structure tr.ui-selected')) {
@@ -49,7 +51,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
self.rpc("/web/export/get_fields", {
model: self.dataset.model,
import_compat: Boolean(import_comp)
- }, function (records) {
+ }).then(function (records) {
got_fields.resolve();
self.on_show_data(records);
});
@@ -57,7 +59,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
return $.when(
got_fields,
- this.rpc('/web/export/formats', {}, this.do_setup_export_formats),
+ this.rpc('/web/export/formats', {}).then(this.do_setup_export_formats),
this.show_exports_list());
},
do_setup_export_formats: function (formats) {
@@ -91,7 +93,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
self.$el.find('#fields_list option').remove();
var export_id = self.$el.find('#saved_export_list option:selected').val();
if (export_id) {
- self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}, self.do_load_export_field);
+ self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}).then(self.do_load_export_field);
}
});
self.$el.find('#delete_export_list').click(function() {
@@ -181,7 +183,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
import_compat: Boolean(import_comp),
parent_field_type : record['field_type'],
exclude: exclude_fields
- }, function(results) {
+ }).then(function(results) {
record.loaded = true;
self.on_show_data(results, record.id);
});
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 01bc0c76c87..a5e1aaeb3ae 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1494,7 +1494,7 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
return $.when(facet_from(this, value));
}
assert(value.length <= 1,
- _("M2O search fields do not currently handle multiple default values"));
+ _t("M2O search fields do not currently handle multiple default values"));
// there are many cases of {search_default_$m2ofield: [id]}, need
// to handle this as if it were a single value.
value = value[0];
@@ -1578,7 +1578,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
$filter.unbind('click').click(function () {
self.view.query.reset([{
- category: _("Custom Filter"),
+ category: _t("Custom Filter"),
icon: 'M',
field: {
get_context: function () { return filter.context; },
@@ -1693,7 +1693,7 @@ instance.web.search.Advanced = instance.web.search.Input.extend({
});
return $.when(
this._super(),
- this.rpc("/web/searchview/fields_get", {model: this.view.model}, function(data) {
+ this.rpc("/web/searchview/fields_get", {model: this.view.model}).then(function(data) {
self.fields = _.extend({
id: { string: 'ID', type: 'id' }
}, data.fields);
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index bf6b869482b..b41039361c0 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -30,7 +30,7 @@ instance.web.form.FieldManagerMixin = {
/**
* Must return the asked field as in fields_get.
*/
- get_field: function(field_name) {},
+ get_field_desc: function(field_name) {},
/**
* Returns the current value of a field present in the view. See the get_value() method
* method in FieldInterface for further information.
@@ -44,6 +44,21 @@ instance.web.form.FieldManagerMixin = {
@return (Deferred) Is resolved after all the values are setted.
*/
set_values: function(values) {},
+ /**
+ Computes an OpenERP domain.
+
+ @param (list) expression An OpenERP domain.
+ @return (boolean) The computed value of the domain.
+ */
+ compute_domain: function(expression) {},
+ /**
+ Builds an evaluation context for the resolution of the fields' contexts. Please note
+ the field are only supposed to use this context to evualuate their own, they should not
+ extend it.
+
+ @return (CompoundContext) An OpenERP context.
+ */
+ build_eval_context: function() {},
};
instance.web.views.add('form', 'instance.web.FormView');
@@ -1085,7 +1100,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
field.on('focused', null, this.proxy('widgetFocused'))
.on('blurred', null, this.proxy('widgetBlurred'));
- if (this.get_field(name).translate) {
+ if (this.get_field_desc(name).translate) {
this.translatable_fields.push(field);
}
field.on('changed_value', this, function() {
@@ -1103,12 +1118,34 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
}
});
},
- get_field: function(field_name) {
+ get_field_desc: function(field_name) {
return this.fields_view.fields[field_name];
},
get_field_value: function(field_name) {
return this.fields[field_name].get_value();
},
+ compute_domain: function(expression) {
+ return instance.web.form.compute_domain(expression, this.fields);
+ },
+ _build_view_fields_values: function(blacklist) {
+ var a_dataset = this.dataset;
+ var fields_values = this.get_fields_values(blacklist);
+ var active_id = a_dataset.ids[a_dataset.index];
+ _.extend(fields_values, {
+ active_id: active_id || false,
+ active_ids: active_id ? [active_id] : [],
+ active_model: a_dataset.model,
+ parent: {}
+ });
+ if (a_dataset.parent_view) {
+ fields_values.parent = a_dataset.parent_view.get_fields_values([a_dataset.child_name]);
+ }
+ return fields_values;
+ },
+ build_eval_context: function(blacklist) {
+ var a_dataset = this.dataset;
+ return new instance.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values(blacklist));
+ },
});
/**
@@ -1175,7 +1212,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
this.$form.appendTo(this.$target);
- _.each(this.fields_to_init, function($elem) {
+ var ws = _.map(this.fields_to_init, function($elem) {
var name = $elem.attr("name");
if (!self.fvg.fields[name]) {
throw new Error("Field '" + name + "' specified in view could not be found.");
@@ -1191,7 +1228,10 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
}
self.alter_field(w);
self.view.register_field(w, $elem.attr("name"));
- w.replace($elem);
+ return [w, $elem];
+ });
+ _.each(ws, function(w) {
+ w[0].replace(w[1]);
});
_.each(this.tags_to_init, function($elem) {
var tag_name = $elem[0].tagName.toLowerCase();
@@ -1528,6 +1568,52 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
},
});
+/**
+ Welcome.
+
+ If you read this documentation, it probably means that you were asked to use a form view widget outside of
+ a form view. Before going further, you must understand that those fields were never really created for
+ that usage. Don't think that this class will hold the answer to all your problems, at best it will allow
+ you to hack the system with more style.
+*/
+instance.web.form.DefaultFieldManager = instance.web.Widget.extend({
+ init: function(parent, eval_context) {
+ this._super(parent);
+ this.field_descs = {};
+ this.eval_context = eval_context || {};
+ this.set({
+ display_invalid_fields: false,
+ actual_mode: 'create',
+ });
+ },
+ get_field_desc: function(field_name) {
+ if (this.field_descs[field_name] === undefined) {
+ this.field_descs[field_name] = {
+ string: field_name,
+ };
+ }
+ return this.field_descs[field_name];
+ },
+ extend_field_desc: function(fields) {
+ var self = this;
+ _.each(fields, function(v, k) {
+ _.extend(self.get_field_desc(k), v);
+ });
+ },
+ get_field_value: function(field_name) {
+ return false;
+ },
+ set_values: function(values) {
+ // nothing
+ },
+ compute_domain: function(expression) {
+ return instance.web.form.compute_domain(expression, {});
+ },
+ build_eval_context: function() {
+ return new instance.web.CompoundContext(this.eval_context);
+ },
+});
+
instance.web.form.FormDialog = instance.web.Dialog.extend({
init: function(parent, options, view_id, dataset) {
this._super(parent, options);
@@ -1641,9 +1727,7 @@ instance.web.form.InvisibilityChangerMixin = {
this._ic_invisible_modifier = invisible_domain;
this._ic_field_manager.on("view_content_has_changed", this, function() {
var result = self._ic_invisible_modifier === undefined ? false :
- instance.web.form.compute_domain(
- self._ic_invisible_modifier,
- self._ic_field_manager.fields);
+ self._ic_field_manager.compute_domain(self._ic_invisible_modifier);
self.set({"invisible": result});
});
this.set({invisible: this._ic_invisible_modifier === true, force_invisible: false});
@@ -1694,19 +1778,22 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
*/
init: function(field_manager, node) {
this._super(field_manager);
- this.view = field_manager;
this.field_manager = field_manager;
+ if (this.field_manager instanceof instance.web.FormView)
+ this.view = this.field_manager;
this.node = node;
this.modifiers = JSON.parse(this.node.attrs.modifiers || '{}');
instance.web.form.InvisibilityChangerMixin.init.call(this, this.field_manager, this.modifiers.invisible);
this.field_manager.on("view_content_has_changed", this, this.process_modifiers);
- this.set({required: this.modifiers['required'] === true});
+ this.set({
+ required: false,
+ readonly: false,
+ });
// some events to make the property "effective_readonly" sync automatically with "readonly" and
// "mode" on field_manager
var self = this;
- this.set({"readonly": this.modifiers['readonly'] === true});
var test_effective_readonly = function() {
self.set({"effective_readonly": self.get("readonly") || self.field_manager.get("actual_mode") === "view"});
};
@@ -1715,6 +1802,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
test_effective_readonly.call(this);
},
renderElement: function() {
+ this.process_modifiers();
this._super();
this.$el.addClass(this.node.attrs["class"] || "");
},
@@ -1737,12 +1825,11 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
});
},
process_modifiers: function() {
- var compute_domain = instance.web.form.compute_domain;
var to_set = {};
for (var a in this.modifiers) {
if (!this.modifiers.hasOwnProperty(a)) { continue; }
if (!_.include(["invisible"], a)) {
- var val = compute_domain(this.modifiers[a], this.view.fields);
+ var val = this.field_manager.compute_domain(this.modifiers[a]);
to_set[a] = val;
}
}
@@ -1771,25 +1858,6 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
}, options || {});
$(trigger).tipsy(options);
},
- _build_view_fields_values: function(blacklist) {
- var a_dataset = this.view.dataset;
- var fields_values = this.view.get_fields_values(blacklist);
- var active_id = a_dataset.ids[a_dataset.index];
- _.extend(fields_values, {
- active_id: active_id || false,
- active_ids: active_id ? [active_id] : [],
- active_model: a_dataset.model,
- parent: {}
- });
- if (a_dataset.parent_view) {
- fields_values.parent = a_dataset.parent_view.get_fields_values([a_dataset.child_name]);
- }
- return fields_values;
- },
- _build_eval_context: function(blacklist) {
- var a_dataset = this.view.dataset;
- return new instance.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values(blacklist));
- },
/**
* Builds a new context usable for operations related to fields by merging
* the fields'context with the action's context.
@@ -1802,7 +1870,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
}
if (v_context.__ref || true) { //TODO: remove true
- var fields_values = this._build_eval_context(blacklist);
+ var fields_values = this.field_manager.build_eval_context(blacklist);
v_context = new instance.web.CompoundContext(v_context).set_eval_context(fields_values);
}
return v_context;
@@ -1813,7 +1881,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
// if there is a domain on the node, overrides the model's domain
var final_domain = n_domain !== null ? n_domain : f_domain;
if (!(final_domain instanceof Array) || true) { //TODO: remove true
- var fields_values = this._build_eval_context();
+ var fields_values = this.field_manager.build_eval_context();
final_domain = new instance.web.CompoundDomain(final_domain).set_eval_context(fields_values);
}
return final_domain;
@@ -2001,7 +2069,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
var self = this
this._super(field_manager, node);
this.name = this.node.attrs.name;
- this.field = this.field_manager.get_field(this.name);
+ this.field = this.field_manager.get_field_desc(this.name);
this.widget = this.node.attrs.widget;
this.string = this.node.attrs.string || this.field.string || this.name;
this.options = JSON.parse(this.node.attrs.options || '{}');
@@ -2015,11 +2083,11 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
renderElement: function() {
var self = this;
this._super();
- if (this.field.translate) {
+ if (this.field.translate && this.view) {
this.$el.addClass('oe_form_field_translatable');
this.$el.find('.oe_field_translate').click(this.on_translate);
}
- this.$label = this.view.$el.find('label[for=' + this.id_for_label + ']');
+ this.$label = this.view ? this.view.$el.find('label[for=' + this.id_for_label + ']') : $();
if (instance.session.debug) {
this.do_attach_tooltip(this, this.$label[0] || this.$el);
this.$label.off('dblclick').on('dblclick', function() {
@@ -2081,7 +2149,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
var self = this;
var trans = new instance.web.DataSet(this, 'ir.translation');
return trans.call_button('translate_fields', [this.view.dataset.model, this.view.datarecord.id, this.name, this.view.dataset.get_context()]).then(function(r) {
- self.do_action(r.result);
+ self.do_action(r);
});
},
});
@@ -2884,7 +2952,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
self.focus();
return;
}
- var pop = new instance.web.form.FormOpenPopup(self.view);
+ var pop = new instance.web.form.FormOpenPopup(self);
pop.show_element(
self.field.relation,
self.get("value"),
@@ -3479,7 +3547,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
}
var self = this;
var id = self.o2m.dataset.index !== null ? self.o2m.dataset.ids[self.o2m.dataset.index] : null;
- var pop = new instance.web.form.FormOpenPopup(self.o2m.view);
+ var pop = new instance.web.form.FormOpenPopup(this);
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(), {
title: _t("Open: ") + self.o2m.string,
create_function: function(data) {
@@ -3595,7 +3663,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
},
do_activate_record: function(index, id) {
var self = this;
- var pop = new instance.web.form.FormOpenPopup(self.o2m.view);
+ var pop = new instance.web.form.FormOpenPopup(self);
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(), {
title: _t("Open: ") + self.o2m.string,
write_function: function(id, data) {
@@ -3623,7 +3691,10 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
var parent_form = this.o2m.view;
var self = this;
this.ensure_saved().pipe(function () {
- return parent_form.do_save();
+ if (parent_form)
+ return parent_form.do_save();
+ else
+ return $.when();
}).then(function () {
self.handle_button(name, id, callback);
});
@@ -3879,7 +3950,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
},
render_value: function() {
var self = this;
- var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.view.dataset.get_context());
+ var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.build_context());
var values = self.get("value")
var handle_names = function(data) {
var indexed = {};
@@ -3914,6 +3985,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
disable_utility_classes: true,
init: function(field_manager, node) {
this._super(field_manager, node);
+ this.set({"value": []});
this.is_loaded = $.Deferred();
this.initial_is_loaded = this.is_loaded;
this.is_setted = $.Deferred();
@@ -4149,7 +4221,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
});
} else {
var id = self.dataset.ids[self.dataset.index];
- var pop = new instance.web.form.FormOpenPopup(self.view);
+ var pop = new instance.web.form.FormOpenPopup(this);
pop.show_element(self.field.relation, id, self.build_context(), {
title: _t("Open: ") + self.string,
write_function: function(id, data, options) {
@@ -4282,7 +4354,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
this.dataset.create_function = function(data, sup) {
var fct = self.options.create_function || sup;
return fct.call(this, data).then(function(r) {
- self.created_elements.push(r.result);
+ self.created_elements.push(r);
});
};
this.dataset.write_function = function(id, data, options, sup) {
@@ -4417,7 +4489,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
self.rpc('/web/session/eval_domain_and_context', {
domains: [],
contexts: [this.context]
- }, function (results) {
+ }).then(function (results) {
var search_defaults = {};
_.each(results.context, function (value_, key) {
var match = /^search_default_(.*)$/.exec(key);
@@ -4485,7 +4557,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
domains: domains || [],
contexts: contexts || [],
group_by_seq: groupbys || []
- }, function (results) {
+ }).then(function (results) {
self.view_list.do_search(results.domain, results.context, results.group_by);
});
},
@@ -4540,22 +4612,28 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
}
},
destroy_content: function() {
- if (this.selection) {
- this.selection.destroy();
- this.selection = undefined;
- }
- if (this.m2o) {
- this.m2o.destroy();
- this.m2o = undefined;
+ if (this.fm) {
+ this.fm.destroy();
}
},
initialize_content: function() {
var self = this;
- this.selection = new instance.web.form.FieldSelection(this, { attrs: {
+ var fm = new instance.web.form.DefaultFieldManager(this);
+ this.fm = fm;
+ fm.extend_field_desc({
+ "selection": {
+ selection: this.field_manager.get_field_desc(this.name).selection,
+ type: "selection",
+ },
+ "m2o": {
+ relation: null,
+ type: "many2one",
+ },
+ });
+ this.selection = new instance.web.form.FieldSelection(fm, { attrs: {
name: 'selection',
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
}});
- this.selection.view = this.view;
this.selection.on("change:value", this, this.on_selection_changed);
this.selection.setElement(this.$(".oe_form_view_reference_selection"));
this.selection.renderElement();
@@ -4564,11 +4642,10 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
.on('focused', null, function () {self.trigger('focused')})
.on('blurred', null, function () {self.trigger('blurred')});
- this.m2o = new instance.web.form.FieldMany2One(this, { attrs: {
+ this.m2o = new instance.web.form.FieldMany2One(fm, { attrs: {
name: 'm2o',
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
}});
- this.m2o.view = this.view;
this.m2o.on("change:value", this, this.data_changed);
this.m2o.setElement(this.$(".oe_form_view_reference_m2o"));
this.m2o.renderElement();
@@ -4608,20 +4685,6 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
this.set({'value': false});
}
},
- get_field: function(name) {
- if (name === "selection") {
- return {
- selection: this.view.fields_view.fields[this.name].selection,
- type: "selection",
- };
- } else if (name === "m2o") {
- return {
- relation: null,
- type: "many2one",
- };
- }
- throw Exception("Should not happen");
- },
});
instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
@@ -4709,9 +4772,10 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
},
set_filename: function(value) {
var filename = this.node.attrs.filename;
- if (this.view.fields[filename]) {
- this.view.fields[filename].set_value(value);
- this.view.fields[filename].on_ui_change();
+ if (filename) {
+ var tmp = {};
+ tmp[filename] = value;
+ this.field_manager.set_values(tmp);
}
},
on_clear: function() {
@@ -4753,7 +4817,9 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
} else {
this.$el.find('a').show(!!this.get('value'));
if (this.get('value')) {
- var show_value = _t("Download") + " " + (this.view.datarecord[this.node.attrs.filename] || '');
+ var show_value = _t("Download")
+ if (this.view)
+ show_value += " " + (this.view.datarecord[this.node.attrs.filename] || '');
this.$el.find('a').text(show_value);
}
}
@@ -4765,12 +4831,6 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
this.$el.find('input').eq(0).val(show_value);
this.set_filename(name);
},
- set_filename: function(value_) {
- var filename = this.node.attrs.filename;
- if (this.view.fields[filename]) {
- this.view.fields[filename].set({value: value_});
- }
- },
on_clear: function() {
this._super.apply(this, arguments);
this.$el.find('input').eq(0).val('');
@@ -4819,10 +4879,12 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
this.set({'value': file_base64});
this.binary_value = true;
this.render_value();
+ this.set_filename(name);
},
on_clear: function() {
this._super.apply(this, arguments);
this.render_value();
+ this.set_filename('');
}
});
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index fd34ffddb7b..7457ca5ef67 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -482,7 +482,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
view_type: "tree",
context: this.dataset.get_context(context),
toolbar: !!this.options.$sidebar
- }, callback);
+ }).then(callback);
}
},
/**
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index e0493a446e2..05760420ba8 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -45,7 +45,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
view_type: "tree",
toolbar: this.view_manager ? !!this.view_manager.sidebar : false,
context: this.dataset.get_context()
- }, this.on_loaded);
+ }).then(this.on_loaded);
},
/**
* Returns the list of fields needed to correctly read objects.
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 2fff0e7b683..21f539fed1b 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -99,6 +99,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.select_breadcrumb(index, subindex);
},
select_breadcrumb: function(index, subindex) {
+ var next_item = this.breadcrumbs[index + 1];
+ if (next_item && next_item.on_reverse_breadcrumb) {
+ next_item.on_reverse_breadcrumb(this.breadcrumbs[index].widget);
+ }
for (var i = this.breadcrumbs.length - 1; i >= 0; i--) {
if (i > index) {
if (this.remove_breadcrumb(i) === false) {
@@ -220,14 +224,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
});
},
- do_action: function(action, on_close, clear_breadcrumbs) {
+ do_action: function(action, on_close, clear_breadcrumbs, on_reverse_breadcrumb) {
if (_.isString(action) && instance.web.client_actions.contains(action)) {
var action_client = { type: "ir.actions.client", tag: action };
- return this.do_action(action_client, on_close, clear_breadcrumbs);
+ return this.do_action(action_client, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
} else if (_.isNumber(action) || _.isString(action)) {
var self = this;
return self.rpc("/web/action/load", { action_id: action }).pipe(function(result) {
- return self.do_action(result.result, on_close, clear_breadcrumbs);
+ return self.do_action(result, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
});
}
if (!action.type) {
@@ -249,7 +253,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
console.error("Action manager can't handle action of type " + action.type, action);
return $.Deferred().reject();
}
- return this[type](action, on_close, clear_breadcrumbs);
+ return this[type](action, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
},
null_action: function() {
this.dialog_stop();
@@ -300,24 +304,24 @@ instance.web.ActionManager = instance.web.Widget.extend({
return this.inner_widget.appendTo(this.$el);
}
},
- ir_actions_act_window: function (action, on_close, clear_breadcrumbs) {
+ ir_actions_act_window: function (action, on_close, clear_breadcrumbs, on_reverse_breadcrumb) {
var self = this;
return this.ir_actions_common({
widget: function () { return new instance.web.ViewManagerAction(self, action); },
action: action,
klass: 'oe_act_window',
- post_process: function (widget) { widget.add_breadcrumb(); }
- }, on_close, clear_breadcrumbs);
+ post_process: function (widget) { widget.add_breadcrumb(on_reverse_breadcrumb); }
+ }, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
},
- ir_actions_client: function (action, on_close, clear_breadcrumbs) {
+ ir_actions_client: function (action, on_close, clear_breadcrumbs, on_reverse_breadcrumb) {
var self = this;
var ClientWidget = instance.web.client_actions.get_object(action.tag);
if (!(ClientWidget.prototype instanceof instance.web.Widget)) {
var next;
if (next = ClientWidget(this, action.params)) {
- return this.do_action(next, on_close, clear_breadcrumbs);
+ return this.do_action(next, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
}
return $.when();
}
@@ -329,13 +333,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
post_process: function(widget) {
self.push_breadcrumb({
widget: widget,
- title: action.name
+ title: action.name,
+ on_reverse_breadcrumb: on_reverse_breadcrumb,
});
if (action.tag !== 'reload') {
self.do_push_state({});
}
}
- }, on_close, clear_breadcrumbs);
+ }, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
},
ir_actions_act_window_close: function (action, on_closed) {
if (!this.dialog && on_closed) {
@@ -343,13 +348,13 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
this.dialog_stop();
},
- ir_actions_server: function (action, on_closed, clear_breadcrumbs) {
+ ir_actions_server: function (action, on_closed, clear_breadcrumbs, on_reverse_breadcrumb) {
var self = this;
this.rpc('/web/action/run', {
action_id: action.id,
context: action.context || {}
}).then(function (action) {
- self.do_action(action, on_closed, clear_breadcrumbs)
+ self.do_action(action, on_closed, clear_breadcrumbs, on_reverse_breadcrumb)
});
},
ir_actions_report_xml: function(action, on_closed) {
@@ -544,7 +549,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
set_title: function(title) {
this.$el.find('.oe_view_title_text:first').text(title);
},
- add_breadcrumb: function() {
+ add_breadcrumb: function(on_reverse_breadcrumb) {
var self = this;
var views = [this.active_view || this.views_src[0].view_type];
this.on_mode_switch.add(function(mode) {
@@ -589,7 +594,8 @@ instance.web.ViewManager = instance.web.Widget.extend({
titles.pop();
}
return titles;
- }
+ },
+ on_reverse_breadcrumb: on_reverse_breadcrumb,
});
},
/**
@@ -648,7 +654,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
domains: [this.action.domain || []].concat(domains || []),
contexts: [action_context].concat(contexts || []),
group_by_seq: groupbys || []
- }, function (results) {
+ }).then(function (results) {
self.dataset._model = new instance.web.Model(
self.dataset.model, results.context, results.domain);
var groupby = results.group_by.length
@@ -807,13 +813,11 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
});
break;
case 'fields':
- this.dataset.call_and_eval(
- 'fields_get', [false, {}], null, 1).then(function (fields) {
+ this.dataset.call('fields_get', [false, {}]).then(function (fields) {
var $root = $('');
_(fields).each(function (attributes, name) {
$root.append($('- ').append($('
').text(name)));
- var $attrs = $('').appendTo(
- $('- ').appendTo($root));
+ var $attrs = $('
').appendTo($('- ').appendTo($root));
_(attributes).each(function (def, name) {
if (def instanceof Object) {
def = JSON.stringify(def);
@@ -1054,7 +1058,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
self.rpc("/web/action/load", {
action_id: item.action.id,
context: additional_context
- }, function(result) {
+ }).then(function(result) {
result.result.context = _.extend(result.result.context || {},
additional_context);
result.result.flags = result.result.flags || {};
@@ -1190,7 +1194,7 @@ instance.web.View = instance.web.Widget.extend({
var context = new instance.web.CompoundContext(dataset.get_context(), action_data.context || {});
var handler = function (r) {
- var action = r.result;
+ var action = r;
if (action && action.constructor == Object) {
var ncontext = new instance.web.CompoundContext(context);
if (record_id) {
@@ -1217,7 +1221,7 @@ instance.web.View = instance.web.Widget.extend({
};
if (action_data.special) {
- return handler({result: {"type":"ir.actions.act_window_close"}});
+ return handler({"type":"ir.actions.act_window_close"});
} else if (action_data.type=="object") {
var args = [[record_id]], additional_args = [];
if (action_data.args) {
@@ -1233,7 +1237,7 @@ instance.web.View = instance.web.Widget.extend({
args.push(context);
return dataset.call_button(action_data.name, args).then(handler);
} else if (action_data.type=="action") {
- return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}, handler);
+ return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}).then(handler);
} else {
return dataset.exec_workflow(record_id, action_data.name).then(handler);
}
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index f4c5de237ac..fa6dbd3a27c 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -2,12 +2,6 @@
-
-
-
-
@@ -413,7 +407,7 @@
@@ -1128,7 +1122,7 @@
|
- width: 83px;
+ width: 83px;
|