summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js
diff options
context:
space:
mode:
authorvta vta@openerp.com <>2012-11-08 14:20:49 +0100
committervta vta@openerp.com <>2012-11-08 14:20:49 +0100
commit2576cd9d5cdf34c3233a0cdae7d8439bce85de1c (patch)
tree08b44ce4e44d01018a32097acb902ee1eb2bb2fa /addons/web/static/src/js
parent6a229f4385db0a2961116fcf599502288089cb38 (diff)
parentd0400362d636cbe2677c29a9196d63f419b72bff (diff)
[MERGE] Latest trunk.
bzr revid: vta@openerp.com-20121108132049-7ape10oz1gvz4vi8
Diffstat (limited to 'addons/web/static/src/js')
-rw-r--r--addons/web/static/src/js/chrome.js90
-rw-r--r--addons/web/static/src/js/corelib.js20
-rw-r--r--addons/web/static/src/js/coresetup.js39
-rw-r--r--addons/web/static/src/js/data.js42
-rw-r--r--addons/web/static/src/js/data_export.js10
-rw-r--r--addons/web/static/src/js/search.js310
-rw-r--r--addons/web/static/src/js/test_support.js8
-rw-r--r--addons/web/static/src/js/view_form.js652
-rw-r--r--addons/web/static/src/js/view_list.js104
-rw-r--r--addons/web/static/src/js/view_list_editable.js63
-rw-r--r--addons/web/static/src/js/view_tree.js111
-rw-r--r--addons/web/static/src/js/views.js60
12 files changed, 866 insertions, 643 deletions
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 81334cd6589..9c249a5fb0c 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -81,9 +81,6 @@ instance.web.Dialog = instance.web.Widget.extend({
}
}
if (options) {
- if (options.buttons) {
- this.params_buttons = true;
- }
_.extend(this.dialog_options, options);
}
this.on("closing", this, this._closing);
@@ -129,6 +126,8 @@ instance.web.Dialog = instance.web.Widget.extend({
if (! this.dialog_inited)
this.init_dialog();
var o = this.get_options(options);
+ this.add_buttons(o.buttons);
+ delete(o.buttons);
this.$buttons.appendTo($("body"));
instance.web.dialog(this.$el, o).dialog('open');
this.$el.dialog("widget").find(".ui-dialog-buttonpane").remove();
@@ -138,22 +137,30 @@ instance.web.Dialog = instance.web.Widget.extend({
}
return this;
},
+ add_buttons: function(buttons) {
+ var self = this;
+ _.each(buttons, function(fn, but) {
+ var $but = $(QWeb.render('WidgetButton', { widget : { string: but, node: { attrs: {} }}}));
+ self.$buttons.append($but);
+ $but.on('click', function(ev) {
+ fn.call(self.$el, ev);
+ });
+ });
+ },
init_dialog: function(options) {
this.renderElement();
var o = this.get_options(options);
instance.web.dialog(this.$el, o);
- if (! this.params_buttons) {
- this.$buttons = $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" />');
- this.$el.dialog("widget").append(this.$buttons);
- } else {
- this.$buttons = this.$el.dialog("widget").find(".ui-dialog-buttonpane");
- }
+ this.$buttons = $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" />');
+ this.$el.dialog("widget").append(this.$buttons);
this.dialog_inited = true;
var res = this.start();
return res;
},
close: function() {
- this.$el.dialog('close');
+ if (this.dialog_inited && this.$el.is(":data(dialog)")) {
+ this.$el.dialog('close');
+ }
},
_closing: function() {
if (this.__tmp_dialog_destroying)
@@ -175,7 +182,7 @@ instance.web.Dialog = instance.web.Widget.extend({
this.close();
this.__tmp_dialog_destroying = undefined;
}
- if (! this.isDestroyed()) {
+ if (this.dialog_inited && !this.isDestroyed()) {
this.$el.dialog('destroy');
}
this._super();
@@ -294,7 +301,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
start: function() {
var self = this;
$('.oe_secondary_menus_container,.oe_user_menu_placeholder').empty();
- var fetch_db = this.rpc("/web/database/get_list", {}).pipe(
+ var fetch_db = this.rpc("/web/database/get_list", {}).then(
function(result) {
self.db_list = result.db_list;
},
@@ -302,10 +309,10 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
ev.preventDefault();
self.db_list = null;
});
- var fetch_langs = this.rpc("/web/session/get_lang_list", {}).then(function(result) {
+ var fetch_langs = this.rpc("/web/session/get_lang_list", {}).done(function(result) {
self.lang_list = result.lang_list;
});
- return $.when(fetch_db, fetch_langs).then(self.do_render);
+ return $.when(fetch_db, fetch_langs).done(self.do_render);
},
do_render: function() {
var self = this;
@@ -394,7 +401,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}).then(function(result) {
+ self.rpc("/web/database/create", {'fields': fields}).done(function(result) {
var form_obj = self.to_object(fields);
var client_action = {
type: 'ir.actions.client',
@@ -420,7 +427,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}).then(function(result) {
+ self.rpc("/web/database/drop", {'fields': fields}).done(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -483,7 +490,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
var self = this;
self.rpc("/web/database/change_password", {
'fields': $(form).serializeArray()
- }).then(function(result) {
+ }).done(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -504,13 +511,13 @@ instance.web.Login = instance.web.Widget.extend({
template: "Login",
remember_credentials: true,
- init: function(parent, params) {
+ init: function(parent, action) {
this._super(parent);
this.has_local_storage = typeof(localStorage) != 'undefined';
this.db_list = null;
this.selected_db = null;
this.selected_login = null;
- this.params = params || {};
+ this.params = action.params || {};
if (this.params.login_successful) {
this.on('login_successful', this, this.params.login_successful);
@@ -581,7 +588,7 @@ instance.web.Login = instance.web.Widget.extend({
var self = this;
self.hide_error();
self.$(".oe_login_pane").fadeOut("slow");
- return this.session.session_authenticate(db, login, password).pipe(function() {
+ return this.session.session_authenticate(db, login, password).then(function() {
if (self.has_local_storage) {
if(self.remember_credentials) {
localStorage.setItem('last_db_login_success', db);
@@ -616,8 +623,9 @@ instance.web.client_actions.add("login", "instance.web.Login");
* Client action to reload the whole interface.
* If params has an entry 'menu_id', it opens the given menu entry.
*/
-instance.web.Reload = function(parent, params) {
- var menu_id = (params && params.menu_id) || false;
+instance.web.Reload = function(parent, action) {
+ var params = action.params || {};
+ var menu_id = params.menu_id || false;
var l = window.location;
var sobj = $.deparam(l.search.substr(1));
@@ -638,7 +646,7 @@ instance.web.client_actions.add("reload", "instance.web.Reload");
* Client action to go back in breadcrumb history.
* If can't go back in history stack, will go back to home.
*/
-instance.web.HistoryBack = function(parent, params) {
+instance.web.HistoryBack = function(parent) {
if (!parent.history_back()) {
window.location = '/' + (window.location.search || '');
}
@@ -649,7 +657,7 @@ instance.web.client_actions.add("history_back", "instance.web.HistoryBack");
* Client action to go back home.
*/
instance.web.Home = instance.web.Widget.extend({
- init: function(parent, params) {
+ init: function(parent) {
window.location = '/' + (window.location.search || '');
}
});
@@ -663,7 +671,7 @@ instance.web.ChangePassword = instance.web.Widget.extend({
submitHandler: function (form) {
self.rpc("/web/session/change_password",{
'fields': $(form).serializeArray()
- }).then(function(result) {
+ }).done(function(result) {
if (result.error) {
self.display_error(result);
return;
@@ -702,7 +710,7 @@ instance.web.Menu = instance.web.Widget.extend({
},
do_reload: function() {
var self = this;
- return this.rpc("/web/menu/load", {}).then(function(r) {
+ return this.rpc("/web/menu/load", {}).done(function(r) {
self.menu_loaded(r);
});
},
@@ -872,7 +880,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
if (!self.session.uid)
return;
var func = new instance.web.Model("res.users").get_func("read");
- return func(self.session.uid, ["name", "company_id"]).pipe(function(res) {
+ return func(self.session.uid, ["name", "company_id"]).then(function(res) {
var topbar_name = res.name;
if(instance.session.debug)
topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db);
@@ -883,7 +891,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
$avatar.attr('src', avatar_src);
});
};
- this.update_promise = this.update_promise.pipe(fct, fct);
+ this.update_promise = this.update_promise.then(fct, fct);
},
on_menu_logout: function() {
this.trigger('user_logout');
@@ -899,7 +907,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
},
on_menu_about: function() {
var self = this;
- self.rpc("/web/webclient/version_info", {}).then(function(res) {
+ self.rpc("/web/webclient/version_info", {}).done(function(res) {
var $help = $(QWeb.render("UserMenu.about", {version_info: res}));
$help.find('a.oe_activate_debug_mode').click(function (e) {
e.preventDefault();
@@ -919,7 +927,7 @@ instance.web.Client = instance.web.Widget.extend({
},
start: function() {
var self = this;
- return instance.session.session_bind(this.origin).pipe(function() {
+ return instance.session.session_bind(this.origin).then(function() {
var $e = $(QWeb.render(self._template, {}));
self.replaceElement($e);
self.bind_events();
@@ -986,7 +994,7 @@ instance.web.WebClient = instance.web.Client.extend({
},
start: function() {
var self = this;
- return $.when(this._super()).pipe(function() {
+ return $.when(this._super()).then(function() {
self.$el.on('click', '.oe_logo', function() {
self.action_manager.do_action('home');
});
@@ -1055,8 +1063,8 @@ instance.web.WebClient = instance.web.Client.extend({
},
do_reload: function() {
var self = this;
- return this.session.session_reload().pipe(function () {
- instance.session.load_modules(true).pipe(
+ return this.session.session_reload().then(function () {
+ instance.session.load_modules(true).then(
self.menu.proxy('do_reload')); });
},
@@ -1071,7 +1079,7 @@ instance.web.WebClient = instance.web.Client.extend({
on_logout: function() {
var self = this;
if (!this.has_uncommitted_changes()) {
- this.session.session_logout().then(function () {
+ this.session.session_logout().done(function () {
$(window).unbind('hashchange', self.on_hashchange);
self.do_push_state({});
window.location.reload();
@@ -1084,7 +1092,7 @@ instance.web.WebClient = instance.web.Client.extend({
var state = $.bbq.getState(true);
if (_.isEmpty(state) || state.action == "login") {
- self.menu.has_been_loaded.then(function() {
+ self.menu.has_been_loaded.done(function() {
var first_menu_id = self.menu.$el.find("a:first").data("menu");
if(first_menu_id) {
self.menu.menu_click(first_menu_id);
@@ -1099,8 +1107,8 @@ instance.web.WebClient = instance.web.Client.extend({
var state = event.getState(true);
if (!_.isEqual(this._current_state, state)) {
if(state.action_id === undefined && state.menu_id) {
- self.menu.has_been_loaded.then(function() {
- self.menu.do_reload().then(function() {
+ self.menu.has_been_loaded.done(function() {
+ self.menu.do_reload().done(function() {
self.menu.menu_click(state.menu_id)
});
});
@@ -1122,7 +1130,7 @@ instance.web.WebClient = instance.web.Client.extend({
on_menu_action: function(options) {
var self = this;
return this.rpc("/web/action/load", { action_id: options.action_id })
- .pipe(function (result) {
+ .then(function (result) {
var action = result;
if (options.needaction) {
action.context.search_default_message_unread = true;
@@ -1168,9 +1176,9 @@ instance.web.EmbeddedClient = instance.web.Client.extend({
},
start: function() {
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 }).then(function(result) {
+ return $.when(this._super()).then(function() {
+ return instance.session.session_authenticate(self.dbname, self.login, self.key, true).then(function() {
+ return self.rpc("/web/action/load", { action_id: self.action_id }).done(function(result) {
var action = result;
action.flags = _.extend({
//views_switcher : false,
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index 6ecbfdd01ac..d2e94d37939 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -809,12 +809,12 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
return false;
},
rpc: function(url, data, success, error) {
- var def = $.Deferred().then(success, error);
+ var def = $.Deferred().done(success).fail(error);
var self = this;
- instance.session.rpc(url, data).then(function() {
+ instance.session.rpc(url, data).done(function() {
if (!self.isDestroyed())
def.resolve.apply(def, arguments);
- }, function() {
+ }).fail(function() {
if (!self.isDestroyed())
def.reject.apply(def, arguments);
});
@@ -1287,7 +1287,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
};
var deferred = $.Deferred();
this.trigger('request', url, payload);
- var request = this.rpc_function(url, payload).then(
+ var request = this.rpc_function(url, payload).done(
function (response, textStatus, jqXHR) {
self.trigger('response', response);
if (!response.error) {
@@ -1300,7 +1300,8 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
} else {
deferred.reject(response.error, $.Event());
}
- },
+ }
+ ).fail(
function(jqXHR, textStatus, errorThrown) {
self.trigger('response_failed', jqXHR);
var error = {
@@ -1387,10 +1388,11 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
$iframe.unbind('load').bind('load', function() {
$.ajax(ajax).always(function() {
cleanUp();
- }).then(
- function() { deferred.resolve.apply(deferred, arguments); },
- function() { deferred.reject.apply(deferred, arguments); }
- );
+ }).done(function() {
+ deferred.resolve.apply(deferred, arguments);
+ }).fail(function() {
+ deferred.reject.apply(deferred, arguments);
+ });
});
// now that the iframe can receive data, we fill and submit the form
$form.submit();
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index 1f1112df2f2..b7dac303520 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -51,15 +51,15 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
var self = this;
// TODO: session store in cookie should be optional
this.session_id = this.get_cookie('session_id');
- return this.session_reload().pipe(function(result) {
+ return this.session_reload().then(function(result) {
var modules = instance._modules.join(',');
- var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb);
+ var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).then(self.do_load_qweb);
if(self.session_is_valid()) {
- return deferred.pipe(function() { return self.load_modules(); });
+ return deferred.then(function() { return self.load_modules(); });
}
return $.when(
deferred,
- self.rpc('/web/webclient/bootstrap_translations', {mods: instance._modules}).pipe(function(trans) {
+ self.rpc('/web/webclient/bootstrap_translations', {mods: instance._modules}).then(function(trans) {
instance.web._t.database.set_bundle(trans);
})
);
@@ -73,7 +73,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
*/
session_reload: function () {
var self = this;
- return this.rpc("/web/session/get_session_info", {}).then(function(result) {
+ return this.rpc("/web/session/get_session_info", {}).done(function(result) {
// If immediately follows a login (triggered by trying to restore
// an invalid session or no session at all), refresh session data
// (should not change, but just in case...)
@@ -96,7 +96,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
var self = this;
var base_location = document.location.protocol + '//' + document.location.host;
var params = { db: db, login: login, password: password, base_location: base_location };
- return this.rpc("/web/session/authenticate", params).pipe(function(result) {
+ return this.rpc("/web/session/authenticate", params).then(function(result) {
if (!result.uid) {
return $.Deferred().reject();
}
@@ -154,30 +154,30 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
*/
load_modules: function() {
var self = this;
- return this.rpc('/web/session/modules', {}).pipe(function(result) {
+ return this.rpc('/web/session/modules', {}).then(function(result) {
var lang = self.user_context.lang,
all_modules = _.uniq(self.module_list.concat(result));
var params = { mods: all_modules, lang: lang};
var to_load = _.difference(result, self.module_list).join(',');
self.module_list = all_modules;
- var loaded = self.rpc('/web/webclient/translations', params).then(function(trans) {
+ var loaded = self.rpc('/web/webclient/translations', params).done(function(trans) {
instance.web._t.database.set_bundle(trans);
});
var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
if(to_load.length) {
loaded = $.when(
loaded,
- self.rpc('/web/webclient/csslist', {mods: to_load}).then(self.do_load_css),
- self.rpc('/web/webclient/qweblist', {mods: to_load}).pipe(self.do_load_qweb),
- self.rpc('/web/webclient/jslist', {mods: to_load}).then(function(files) {
+ self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.do_load_css),
+ self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.do_load_qweb),
+ self.rpc('/web/webclient/jslist', {mods: to_load}).done(function(files) {
file_list = file_list.concat(files);
})
);
}
- return loaded.pipe(function () {
+ return loaded.then(function () {
return self.do_load_js(file_list);
- }).then(function() {
+ }).done(function() {
self.on_modules_loaded();
self.trigger('module_loaded');
if (!Date.CultureInfo.pmDesignator) {
@@ -212,7 +212,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
return;
tag.onload_done = true;
- self.do_load_js(files).then(function () {
+ self.do_load_js(files).done(function () {
d.resolve();
});
};
@@ -227,7 +227,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
var self = this;
_.each(files, function(file) {
self.qweb_mutex.exec(function() {
- return self.rpc('/web/proxy/load', {path: file}).pipe(function(xml) {
+ return self.rpc('/web/proxy/load', {path: file}).then(function(xml) {
if (!xml) { return; }
instance.web.qweb.add_template(_.str.trim(xml));
});
@@ -462,7 +462,7 @@ $.Mutex = (function() {
Mutex.prototype.exec = function(action) {
var current = this.def;
var next = this.def = $.Deferred();
- return current.pipe(function() {
+ return current.then(function() {
return $.when(action()).always(function() {
next.resolve();
});
@@ -474,7 +474,7 @@ $.Mutex = (function() {
$.async_when = function() {
var async = false;
var def = $.Deferred();
- $.when.apply($, arguments).then(function() {
+ $.when.apply($, arguments).done(function() {
var args = arguments;
var action = function() {
def.resolve.apply(def, args);
@@ -483,7 +483,7 @@ $.async_when = function() {
action();
else
setTimeout(action, 0);
- }, function() {
+ }).fail(function() {
var args = arguments;
var action = function() {
def.reject.apply(def, args);
@@ -530,7 +530,8 @@ instance.web.qweb.default_dict['__debug__'] = instance.session.debug; // Which o
instance.web.qweb.debug = instance.session.debug;
instance.web.qweb.default_dict = {
'_' : _,
- '_t' : instance.web._t
+ '_t' : instance.web._t,
+ 'JSON': JSON,
};
instance.web.qweb.preprocess_node = function() {
// Note that 'this' is the Qweb Node
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index e279ade6fb3..2f8679794b0 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -66,7 +66,7 @@ instance.web.Query = instance.web.Class.extend({
offset: this._offset,
limit: this._limit,
sort: instance.web.serialize_sort(this._order_by)
- }).pipe(function (results) {
+ }).then(function (results) {
self._count = results.length;
return results.records;
}, null);
@@ -78,7 +78,7 @@ instance.web.Query = instance.web.Class.extend({
*/
first: function () {
var self = this;
- return this.clone({limit: 1})._execute().pipe(function (records) {
+ return this.clone({limit: 1})._execute().then(function (records) {
delete self._count;
if (records.length) { return records[0]; }
return null;
@@ -132,7 +132,7 @@ instance.web.Query = instance.web.Class.extend({
offset: this._offset,
limit: this._limit,
orderby: instance.web.serialize_sort(this._order_by) || false
- }).pipe(function (results) {
+ }).then(function (results) {
return _(results).map(function (result) {
// FIX: querygroup initialization
result.__context = result.__context || {};
@@ -443,7 +443,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
return this._model.query(fields)
.limit(options.limit || false)
.offset(options.offset || 0)
- .all().then(function (records) {
+ .all().done(function (records) {
self.ids = _(records).pluck('id');
});
},
@@ -456,7 +456,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
*/
read_index: function (fields, options) {
options = options || {};
- return this.read_ids([this.ids[this.index]], fields, options).pipe(function (records) {
+ return this.read_ids([this.ids[this.index]], fields, options).then(function (records) {
if (_.isEmpty(records)) { return $.Deferred().reject().promise(); }
return records[0];
});
@@ -471,7 +471,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
default_get: function(fields, options) {
options = options || {};
return this._model.call('default_get',
- [fields], {context: this._model.context(options.context)});
+ [fields], {context: this.get_context(options.context)});
},
/**
* Creates a new record in db
@@ -480,7 +480,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @returns {$.Deferred}
*/
create: function(data) {
- return this._model.call('create', [data], {context: this._model.context()});
+ return this._model.call('create', [data], {context: this.get_context()});
},
/**
* Saves the provided data in an existing db record
@@ -493,7 +493,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
*/
write: function (id, data, options) {
options = options || {};
- return this._model.call('write', [[id], data], {context: this._model.context(options.context)}).then(this.trigger('dataset_changed', id, data, options));
+ return this._model.call('write', [[id], data], {context: this.get_context(options.context)}).done(this.trigger('dataset_changed', id, data, options));
},
/**
* Deletes an existing record from the database
@@ -501,7 +501,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @param {Number|String} ids identifier of the record to delete
*/
unlink: function(ids) {
- return this._model.call('unlink', [ids], {context: this._model.context()}).then(this.trigger('dataset_changed', ids));
+ return this._model.call('unlink', [ids], {context: this.get_context()}).done(this.trigger('dataset_changed', ids));
},
/**
* Calls an arbitrary RPC method
@@ -532,7 +532,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @returns {$.Deferred}
*/
name_get: function(ids) {
- return this._model.call('name_get', [ids], {context: this._model.context()});
+ return this._model.call('name_get', [ids], {context: this.get_context()});
},
/**
*
@@ -556,7 +556,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @param name
*/
name_create: function(name) {
- return this._model.call('name_create', [name], {context: this._model.context()});
+ return this._model.call('name_create', [name], {context: this.get_context()});
},
exec_workflow: function (id, signal) {
return this._model.exec_workflow(id, signal);
@@ -606,8 +606,8 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
return instance.session.rpc('/web/dataset/resequence', {
model: this.model,
ids: ids,
- context: this._model.context(options.context),
- }).pipe(function (results) {
+ context: this.get_context(options.context),
+ }).then(function (results) {
return results;
});
},
@@ -682,9 +682,9 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({
.limit(options.limit || false);
q = q.order_by.apply(q, this._sort);
- return q.all().then(function (records) {
+ return q.all().done(function (records) {
// FIXME: not sure about that one, *could* have discarded count
- q.count().then(function (count) { self._length = count; });
+ q.count().done(function (count) { self._length = count; });
self.ids = _(records).pluck('id');
});
},
@@ -693,7 +693,7 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({
},
unlink: function(ids, callback, error_callback) {
var self = this;
- return this._super(ids).then(function(result) {
+ return this._super(ids).done(function(result) {
self.ids = _(self.ids).difference(ids);
if (self._length) {
self._length -= 1;
@@ -722,7 +722,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
this.last_default_get = {};
},
default_get: function(fields, options) {
- return this._super(fields, options).then(this.on_default_get);
+ return this._super(fields, options).done(this.on_default_get);
},
on_default_get: function(res) {
this.last_default_get = res;
@@ -774,7 +774,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
this.trigger("dataset_changed", ids, callback, error_callback);
- return $.async_when({result: true}).then(callback);
+ return $.async_when({result: true}).done(callback);
},
reset_ids: function(ids) {
this.set_ids(ids);
@@ -836,7 +836,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
completion.resolve(records);
};
if(to_get.length > 0) {
- var rpc_promise = this._super(to_get, fields, options).then(function(records) {
+ var rpc_promise = this._super(to_get, fields, options).done(function(records) {
_.each(records, function(record, index) {
var id = to_get[index];
var cached = _.detect(self.cache, function(x) {return x.id === id;});
@@ -991,14 +991,14 @@ instance.web.DropMisordered = instance.web.Class.extend({
var res = $.Deferred();
var self = this, seq = this.lsn++;
- deferred.then(function () {
+ deferred.done(function () {
if (seq > self.rsn) {
self.rsn = seq;
res.resolve.apply(res, arguments);
} else if (self.failMisordered) {
res.reject();
}
- }, function () {
+ }).fail(function () {
res.reject.apply(res, arguments);
});
diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js
index b4beb4c3a58..477d89c99b3 100644
--- a/addons/web/static/src/js/data_export.js
+++ b/addons/web/static/src/js/data_export.js
@@ -51,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)
- }).then(function (records) {
+ }).done(function (records) {
got_fields.resolve();
self.on_show_data(records);
});
@@ -59,7 +59,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
return $.when(
got_fields,
- this.rpc('/web/export/formats', {}).then(this.do_setup_export_formats),
+ this.rpc('/web/export/formats', {}).done(this.do_setup_export_formats),
this.show_exports_list());
},
do_setup_export_formats: function (formats) {
@@ -84,7 +84,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
}
return this.exports.read_slice(['name'], {
domain: [['resource', '=', this.dataset.model]]
- }).then(function (export_list) {
+ }).done(function (export_list) {
if (!export_list.length) {
return;
}
@@ -93,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)}).then(self.do_load_export_field);
+ self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}).done(self.do_load_export_field);
}
});
self.$el.find('#delete_export_list').click(function() {
@@ -183,7 +183,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
import_compat: Boolean(import_comp),
parent_field_type : record['field_type'],
exclude: exclude_fields
- }).then(function(results) {
+ }).done(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 9351f621324..e84ea66ff9a 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -124,19 +124,10 @@ function assert(condition, message) {
}
my.InputView = instance.web.Widget.extend({
template: 'SearchView.InputView',
- start: function () {
- var p = this._super.apply(this, arguments);
- this.$el.on('focus', this.proxy('onFocus'));
- this.$el.on('blur', this.proxy('onBlur'));
- this.$el.on('keydown', this.proxy('onKeydown'));
- return p;
- },
- onFocus: function () {
- this.trigger('focused', this);
- },
- onBlur: function () {
- this.$el.text('');
- this.trigger('blurred', this);
+ events: {
+ focus: function () { this.trigger('focused', this); },
+ blur: function () { this.$el.text(''); this.trigger('blurred', this); },
+ keydown: 'onKeydown'
},
getSelection: function () {
// get Text node
@@ -212,6 +203,27 @@ my.InputView = instance.web.Widget.extend({
});
my.FacetView = instance.web.Widget.extend({
template: 'SearchView.FacetView',
+ events: {
+ 'focus': function () { this.trigger('focused', this); },
+ 'blur': function () { this.trigger('blurred', this); },
+ 'click': function (e) {
+ if ($(e.target).is('.oe_facet_remove')) {
+ this.model.destroy();
+ return false;
+ }
+ this.$el.focus();
+ e.stopPropagation();
+ },
+ 'keydown': function (e) {
+ var keys = $.ui.keyCode;
+ switch (e.which) {
+ case keys.BACKSPACE:
+ case keys.DELETE:
+ this.model.destroy();
+ return false;
+ }
+ }
+ },
init: function (parent, model) {
this._super(parent);
this.model = model;
@@ -223,33 +235,11 @@ my.FacetView = instance.web.Widget.extend({
},
start: function () {
var self = this;
- this.$el.on('focus', function () { self.trigger('focused', self); });
- this.$el.on('blur', function () { self.trigger('blurred', self); });
- this.$el.on('click', function (e) {
- if ($(e.target).is('.oe_facet_remove')) {
- self.model.destroy();
- return false;
- }
- self.$el.focus();
- e.stopPropagation();
- });
- this.$el.on('keydown', function (e) {
- var keys = $.ui.keyCode;
- switch (e.which) {
- case keys.BACKSPACE:
- case keys.DELETE:
- self.model.destroy();
- return false;
- }
- });
- var $e = self.$el.find('> span:last-child');
- var q = $.when(this._super());
- return q.pipe(function () {
- var values = self.model.values.map(function (value) {
+ var $e = this.$('> span:last-child');
+ return $.when(this._super()).then(function () {
+ return $.when.apply(null, self.model.values.map(function (value) {
return new my.FacetValueView(self, value).appendTo($e);
- });
-
- return $.when.apply(null, values);
+ }));
});
},
model_changed: function () {
@@ -274,6 +264,39 @@ my.FacetValueView = instance.web.Widget.extend({
instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.SearchView# */{
template: "SearchView",
+ events: {
+ // focus last input if view itself is clicked
+ 'click': function (e) {
+ if (e.target === this.$('.oe_searchview_facets')[0]) {
+ this.$('.oe_searchview_input:last').focus();
+ }
+ },
+ // search button
+ 'click button.oe_searchview_search': function (e) {
+ e.stopImmediatePropagation();
+ this.do_search();
+ },
+ 'click .oe_searchview_clear': function (e) {
+ e.stopImmediatePropagation();
+ this.query.reset();
+ },
+ 'click .oe_searchview_unfold_drawer': function (e) {
+ e.stopImmediatePropagation();
+ this.$el.toggleClass('oe_searchview_open_drawer');
+ },
+ 'keydown .oe_searchview_input, .oe_searchview_facet': function (e) {
+ switch(e.which) {
+ case $.ui.keyCode.LEFT:
+ this.focusPreceding(this);
+ e.preventDefault();
+ break;
+ case $.ui.keyCode.RIGHT:
+ this.focusFollowing(this);
+ e.preventDefault();
+ break;
+ }
+ }
+ },
/**
* @constructs instance.web.SearchView
* @extends instance.web.Widget
@@ -324,62 +347,18 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
context: this.dataset.get_context() });
$.when(load_view)
- .pipe(function(r) {
+ .then(function(r) {
self.search_view_loaded(r)
}).fail(function () {
self.ready.reject.apply(null, arguments);
});
}
- // Launch a search on clicking the oe_searchview_search button
- this.$el.on('click', 'button.oe_searchview_search', function (e) {
- e.stopImmediatePropagation();
- self.do_search();
- });
-
- this.$el.on('keydown',
- '.oe_searchview_input, .oe_searchview_facet', function (e) {
- switch(e.which) {
- case $.ui.keyCode.LEFT:
- self.focusPreceding(this);
- e.preventDefault();
- break;
- case $.ui.keyCode.RIGHT:
- self.focusFollowing(this);
- e.preventDefault();
- break;
- }
- });
-
- this.$el.on('click', '.oe_searchview_clear', function (e) {
- e.stopImmediatePropagation();
- self.query.reset();
- });
- this.$el.on('click', '.oe_searchview_unfold_drawer', function (e) {
- e.stopImmediatePropagation();
- self.$el.toggleClass('oe_searchview_open_drawer');
- });
instance.web.bus.on('click', this, function(ev) {
if ($(ev.target).parents('.oe_searchview').length === 0) {
self.$el.removeClass('oe_searchview_open_drawer');
}
});
- // Focus last input if the view itself is clicked (empty section of
- // facets element)
- this.$el.on('click', function (e) {
- if (e.target === self.$el.find('.oe_searchview_facets')[0]) {
- self.$el.find('.oe_searchview_input:last').focus();
- }
- });
- // when the completion list opens/refreshes, automatically select the
- // first completion item so if the user just hits [RETURN] or [TAB] it
- // automatically selects it
- this.$el.on('autocompleteopen', function () {
- var menu = self.$el.data('autocomplete').menu;
- menu.activate(
- $.Event({ type: "mouseenter" }),
- menu.element.children().first());
- });
return $.when(p, this.ready);
},
@@ -429,58 +408,46 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
setup_global_completion: function () {
var self = this;
- // autocomplete only correctly handles being initialized on the actual
- // editable element (and only an element with a @value in 1.8 e.g.
- // input or textarea), cheat by setting val() on $el
- this.$el.on('keydown', function () {
- // keydown is triggered *before* the element's value is set, so
- // delay this. Pray that setTimeout are executed in FIFO (if they
- // have the same delay) as autocomplete uses the exact same trick.
- // FIXME: brittle as fuck
- setTimeout(function () {
- self.$el.val(self.currentInputValue());
- }, 0);
-
- });
-
- this.$el.autocomplete({
+ var autocomplete = this.$el.autocomplete({
source: this.proxy('complete_global_search'),
select: this.proxy('select_completion'),
focus: function (e) { e.preventDefault(); },
html: true,
+ autoFocus: true,
minLength: 1,
delay: 0
- }).data('autocomplete')._renderItem = function (ul, item) {
- // item of completion list
- var $item = $( "<li></li>" )
- .data( "item.autocomplete", item )
- .appendTo( ul );
-
- if (item.facet !== undefined) {
- // regular completion item
- return $item.append(
- (item.label)
- ? $('<a>').html(item.label)
- : $('<a>').text(item.value));
- }
- return $item.text(item.label)
- .css({
- borderTop: '1px solid #cccccc',
- margin: 0,
- padding: 0,
- zoom: 1,
- 'float': 'left',
- clear: 'left',
- width: '100%'
- });
- };
- },
- /**
- * Gets value out of the currently focused "input" (a
- * div[contenteditable].oe_searchview_input)
- */
- currentInputValue: function () {
- return this.$el.find('div.oe_searchview_input:focus').text();
+ }).data('autocomplete');
+
+ // MonkeyPatch autocomplete instance
+ _.extend(autocomplete, {
+ _renderItem: function (ul, item) {
+ // item of completion list
+ var $item = $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .appendTo( ul );
+
+ if (item.facet !== undefined) {
+ // regular completion item
+ return $item.append(
+ (item.label)
+ ? $('<a>').html(item.label)
+ : $('<a>').text(item.value));
+ }
+ return $item.text(item.label)
+ .css({
+ borderTop: '1px solid #cccccc',
+ margin: 0,
+ padding: 0,
+ zoom: 1,
+ 'float': 'left',
+ clear: 'left',
+ width: '100%'
+ });
+ },
+ _value: function() {
+ return self.$('div.oe_searchview_input').text();
+ },
+ });
},
/**
* Provide auto-completion result for req.term (an array to `resp`)
@@ -492,7 +459,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
complete_global_search: function (req, resp) {
$.when.apply(null, _(this.inputs).chain()
.invoke('complete', req.term)
- .value()).then(function () {
+ .value()).done(function () {
resp(_(_(arguments).compact()).flatten(true));
});
},
@@ -510,7 +477,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
var input_index = _(this.input_subviews).indexOf(
this.subviewForRoot(
- this.$el.find('div.oe_searchview_input:focus')[0]));
+ this.$('div.oe_searchview_input:focus')[0]));
this.query.add(ui.item.facet, {at: input_index / 2});
},
childFocused: function () {
@@ -539,7 +506,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
// _2: undefined if event=change, otherwise model
var self = this;
var started = [];
- var $e = this.$el.find('div.oe_searchview_facets');
+ var $e = this.$('div.oe_searchview_facets');
_.invoke(this.input_subviews, 'destroy');
this.input_subviews = [];
@@ -560,7 +527,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
childView.on('blurred', self, self.proxy('childBlurred'));
});
- $.when.apply(null, started).then(function () {
+ $.when.apply(null, started).done(function () {
var input_to_focus;
// options.at: facet inserted at given index, focus next input
// otherwise just focus last input
@@ -664,16 +631,16 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
// build drawer
var drawer_started = $.when.apply(
null, _(this.select_for_drawer()).invoke(
- 'appendTo', this.$el.find('.oe_searchview_drawer')));
+ 'appendTo', this.$('.oe_searchview_drawer')));
// load defaults
var defaults_fetched = $.when.apply(null, _(this.inputs).invoke(
- 'facet_for_defaults', this.defaults)).then(function () {
+ 'facet_for_defaults', this.defaults)).done(function () {
self.query.reset(_(arguments).compact(), {preventSearch: true});
});
return $.when(drawer_started, defaults_fetched)
- .then(function () {
+ .done(function () {
self.trigger("search_view_loaded", data);
self.ready.resolve();
});
@@ -736,6 +703,9 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
*
* If at least one field failed its validation, triggers
* :js:func:`instance.web.SearchView.on_invalid` instead.
+ *
+ * @param [_query]
+ * @param {Object} [options]
*/
do_search: function (_query, options) {
if (options && options.preventSearch) {
@@ -788,6 +758,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
instance.web.search.fields = new instance.web.Registry({
'char': 'instance.web.search.CharField',
'text': 'instance.web.search.CharField',
+ 'html': 'instance.web.search.CharField',
'boolean': 'instance.web.search.BooleanField',
'integer': 'instance.web.search.IntegerField',
'id': 'instance.web.search.IntegerField',
@@ -960,7 +931,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
*/
search_change: function () {
var self = this;
- var $filters = this.$el.find('> li').removeClass('oe_selected');
+ var $filters = this.$('> li').removeClass('oe_selected');
var facet = this.view.query.find(_.bind(this.match_facet, this));
if (!facet) { return; }
facet.values.each(function (v) {
@@ -1438,7 +1409,7 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
name: needle,
limit: 8,
context: {}
- }).pipe(function (results) {
+ }).then(function (results) {
if (_.isEmpty(results)) { return null; }
return [{label: self.attrs.string}].concat(
_(results).map(function (result) {
@@ -1461,7 +1432,7 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
// to handle this as if it were a single value.
value = value[0];
}
- return this.model.call('name_get', [value]).pipe(function (names) {
+ return this.model.call('name_get', [value]).then(function (names) {
if (_(names).isEmpty()) { return null; }
return facet_from(self, names[0]);
})
@@ -1508,10 +1479,10 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
// FIXME: local eval of domain and context to get rid of special endpoint
return this.rpc('/web/searchview/get_filters', {
model: this.view.model
- }).pipe(this.proxy('set_filters'));
+ }).then(this.proxy('set_filters'));
},
clear_selection: function () {
- this.$el.find('li.oe_selected').removeClass('oe_selected');
+ this.$('li.oe_selected').removeClass('oe_selected');
},
append_filter: function (filter) {
var self = this;
@@ -1523,7 +1494,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
} else {
var id = filter.id;
$filter = this.filters[key] = $('<li></li>')
- .appendTo(this.$el.find('.oe_searchview_custom_list'))
+ .appendTo(this.$('.oe_searchview_custom_list'))
.addClass(filter.user_id ? 'oe_searchview_custom_private'
: 'oe_searchview_custom_public')
.text(filter.name);
@@ -1531,7 +1502,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
$('<a class="oe_searchview_custom_delete">x</a>')
.click(function (e) {
e.stopPropagation();
- self.model.call('unlink', [id]).then(function () {
+ self.model.call('unlink', [id]).done(function () {
$filter.remove();
});
})
@@ -1558,15 +1529,15 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
},
save_current: function () {
var self = this;
- var $name = this.$el.find('input:first');
- var private_filter = !this.$el.find('input:last').prop('checked');
+ var $name = this.$('input:first');
+ var private_filter = !this.$('input:last').prop('checked');
var search = this.view.build_search_data();
this.rpc('/web/session/eval_domain_and_context', {
domains: search.domains,
contexts: search.contexts,
group_by_seq: search.groupbys || []
- }).then(function (results) {
+ }).done(function (results) {
if (!_.isEmpty(results.group_by)) {
results.context.group_by = results.group_by;
}
@@ -1578,7 +1549,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
domain: results.domain
};
// FIXME: current context?
- return self.model.call('create_or_replace', [filter]).then(function (id) {
+ return self.model.call('create_or_replace', [filter]).done(function (id) {
filter.id = id;
self.append_filter(filter);
self.$el
@@ -1655,20 +1626,29 @@ instance.web.search.Advanced = instance.web.search.Input.extend({
});
return $.when(
this._super(),
- this.rpc("/web/searchview/fields_get", {model: this.view.model}).then(function(data) {
+ this.rpc("/web/searchview/fields_get", {model: this.view.model}).done(function(data) {
self.fields = _.extend({
id: { string: 'ID', type: 'id' }
}, data.fields);
- })).then(function () {
+ })).done(function () {
self.append_proposition();
});
},
append_proposition: function () {
+ var self = this;
return (new instance.web.search.ExtendedSearchProposition(this, this.fields))
- .appendTo(this.$el.find('ul'));
+ .appendTo(this.$('ul')).done(function () {
+ self.$('button.oe_apply').prop('disabled', false);
+ });
+ },
+ remove_proposition: function (prop) {
+ // removing last proposition, disable apply button
+ if (this.getChildren().length <= 1) {
+ this.$('button.oe_apply').prop('disabled', true);
+ }
+ prop.destroy();
},
commit_search: function () {
- var self = this;
// Get domain sections from all propositions
var children = this.getChildren();
var propositions = _.invoke(children, 'get_proposition');
@@ -1698,6 +1678,13 @@ instance.web.search.Advanced = instance.web.search.Input.extend({
instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @lends instance.web.search.ExtendedSearchProposition# */{
template: 'SearchView.extended_search.proposition',
+ events: {
+ 'change .searchview_extended_prop_field': 'changed',
+ 'click .searchview_extended_delete_prop': function (e) {
+ e.stopPropagation();
+ this.getParent().remove_proposition(this);
+ }
+ },
/**
* @constructs instance.web.search.ExtendedSearchProposition
* @extends instance.web.Widget
@@ -1715,17 +1702,10 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
this.value = null;
},
start: function () {
- var _this = this;
- this.$el.find(".searchview_extended_prop_field").change(function() {
- _this.changed();
- });
- this.$el.find('.searchview_extended_delete_prop').click(function () {
- _this.destroy();
- });
- this.changed();
+ return this._super().done(this.proxy('changed'));
},
changed: function() {
- var nval = this.$el.find(".searchview_extended_prop_field").val();
+ var nval = this.$(".searchview_extended_prop_field").val();
if(this.attrs.selected == null || nval != this.attrs.selected.name) {
this.select_field(_.detect(this.fields, function(x) {return x.name == nval;}));
}
@@ -1740,7 +1720,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
if(this.attrs.selected != null) {
this.value.destroy();
this.value = null;
- this.$el.find('.searchview_extended_prop_op').html('');
+ this.$('.searchview_extended_prop_op').html('');
}
this.attrs.selected = field;
if(field == null) {
@@ -1756,9 +1736,9 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
_.each(this.value.operators, function(operator) {
$('<option>', {value: operator.value})
.text(String(operator.text))
- .appendTo(self.$el.find('.searchview_extended_prop_op'));
+ .appendTo(self.$('.searchview_extended_prop_op'));
});
- var $value_loc = this.$el.find('.searchview_extended_prop_value').empty();
+ var $value_loc = this.$('.searchview_extended_prop_value').empty();
this.value.appendTo($value_loc);
},
@@ -1766,7 +1746,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
if ( this.attrs.selected == null)
return null;
var field = this.attrs.selected;
- var op = this.$el.find('.searchview_extended_prop_op')[0];
+ var op = this.$('.searchview_extended_prop_op')[0];
var operator = op.options[op.selectedIndex];
return {
label: _.str.sprintf(_t('%(field)s %(operator)s "%(value)s"'), {
diff --git a/addons/web/static/src/js/test_support.js b/addons/web/static/src/js/test_support.js
index 8e1317ba2b0..90173f89845 100644
--- a/addons/web/static/src/js/test_support.js
+++ b/addons/web/static/src/js/test_support.js
@@ -32,20 +32,20 @@ openerp.test_support = {
window.openerp.web[tested_core](oe);
var done = openerp.test_support.setup_session(oe.session);
if (nonliterals) {
- done = done.pipe(function () {
+ done = done.then(function () {
return oe.session.rpc('/tests/add_nonliterals', {
domains: nonliterals.domains || [],
contexts: nonliterals.contexts || []
- }).then(function (r) {
+ }).done(function (r) {
oe.domains = r.domains;
oe.contexts = r.contexts;
});
});
}
done.always(QUnit.start)
- .then(function () {
+ .done(function () {
conf.openerp = oe;
- }, function (e) {
+ }).fail(function (e) {
QUnit.test(title, function () {
console.error(e);
QUnit.ok(false, 'Could not obtain a session:' + e.debug);
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 67c5fa0292e..55f5b580015 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -114,13 +114,14 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
this.is_initialized = $.Deferred();
this.mutating_mutex = new $.Mutex();
- this.on_change_mutex = new $.Mutex();
+ this.on_change_list = [];
+ this.save_list = [];
this.reload_mutex = new $.Mutex();
this.__clicked_inside = false;
this.__blur_timeout = null;
this.rendering_engine = new instance.web.form.FormRenderingEngine(this);
self.set({actual_mode: self.options.initial_mode});
- this.has_been_loaded.then(function() {
+ this.has_been_loaded.done(function() {
self.on("change:actual_mode", self, self.check_actual_mode);
self.check_actual_mode();
self.on("change:actual_mode", self, self.init_pager);
@@ -274,7 +275,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var shown = this.has_been_loaded;
if (options.reload !== false) {
- shown = shown.pipe(function() {
+ shown = shown.then(function() {
if (self.dataset.index === null) {
// null index means we should start a new record
return self.on_button_new();
@@ -283,12 +284,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
fields.push('display_name');
return self.dataset.read_index(fields, {
context: { 'bin_size': true, 'future_display_name' : true }
- }).pipe(function(r) {
+ }).then(function(r) {
self.trigger('load_record', r);
});
});
}
- return shown.pipe(function() {
+ return shown.then(function() {
self._actualize_mode(options.mode || self.options.initial_mode);
self.$el.css({
opacity: '1',
@@ -326,7 +327,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
field._inhibit_on_change_flag = false;
set_values.push(result);
});
- return $.when.apply(null, set_values).pipe(function() {
+ return $.when.apply(null, set_values).then(function() {
if (!record.id) {
// New record: Second pass in order to trigger the onchanges
// respecting the fields order defined in the view
@@ -364,7 +365,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var self = this;
var keys = _.keys(this.fields_view.fields);
if (keys.length) {
- return this.dataset.default_get(keys).pipe(function(r) {
+ return this.dataset.default_get(keys).then(function(r) {
self.trigger('load_record', r);
});
}
@@ -427,7 +428,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var onchange = _.str.trim(on_change);
var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
if (!call) {
- return null;
+ throw new Error("Wrong on change format: " + onchange);
}
var method = call[1];
@@ -466,7 +467,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var splitted = field.split('.');
if (splitted.length > 1 && _.str.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
if (parent_fields === null) {
- parent_fields = self.dataset.parent_view.get_fields_values([self.dataset.child_name]);
+ parent_fields = self.dataset.parent_view.get_fields_values();
}
var p_val = parent_fields[_.str.trim(splitted[1])];
if (p_val !== undefined) {
@@ -492,38 +493,33 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
do_onchange: function(widget, processed) {
var self = this;
- return this.on_change_mutex.exec(function() {
- try {
- var response = {}, can_process_onchange = $.Deferred();
- processed = processed || [];
- processed.push(widget.name);
- var on_change = widget.node.attrs.on_change;
- if (on_change) {
- var change_spec = self.parse_on_change(on_change, widget);
- if (change_spec) {
- var ajax = {
- url: '/web/dataset/onchange',
- async: false
- };
- can_process_onchange = self.rpc(ajax, {
- model: self.dataset.model,
- method: change_spec.method,
- args: [(self.datarecord.id == null ? [] : [self.datarecord.id])].concat(change_spec.args),
- context_id: change_spec.context_index == undefined ? null : change_spec.context_index + 1
- }).then(function(r) {
- _.extend(response, r);
- });
- } else {
- console.warn("Wrong on_change format", on_change);
- }
- }
- // fail if onchange failed
- if (can_process_onchange.isRejected()) {
- return can_process_onchange;
- }
-
+ this.on_change_list = [{widget: widget, processed: processed}].concat(this.on_change_list);
+ return this._process_operations();
+ },
+ _process_onchange: function(on_change_obj) {
+ var self = this;
+ var widget = on_change_obj.widget;
+ var processed = on_change_obj.processed;
+ try {
+ var def;
+ processed = processed || [];
+ processed.push(widget.name);
+ var on_change = widget.node.attrs.on_change;
+ if (on_change) {
+ var change_spec = self.parse_on_change(on_change, widget);
+ def = self.rpc('/web/dataset/onchange', {
+ model: self.dataset.model,
+ method: change_spec.method,
+ args: [(self.datarecord.id == null ? [] : [self.datarecord.id])].concat(change_spec.args),
+ context_id: change_spec.context_index == undefined ? null : change_spec.context_index + 1
+ });
+ } else {
+ def = $.when({});
+ }
+ return def.then(function(response) {
if (widget.field['change_default']) {
- var fieldname = widget.name, value_;
+ var fieldname = widget.name
+ var value_;
if (response.value && (fieldname in response.value)) {
// Use value from onchange if onchange executed
value_ = response.value[fieldname];
@@ -534,15 +530,14 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var condition = fieldname + '=' + value_;
if (value_) {
- can_process_onchange = self.rpc({
- url: '/web/dataset/call',
- async: false
- }, {
+ return self.rpc('/web/dataset/call', {
model: 'ir.values',
method: 'get_defaults',
args: [self.model, condition]
}).then(function (results) {
- if (!results.length) { return; }
+ if (!results.length) {
+ return response;
+ }
if (!response.value) {
response.value = {};
}
@@ -551,20 +546,19 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var triplet = results[i];
response.value[triplet[1]] = triplet[2];
}
+ return response;
});
}
}
- if (can_process_onchange.isRejected()) {
- return can_process_onchange;
- }
-
+ return response;
+ }).then(function(response) {
return self.on_processed_onchange(response, processed);
- } catch(e) {
- console.error(e);
- instance.webclient.crashmanager.show_message(e);
- return $.Deferred().reject();
- }
- });
+ });
+ } catch(e) {
+ console.error(e);
+ instance.webclient.crashmanager.show_message(e);
+ return $.Deferred().reject();
+ }
},
on_processed_onchange: function(result, processed) {
try {
@@ -600,6 +594,38 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.Deferred().reject();
}
},
+ _process_operations: function() {
+ var self = this;
+ return this.mutating_mutex.exec(function() {
+ function iterate() {
+ var on_change_obj = self.on_change_list.shift();
+ if (on_change_obj) {
+ return self._process_onchange(on_change_obj).then(function() {
+ return iterate();
+ });
+ }
+ var defs = [];
+ _.each(self.fields, function(field) {
+ defs.push(field.commit_value());
+ });
+ var args = _.toArray(arguments);
+ return $.when.apply($, defs).then(function() {
+ if (self.on_change_list.length !== 0) {
+ return iterate();
+ }
+ var save_obj = self.save_list.pop();
+ if (save_obj) {
+ return self._process_save(save_obj).then(function() {
+ save_obj.ret = _.toArray(arguments);
+ return iterate();
+ });
+ }
+ return $.when();
+ });
+ };
+ return iterate();
+ });
+ },
_internal_set_values: function(values, exclude) {
exclude = exclude || [];
for (var f in values) {
@@ -623,7 +649,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
set_values: function(values) {
var self = this;
- return this.on_change_mutex.exec(function() {
+ return this.mutating_mutex.exec(function() {
self._internal_set_values(values);
});
},
@@ -693,7 +719,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
on_button_save: function() {
var self = this;
- return this.save().then(function(result) {
+ return this.save().done(function(result) {
self.trigger("save", result);
self.to_view_mode();
});
@@ -713,7 +739,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
on_button_new: function() {
var self = this;
this.to_edit_mode();
- return $.when(this.has_been_loaded).pipe(function() {
+ return $.when(this.has_been_loaded).then(function() {
if (self.can_be_discarded()) {
return self.load_defaults();
}
@@ -728,29 +754,24 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
on_button_duplicate: function() {
var self = this;
- var def = $.Deferred();
- $.when(this.has_been_loaded).then(function() {
- self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
- return self.record_created(new_id);
- }).then(function() {
- return self.to_edit_mode();
- }).then(function() {
- def.resolve();
+ return this.has_been_loaded.then(function() {
+ return self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
+ self.record_created(new_id);
+ self.to_edit_mode();
});
});
- return def.promise();
},
on_button_delete: function() {
var self = this;
var def = $.Deferred();
- $.when(this.has_been_loaded).then(function() {
+ this.has_been_loaded.done(function() {
if (self.datarecord.id && confirm(_t("Do you really want to delete this record?"))) {
- self.dataset.unlink([self.datarecord.id]).then(function() {
+ self.dataset.unlink([self.datarecord.id]).done(function() {
self.execute_pager_action('next');
def.resolve();
});
} else {
- $.async_when().then(function () {
+ $.async_when().done(function () {
def.reject();
})
}
@@ -777,8 +798,16 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
*/
save: function(prepend_on_create) {
var self = this;
- return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
- try {
+ var save_obj = {prepend_on_create: prepend_on_create, ret: null};
+ this.save_list.push(save_obj);
+ return this._process_operations().then(function() {
+ return $.when.apply($, save_obj.ret);
+ });
+ },
+ _process_save: function(save_obj) {
+ var self = this;
+ var prepend_on_create = save_obj.prepend_on_create;
+ try {
var form_invalid = false,
values = {},
first_invalid_field = null;
@@ -807,7 +836,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var save_deferral;
if (!self.datarecord.id) {
// Creation save
- save_deferral = self.dataset.create(values).pipe(function(r) {
+ save_deferral = self.dataset.create(values).then(function(r) {
return self.record_created(r, prepend_on_create);
}, null);
} else if (_.isEmpty(values) && ! self.force_dirty) {
@@ -816,17 +845,16 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
} else {
self.force_dirty = false;
// Write save
- save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
+ save_deferral = self.dataset.write(self.datarecord.id, values, {}).then(function(r) {
return self.record_saved(r);
}, null);
}
return save_deferral;
}
- } catch (e) {
- console.error(e);
- return $.Deferred().reject();
- }
- });});
+ } catch (e) {
+ console.error(e);
+ return $.Deferred().reject();
+ }
},
on_invalid: function() {
var warnings = _(this.fields).chain()
@@ -851,7 +879,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.trigger('record_saved', r);
return $.Deferred().reject();
} else {
- return $.when(this.reload()).pipe(function () {
+ return $.when(this.reload()).then(function () {
self.trigger('record_saved', r);
return r;
});
@@ -890,7 +918,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.sidebar.do_attachement_update(this.dataset, this.datarecord.id);
}
//openerp.log("The record has been created with id #" + this.datarecord.id);
- return $.when(this.reload()).pipe(function () {
+ return $.when(this.reload()).then(function () {
self.trigger('record_created', r);
return _.extend(r, {created: true});
});
@@ -917,7 +945,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
'bin_size': true,
'future_display_name': true
}
- }).pipe(function(r) {
+ }).then(function(r) {
self.trigger('load_record', r);
});
}
@@ -928,15 +956,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return obj instanceof instance.web.form.FormWidget;
});
},
- get_fields_values: function(blacklist) {
- blacklist = blacklist || [];
+ get_fields_values: function() {
var values = {};
var ids = this.get_selected_ids();
values["id"] = ids.length > 0 ? ids[0] : false;
_.each(this.fields, function(value_, key) {
- if (_.include(blacklist, key)) {
- return;
- }
values[key] = value_.get_value();
});
return values;
@@ -947,7 +971,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
recursive_save: function() {
var self = this;
- return $.when(this.save()).pipe(function(res) {
+ return $.when(this.save()).then(function(res) {
if (self.dataset.parent_view)
return self.dataset.parent_view.recursive_save();
});
@@ -957,7 +981,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var pre = $.when();
if (self.dataset.parent_view)
pre = self.dataset.parent_view.recursive_reload();
- return pre.pipe(function() {
+ return pre.then(function() {
return self.reload();
});
},
@@ -978,7 +1002,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return true;
},
sidebar_context: function () {
- return this.save().pipe(_.bind(function() {return this.get_fields_values();}, this));
+ return this.save().then(_.bind(function() {return this.get_fields_values();}, this));
},
open_defaults_dialog: function () {
var self = this;
@@ -1054,7 +1078,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
all_users,
true,
condition || false
- ]).then(function () { d.close(); });
+ ]).done(function () { d.close(); });
}}
]
});
@@ -1097,9 +1121,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
compute_domain: function(expression) {
return instance.web.form.compute_domain(expression, this.fields);
},
- _build_view_fields_values: function(blacklist) {
+ _build_view_fields_values: function() {
var a_dataset = this.dataset;
- var fields_values = this.get_fields_values(blacklist);
+ var fields_values = this.get_fields_values();
var active_id = a_dataset.ids[a_dataset.index];
_.extend(fields_values, {
active_id: active_id || false,
@@ -1108,13 +1132,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
parent: {}
});
if (a_dataset.parent_view) {
- fields_values.parent = a_dataset.parent_view.get_fields_values([a_dataset.child_name]);
+ fields_values.parent = a_dataset.parent_view.get_fields_values();
}
return fields_values;
},
- build_eval_context: function(blacklist) {
+ build_eval_context: function() {
var a_dataset = this.dataset;
- return new instance.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values(blacklist));
+ return new instance.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values());
},
});
@@ -1810,7 +1834,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
* Builds a new context usable for operations related to fields by merging
* the fields'context with the action's context.
*/
- build_context: function(blacklist) {
+ build_context: function() {
// only use the model's context if there is not context on the node
var v_context = this.node.attrs.context;
if (! v_context) {
@@ -1818,7 +1842,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.field_manager.build_eval_context(blacklist);
+ var fields_values = this.field_manager.build_eval_context();
v_context = new instance.web.CompoundContext(v_context).set_eval_context(fields_values);
}
return v_context;
@@ -1883,7 +1907,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
}
},
{text: _t("Ok"), click: function() {
- self.on_confirmed().then(function() {
+ self.on_confirmed().done(function() {
def.resolve();
});
$(this).dialog("close");
@@ -1898,7 +1922,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
};
if (!this.node.attrs.special) {
this.view.force_dirty = true;
- return this.view.recursive_save().pipe(exec_action);
+ return this.view.recursive_save().then(exec_action);
} else {
return exec_action();
}
@@ -1991,6 +2015,11 @@ instance.web.form.FieldInterface = {
* Called when the translate button is clicked.
*/
on_translate: function() {},
+ /**
+ This method is called by the form view before reading on_change values and before saving. It tells
+ the field to save its value before reading it using get_value(). Must return a promise.
+ */
+ commit_value: function() {},
};
/**
@@ -2117,7 +2146,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
on_translate: function() {
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) {
+ return trans.call_button('translate_fields', [this.view.dataset.model, this.view.datarecord.id, this.name, this.view.dataset.get_context()]).done(function(r) {
self.do_action(r);
});
},
@@ -2134,7 +2163,10 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
}
this.$el.attr('style', style);
this.$el.css('minHeight', height);
- }
+ },
+ commit_value: function() {
+ return $.when();
+ },
});
/**
@@ -2228,6 +2260,13 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we
},
focus: function() {
this.$('input:first').focus();
+ },
+ set_dimensions: function (height, width) {
+ this._super(height, width);
+ this.$('input').css({
+ height: height,
+ width: width
+ });
}
});
@@ -2454,6 +2493,10 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc
if (this.datewidget && this.datewidget.$input) {
this.datewidget.$input.focus();
}
+ },
+ set_dimensions: function (height, width) {
+ this._super(height, width);
+ this.datewidget.$input.css('height', height);
}
});
@@ -2514,7 +2557,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
this.$textarea.focus();
},
set_dimensions: function (height, width) {
- this._super();
+ this._super(height, width);
this.$textarea.css({
width: width,
minHeight: height
@@ -2539,7 +2582,7 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc
if (! this.get("effective_readonly")) {
self._updating_editor = false;
this.$textarea = this.$el.find('textarea');
- var width = ((this.node.attrs || {}).editor_width || 468);
+ var width = ((this.node.attrs || {}).editor_width || '100%');
var height = ((this.node.attrs || {}).editor_height || 250);
this.$textarea.cleditor({
width: width, // width not including margins, borders or padding
@@ -2676,6 +2719,13 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
},
focus: function() {
this.$el.find('select:first').focus();
+ },
+ set_dimensions: function (height, width) {
+ this._super(height, width);
+ this.$('select').css({
+ height: height,
+ width: width
+ });
}
});
@@ -2732,7 +2782,7 @@ instance.web.form.CompletionFieldMixin = {
return this.orderer.add(dataset.name_search(
search_val, new instance.web.CompoundDomain(self.build_domain(), [["id", "not in", blacklist]]),
- 'ilike', this.limit + 1, self.build_context())).pipe(function(data) {
+ 'ilike', this.limit + 1, self.build_context())).then(function(data) {
self.last_search = data;
// possible selections for the m2o
var values = _.map(data, function(x) {
@@ -2751,7 +2801,7 @@ instance.web.form.CompletionFieldMixin = {
values.push({
label: _t("Search More..."),
action: function() {
- dataset.name_search(search_val, self.build_domain(), 'ilike', false).then(function(data) {
+ dataset.name_search(search_val, self.build_domain(), 'ilike', false).done(function(data) {
self._search_create_popup("search", data);
});
},
@@ -2792,7 +2842,7 @@ instance.web.form.CompletionFieldMixin = {
};
if (self.options.quick_create === undefined || self.options.quick_create) {
new instance.web.DataSet(this, this.field.relation, self.build_context())
- .name_create(name).then(function(data) {
+ .name_create(name).done(function(data) {
self.add_id(data[0]);
}).fail(function(error, event) {
event.preventDefault();
@@ -2967,7 +3017,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
self.uned_def = $.Deferred();
var ed_delay = 200;
var ed_duration = 15000;
- var anyoneLoosesFocus = function() {
+ var anyoneLoosesFocus = function (e) {
var used = false;
if (self.floating) {
if (self.last_search.length > 0) {
@@ -2989,14 +3039,17 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
self.ed_def.reject();
self.uned_def.reject();
self.ed_def = $.Deferred();
- self.ed_def.then(function() {
+ self.ed_def.done(function() {
self.show_error_displayer();
+ ignore_blur = false;
+ self.trigger('focused');
});
+ ignore_blur = true;
setTimeout(function() {
self.ed_def.resolve();
self.uned_def.reject();
self.uned_def = $.Deferred();
- self.uned_def.then(function() {
+ self.uned_def.done(function() {
self.hide_error_displayer();
});
setTimeout(function() {self.uned_def.resolve();}, ed_duration);
@@ -3026,7 +3079,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
// autocomplete
this.$input.autocomplete({
source: function(req, resp) {
- self.get_search_result(req.term).then(function(result) {
+ self.get_search_result(req.term).done(function(result) {
resp(result);
});
},
@@ -3077,7 +3130,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
}
if (! no_recurse) {
var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.build_context());
- dataset.name_get([self.get("value")]).then(function(data) {
+ dataset.name_get([self.get("value")]).done(function(data) {
self.display_value["" + self.get("value")] = data[0][1];
self.render_value(true);
});
@@ -3110,7 +3163,6 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
type: 'ir.actions.act_window',
res_model: self.field.relation,
res_id: self.get("value"),
- context: self.build_context(),
views: [[false, 'form']],
target: 'current'
});
@@ -3156,6 +3208,62 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
this.ed_def.reject();
return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments);
},
+ set_dimensions: function (height, width) {
+ this._super(height, width);
+ this.$input.css('height', height);
+ }
+});
+
+instance.web.form.Many2OneButton = instance.web.form.AbstractField.extend({
+ template: 'Many2OneButton',
+ init: function(field_manager, node) {
+ this._super.apply(this, arguments);
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.set_button();
+ },
+ set_button: function() {
+ var self = this;
+ if (this.$button) {
+ this.$button.remove();
+ }
+ var options = {};
+ try {
+ options = py.eval(this.node.attrs.options);
+ } catch (e) {}
+ if (options.label) {
+ this.string = this.get('value') ? _t(options.label.edit) : _t(options.label.create);
+ } else {
+ this.string = '';
+ }
+ this.node.attrs.icon = this.get('value') ? '/web/static/src/img/icons/gtk-yes.png' : '/web/static/src/img/icons/gtk-no.png';
+ this.$button = $(QWeb.render('WidgetButton', {'widget': this}));
+ this.$el.append(this.$button);
+ this.$button.on('click', self.on_click);
+ },
+ on_click: function(ev) {
+ var self = this;
+ this.popup = new instance.web.form.FormOpenPopup(this);
+ this.popup.show_element(
+ this.field.relation,
+ this.get('value'),
+ this.build_context(),
+ {title: this.string}
+ );
+ this.popup.on('create_completed write_completed', self, function(r) {
+ self.set_value(r);
+ });
+ },
+ set_value: function(value_) {
+ var self = this;
+ if (value_ instanceof Array) {
+ value_ = value_[0];
+ }
+ value_ = value_ || false;
+ this.set('value', value_);
+ this.set_button();
+ },
});
/*
@@ -3231,11 +3339,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var self = this;
self.load_views();
- this.is_loaded.then(function() {
+ this.is_loaded.done(function() {
self.on("change:effective_readonly", self, function() {
- self.is_loaded = self.is_loaded.pipe(function() {
+ self.is_loaded = self.is_loaded.then(function() {
self.viewmanager.destroy();
- return $.when(self.load_views()).then(function() {
+ return $.when(self.load_views()).done(function() {
self.reload_current_view();
});
});
@@ -3245,10 +3353,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
this.reload_current_view();
},
trigger_on_change: function() {
- var tmp = this.doing_on_change;
- this.doing_on_change = true;
this.trigger('changed_value');
- this.doing_on_change = tmp;
},
load_views: function() {
var self = this;
@@ -3308,10 +3413,10 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
this.viewmanager = new instance.web.form.One2ManyViewManager(this, this.dataset, views, {});
this.viewmanager.o2m = self;
- var once = $.Deferred().then(function() {
+ var once = $.Deferred().done(function() {
self.init_form_last_update.resolve();
});
- var def = $.Deferred().then(function() {
+ var def = $.Deferred().done(function() {
self.initial_is_loaded.resolve();
});
this.viewmanager.on("controller_inited", self, function(view_type, controller) {
@@ -3322,7 +3427,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
e.cancel = true;
});
_(controller.columns).find(function (column) {
- if (!column instanceof instance.web.list.Handle) {
+ if (!(column instanceof instance.web.list.Handle)) {
return false;
}
column.modifiers.invisible = true;
@@ -3343,22 +3448,22 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
def.resolve();
});
this.viewmanager.on("switch_mode", self, function(n_mode, b, c, d, e) {
- $.when(self.save_any_view()).then(function() {
+ $.when(self.save_any_view()).done(function() {
if (n_mode === "list") {
- $.async_when().then(function() {
+ $.async_when().done(function() {
self.reload_current_view();
});
}
});
});
- $.async_when().then(function () {
+ $.async_when().done(function () {
self.viewmanager.appendTo(self.$el);
});
return def;
},
reload_current_view: function() {
var self = this;
- return self.is_loaded = self.is_loaded.pipe(function() {
+ return self.is_loaded = self.is_loaded.then(function() {
var active_view = self.viewmanager.active_view;
var view = self.viewmanager.views[active_view].controller;
if(active_view === "list") {
@@ -3370,7 +3475,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var act = function() {
return view.do_show();
};
- self.form_last_update = self.form_last_update.pipe(act, act);
+ self.form_last_update = self.form_last_update.then(act, act);
return self.form_last_update;
} else if (view.do_search) {
return view.do_search(self.build_domain(), self.dataset.get_context(), []);
@@ -3443,7 +3548,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var self = this;
if (!this.dataset)
return [];
- this.save_any_view();
var val = this.dataset.delete_all ? [commands.delete_all()] : [];
val = val.concat(_.map(this.dataset.ids, function(id) {
var alter_order = _.detect(self.dataset.to_create, function(x) {return x.id === id;});
@@ -3460,33 +3564,24 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
this.dataset.to_delete, function(x) {
return commands['delete'](x.id);}));
},
+ commit_value: function() {
+ return this.save_any_view();
+ },
save_any_view: function() {
- if (this.doing_on_change)
- return false;
- return this.session.synchronized_mode(_.bind(function() {
- if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view &&
- this.viewmanager.views[this.viewmanager.active_view] &&
- this.viewmanager.views[this.viewmanager.active_view].controller) {
- var view = this.viewmanager.views[this.viewmanager.active_view].controller;
- if (this.viewmanager.active_view === "form") {
- if (!view.is_initialized.isResolved()) {
- return false;
- }
- var res = $.when(view.save());
- if (!res.isResolved() && !res.isRejected()) {
- console.warn("Asynchronous get_value() is not supported in form view.");
- }
- return res;
- } else if (this.viewmanager.active_view === "list") {
- var res = $.when(view.ensure_saved());
- if (!res.isResolved() && !res.isRejected()) {
- console.warn("Asynchronous get_value() is not supported in list view.");
- }
- return res;
+ if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view &&
+ this.viewmanager.views[this.viewmanager.active_view] &&
+ this.viewmanager.views[this.viewmanager.active_view].controller) {
+ var view = this.viewmanager.views[this.viewmanager.active_view].controller;
+ if (this.viewmanager.active_view === "form") {
+ if (!view.is_initialized.state() === 'resolved') {
+ return $.when(false);
}
+ return $.when(view.save());
+ } else if (this.viewmanager.active_view === "list") {
+ return $.when(view.ensure_saved());
}
- return false;
- }, this));
+ }
+ return $.when(false);
},
is_syntax_valid: function() {
if (! this.viewmanager || ! this.viewmanager.views[this.viewmanager.active_view])
@@ -3527,13 +3622,13 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(), {
title: _t("Open: ") + self.o2m.string,
create_function: function(data) {
- return self.o2m.dataset.create(data).then(function(r) {
+ return self.o2m.dataset.create(data).done(function(r) {
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
self.o2m.dataset.trigger("dataset_changed", r);
});
},
write_function: function(id, data, options) {
- return self.o2m.dataset.write(id, data, {}).then(function() {
+ return self.o2m.dataset.write(id, data, {}).done(function() {
self.o2m.reload_current_view();
});
},
@@ -3554,7 +3649,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
instance.web.form.One2ManyDataSet = instance.web.BufferedDataSet.extend({
get_context: function() {
- this.context = this.o2m.build_context([this.o2m.name]);
+ this.context = this.o2m.build_context();
return this.context;
}
});
@@ -3618,10 +3713,10 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
initial_view: "form",
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
create_function: function(data, callback, error_callback) {
- return self.o2m.dataset.create(data).then(function(r) {
+ return self.o2m.dataset.create(data).done(function(r) {
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
self.o2m.dataset.trigger("dataset_changed", r);
- }).then(callback, error_callback);
+ }).done(callback).fail(error_callback);
},
read_function: function() {
return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
@@ -3644,7 +3739,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(), {
title: _t("Open: ") + self.o2m.string,
write_function: function(id, data) {
- return self.o2m.dataset.write(id, data, {}).then(function() {
+ return self.o2m.dataset.write(id, data, {}).done(function() {
self.o2m.reload_current_view();
});
},
@@ -3667,12 +3762,12 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
}
var parent_form = this.o2m.view;
var self = this;
- this.ensure_saved().pipe(function () {
+ this.ensure_saved().then(function () {
if (parent_form)
return parent_form.save();
else
return $.when();
- }).then(function () {
+ }).done(function () {
self.handle_button(name, id, callback);
});
},
@@ -3709,7 +3804,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
}
// FIXME: why isn't there an API for this?
if (this.editor.form.$el.hasClass('oe_form_dirty')) {
- this.save_edition();
+ this.ensure_saved();
return;
}
this.cancel_edition();
@@ -3732,7 +3827,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
ids.splice(false_id_index, 1);
next = this.cancel_edition(true);
}
- return next.pipe(function () {
+ return next.then(function () {
// wheeee
var confirm = window.confirm;
window.confirm = function () { return true; };
@@ -3794,7 +3889,7 @@ instance.web.form.One2ManyList = instance.web.ListView.List.extend({
clearTimeout(self.view.editor.form.__blur_timeout);
self.view.editor.form.__blur_timeout = false;
}
- self.view.ensure_saved().then(function () {
+ self.view.ensure_saved().done(function () {
self.view.do_add_record();
});
}));
@@ -3815,7 +3910,7 @@ instance.web.form.One2ManyFormView = instance.web.FormView.extend({
this._super(data);
var self = this;
this.$buttons.find('button.oe_form_button_create').click(function() {
- self.save().then(self.on_button_new);
+ self.save().done(self.on_button_new);
});
},
do_notify_change: function() {
@@ -3828,11 +3923,11 @@ instance.web.form.One2ManyFormView = instance.web.FormView.extend({
});
var lazy_build_o2m_kanban_view = function() {
-if (! instance.web_kanban || instance.web.form.One2ManyKanbanView)
- return;
-instance.web.form.One2ManyKanbanView = instance.web_kanban.KanbanView.extend({
-});
-}
+ if (! instance.web_kanban || instance.web.form.One2ManyKanbanView)
+ return;
+ instance.web.form.One2ManyKanbanView = instance.web_kanban.KanbanView.extend({
+ });
+};
instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, {
template: "FieldMany2ManyTags",
@@ -3847,7 +3942,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
if (this.get("effective_readonly"))
return;
var self = this;
- self.$text = $("textarea", this.$el);
+ self.$text = this.$("textarea");
self.$text.textext({
plugins : 'tags arrow autocomplete',
autocomplete: {
@@ -3871,9 +3966,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
},
tags: {
isTagAllowed: function(tag) {
- if (! tag.name)
- return false;
- return true;
+ return !!tag.name;
+
},
removeTag: function(tag) {
var id = tag.data("id");
@@ -3893,7 +3987,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
}).bind('getSuggestions', function(e, data) {
var _this = this;
var str = !!data ? data.query || '' : '';
- self.get_search_result(str).then(function(result) {
+ self.get_search_result(str).done(function(result) {
self.search_result = result;
$(_this).trigger('setSuggestions', {result : _.map(result, function(el, i) {
return _.extend(el, {index:i});
@@ -3905,7 +3999,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
self._drop_shown = true;
});
self.tags = self.$text.textext()[0].tags();
- $("textarea", this.$el).focusout(function() {
+ self.$text.focusout(function() {
self.$text.trigger("setInputData", "");
}).keydown(function(e) {
if (e.which === $.ui.keyCode.TAB && self._drop_shown) {
@@ -3930,8 +4024,10 @@ 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.build_context());
- var values = self.get("value")
+ var values = self.get("value");
var handle_names = function(data) {
+ if (self.isDestroyed())
+ return;
var indexed = {};
_.each(data, function(el) {
indexed[el[0]] = el;
@@ -3939,14 +4035,14 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
data = _.map(values, function(el) { return indexed[el]; });
if (! self.get("effective_readonly")) {
self.tags.containerElement().children().remove();
- $("textarea", self.$el).css("padding-left", "3px");
+ self.$('textarea').css("padding-left", "3px");
self.tags.addTags(_.map(data, function(el) {return {name: el[1], id:el[0]};}));
} else {
self.$el.html(QWeb.render("FieldMany2ManyTag", {elements: data}));
}
};
if (! values || values.length > 0) {
- this._display_orderer.add(dataset.name_get(values)).then(handle_names);
+ this._display_orderer.add(dataset.name_get(values)).done(handle_names);
} else {
handle_names([]);
}
@@ -3983,11 +4079,11 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
var self = this;
self.load_view();
- this.is_loaded.then(function() {
+ this.is_loaded.done(function() {
self.on("change:effective_readonly", self, function() {
- self.is_loaded = self.is_loaded.pipe(function() {
+ self.is_loaded = self.is_loaded.then(function() {
self.list_view.destroy();
- return $.when(self.load_view()).then(function() {
+ return $.when(self.load_view()).done(function() {
self.render_value();
});
});
@@ -4028,7 +4124,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
self.initial_is_loaded.resolve();
loaded.resolve();
});
- $.async_when().then(function () {
+ $.async_when().done(function () {
self.list_view.appendTo(self.$el);
});
return loaded;
@@ -4036,7 +4132,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
render_value: function() {
var self = this;
this.dataset.set_ids(this.get("value"));
- this.is_loaded = this.is_loaded.pipe(function() {
+ this.is_loaded = this.is_loaded.then(function() {
return self.list_view.reload_content();
});
},
@@ -4097,7 +4193,7 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in
if (! this.m2m_field.options.reload_on_button) {
return _sup(name, id, callback);
} else {
- return this.m2m_field.view.save().pipe(function() {
+ return this.m2m_field.view.save().then(function() {
return _sup(name, id, function() {
self.m2m_field.view.reload();
});
@@ -4128,11 +4224,11 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
var self = this;
self.load_view();
- this.is_loaded.then(function() {
+ this.is_loaded.done(function() {
self.on("change:effective_readonly", self, function() {
- self.is_loaded = self.is_loaded.pipe(function() {
+ self.is_loaded = self.is_loaded.then(function() {
self.kanban_view.destroy();
- return $.when(self.load_view()).then(function() {
+ return $.when(self.load_view()).done(function() {
self.render_value();
});
});
@@ -4169,7 +4265,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
loaded.resolve();
});
this.kanban_view.on('switch_mode', this, this.open_popup);
- $.async_when().then(function () {
+ $.async_when().done(function () {
self.kanban_view.appendTo(self.$el);
});
return loaded;
@@ -4177,7 +4273,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
render_value: function() {
var self = this;
this.dataset.set_ids(this.get("value"));
- this.is_loaded = this.is_loaded.pipe(function() {
+ this.is_loaded = this.is_loaded.then(function() {
return self.kanban_view.do_search(self.build_domain(), self.dataset.get_context(), []);
});
},
@@ -4213,7 +4309,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
pop.show_element(self.field.relation, id, self.build_context(), {
title: _t("Open: ") + self.string,
write_function: function(id, data, options) {
- return self.dataset.write(id, data, {}).then(function() {
+ return self.dataset.write(id, data, {}).done(function() {
self.render_value();
});
},
@@ -4286,7 +4382,7 @@ instance.web.form.Many2ManyQuickCreate = instance.web.Widget.extend({
}).bind('getSuggestions', function(e, data) {
var _this = this;
var str = !!data ? data.query || '' : '';
- self.m2m.get_search_result(str).then(function(result) {
+ self.m2m.get_search_result(str).done(function(result) {
self.search_result = result;
$(_this).trigger('setSuggestions', {result : _.map(result, function(el, i) {
return _.extend(el, {index:i});
@@ -4341,14 +4437,15 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
this.dataset.read_function = this.options.read_function;
this.dataset.create_function = function(data, sup) {
var fct = self.options.create_function || sup;
- return fct.call(this, data).then(function(r) {
+ return fct.call(this, data).done(function(r) {
+ self.trigger('create_completed saved', r);
self.created_elements.push(r);
});
};
this.dataset.write_function = function(id, data, options, sup) {
var fct = self.options.write_function || sup;
- return fct.call(this, id, data, options).then(function() {
- self.trigger('write_completed');
+ return fct.call(this, id, data, options).done(function() {
+ self.trigger('write_completed saved');
});
};
this.dataset.parent_view = this.options.parent_view;
@@ -4396,7 +4493,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
}));
var $snbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save-new");
$snbutton.click(function() {
- $.when(self.view_form.save()).then(function() {
+ $.when(self.view_form.save()).done(function() {
self.view_form.reload_mutex.exec(function() {
self.view_form.on_button_new();
});
@@ -4404,7 +4501,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
});
var $sbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save");
$sbutton.click(function() {
- $.when(self.view_form.save()).then(function() {
+ $.when(self.view_form.save()).done(function() {
self.view_form.reload_mutex.exec(function() {
self.check_exit();
});
@@ -4425,10 +4522,14 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
this.select_elements(this.created_elements);
this.created_elements = [];
}
+ this.trigger('closed');
this.destroy();
},
destroy: function () {
- this.$el.dialog('close');
+ this.trigger('closed');
+ if (this.$el.is(":data(dialog)")) {
+ this.$el.dialog('close');
+ }
this._super();
},
});
@@ -4478,7 +4579,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
self.rpc('/web/session/eval_domain_and_context', {
domains: [],
contexts: [this.context]
- }).then(function (results) {
+ }).done(function (results) {
var search_defaults = {};
_.each(results.context, function (value_, key) {
var match = /^search_default_(.*)$/.exec(key);
@@ -4520,9 +4621,9 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
e.cancel = true;
});
self.view_list.popup = self;
- self.view_list.appendTo($(".oe_popup_list", self.$el)).pipe(function() {
+ self.view_list.appendTo($(".oe_popup_list", self.$el)).then(function() {
self.view_list.do_show();
- }).pipe(function() {
+ }).then(function() {
self.searchview.do_search();
});
self.view_list.on("list_view_loaded", self, function() {
@@ -4550,7 +4651,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
domains: domains || [],
contexts: contexts || [],
group_by_seq: groupbys || []
- }).then(function (results) {
+ }).done(function (results) {
self.view_list.do_search(results.domain, results.context, results.group_by);
});
},
@@ -4831,6 +4932,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
template: 'FieldBinaryImage',
+ placeholder: "/web/static/src/img/placeholder.png",
render_value: function() {
var self = this;
var url;
@@ -4844,7 +4946,7 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' +
this.view.dataset.model +'&id=' + id + '&field=' + field + '&t=' + (new Date().getTime());
} else {
- url = "/web/static/src/img/placeholder.png";
+ url = this.placeholder;
}
var $img = $(QWeb.render("FieldBinaryImage-img", { widget: this, url: url }));
this.$el.find('> img').remove();
@@ -4857,10 +4959,10 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
$img.css("margin-left", "" + (self.options.size[0] - $img.width()) / 2 + "px");
$img.css("margin-top", "" + (self.options.size[1] - $img.height()) / 2 + "px");
});
- },
- on_file_change: function() {
- this.render_value();
- this._super.apply(this, arguments);
+ $img.on('error', function() {
+ $img.attr('src', self.placeholder);
+ instance.webclient.notification.warn(_t("Image"), _t("Could not display the selected image."));
+ });
},
on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
this.internal_set_value(file_base64);
@@ -4875,6 +4977,132 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
}
});
+/**
+ * Widget for (one2many field) to upload one or more file in same time and display in list.
+ * The user can delete his files.
+ * Options on attribute ; "blockui" {Boolean} block the UI or not
+ * during the file is uploading
+ */
+instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({
+ template: "FieldBinaryFileUploader",
+ init: function(field_manager, node) {
+ this._super(field_manager, node);
+ this.field_manager = field_manager;
+ this.node = node;
+ if(this.field.type != "one2many" || this.field.relation != 'ir.attachment') {
+ throw "The type of the field '"+this.field.string+"' must be a one2many field with a relation to 'ir.attachment' model.";
+ }
+ this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment');
+ this.fileupload_id = _.uniqueId('oe_fileupload_temp');
+ $(window).on(this.fileupload_id, _.bind(this.on_file_loaded, this));
+ },
+ start: function() {
+ this._super(this);
+ this.$el.on('change', 'input.oe_form_binary_file', this.on_file_change );
+ },
+ get_value: function() {
+ return _.map(this.get('value'), function (value) { return commands.link_to( value.id ); });
+ },
+ get_file_url: function (attachment) {
+ return instance.origin + '/web/binary/saveas?session_id=' + this.session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
+ },
+ render_value: function () {
+ var render = $(instance.web.qweb.render('FieldBinaryFileUploader.files', {'widget': this}));
+ render.on('click', '.oe_delete', _.bind(this.on_file_delete, this));
+ this.$('.oe_placeholder_files, .oe_attachments').replaceWith( render );
+
+ // reinit input type file
+ var $input = this.$('input.oe_form_binary_file');
+ $input.after($input.clone(true)).remove();
+ this.$(".oe_fileupload").show();
+ },
+ on_file_change: function (event) {
+ event.stopPropagation();
+ var self = this;
+ var $target = $(event.target);
+ if ($target.val() !== '') {
+
+ var filename = $target.val().replace(/.*[\\\/]/,'');
+
+ // if the files is currently uploded, don't send again
+ if( !isNaN(_.find(this.get('value'), function (file) { return (file.filename || file.name) == filename && file.upload; } )) ) {
+ return false;
+ }
+
+ // block UI or not
+ if(this.node.attrs.blockui) {
+ instance.web.blockUI();
+ }
+
+ // if the files exits for this answer, delete the file before upload
+ var files = _.filter(this.get('value'), function (file) {
+ if((file.filename || file.name) == filename) {
+ self.ds_file.unlink([file.id]);
+ return false;
+ } else {
+ return true;
+ }
+ });
+
+ // TODO : unactivate send on wizard and form
+
+ // submit file
+ this.$('form.oe_form_binary_form').submit();
+ this.$(".oe_fileupload").hide();
+
+ // add file on result
+ files.push({
+ 'id': 0,
+ 'name': filename,
+ 'filename': filename,
+ 'url': '',
+ 'upload': true
+ });
+
+ this.set({'value': files});
+ }
+ },
+ on_file_loaded: function (event, result) {
+ // unblock UI
+ if(this.node.attrs.blockui) {
+ instance.web.unblockUI();
+ }
+
+ // TODO : activate send on wizard and form
+
+ var files = this.get('value');
+ for(var i in files){
+ if(files[i].filename == result.filename && files[i].upload) {
+ files[i] = {
+ 'id': result.id,
+ 'name': result.name,
+ 'filename': result.filename,
+ 'url': this.get_file_url(result)
+ };
+ }
+ }
+
+ this.set({'value': files});
+ this.render_value()
+ },
+ on_file_delete: function (event) {
+ event.stopPropagation();
+ var file_id=$(event.target).data("id");
+ if (file_id) {
+ var files=[];
+ for(var i in this.get('value')){
+ if(file_id != this.get('value')[i].id){
+ files.push(this.get('value')[i]);
+ }
+ else {
+ this.ds_file.unlink([file_id]);
+ }
+ }
+ this.set({'value': files});
+ }
+ },
+});
+
instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
template: "FieldStatus",
init: function(field_manager, node) {
@@ -4900,7 +5128,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
},
render_value: function() {
var self = this;
- self.get_selection().then(function() {
+ self.get_selection().done(function() {
var content = QWeb.render("FieldStatus.content", {widget: self});
self.$el.html(content);
var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}");
@@ -4924,7 +5152,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
domain = new instance.web.CompoundDomain(['|'], self.build_domain(), [['id', '=', self.get('value')]]);
}
var ds = new instance.web.DataSetSearch(this, this.field.relation, self.build_context(), domain);
- return ds.read_slice(['name'], {}).pipe(function (records) {
+ return ds.read_slice(['name'], {}).then(function (records) {
for(var i = 0; i < records.length; i++) {
self.selection.push([records[i].id, records[i].name]);
}
@@ -4948,10 +5176,10 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
var $li = $(ev.currentTarget);
var val = parseInt($li.data("id"));
if (val != self.get('value')) {
- this.view.recursive_save().then(function() {
+ this.view.recursive_save().done(function() {
var change = {};
change[self.name] = val;
- self.view.dataset.write(self.view.datarecord.id, change).then(function() {
+ self.view.dataset.write(self.view.datarecord.id, change).done(function() {
self.view.reload();
});
});
@@ -4985,7 +5213,7 @@ instance.web.form.FieldMonetary = instance.web.form.FieldFloat.extend({
return;
}
return this.ci_dm.add(new instance.web.Model("res.currency").query(["symbol", "position"])
- .filter([["id", "=", self.get("currency")]]).first()).pipe(function(res) {
+ .filter([["id", "=", self.get("currency")]]).first()).then(function(res) {
self.set({"currency_info": res});
});
},
@@ -5014,6 +5242,7 @@ instance.web.form.widgets = new instance.web.Registry({
'datetime' : 'instance.web.form.FieldDatetime',
'selection' : 'instance.web.form.FieldSelection',
'many2one' : 'instance.web.form.FieldMany2One',
+ 'many2onebutton' : 'instance.web.form.Many2OneButton',
'many2many' : 'instance.web.form.FieldMany2Many',
'many2many_tags' : 'instance.web.form.FieldMany2ManyTags',
'many2many_kanban' : 'instance.web.form.FieldMany2ManyKanban',
@@ -5027,6 +5256,7 @@ instance.web.form.widgets = new instance.web.Registry({
'progressbar': 'instance.web.form.FieldProgressBar',
'image': 'instance.web.form.FieldBinaryImage',
'binary': 'instance.web.form.FieldBinaryFile',
+ 'one2many_binary': 'instance.web.form.FieldOne2ManyBinaryMultiFiles',
'statusbar': 'instance.web.form.FieldStatus',
'monetary': 'instance.web.form.FieldMonetary',
});
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 5546105e901..f11a9a2e3ac 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -508,7 +508,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
_.pluck(_(this.columns).filter(function (r) {
return r.tag === 'field';
}), 'name')
- ).then(function (records) {
+ ).done(function (records) {
_(records[0]).each(function (value, key) {
record.set(key, value, {silent: true});
});
@@ -553,7 +553,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
this.no_leaf = !!context['group_by_no_leaf'];
this.grouped = !!group_by;
- return this.load_view(context).pipe(
+ return this.load_view(context).then(
this.proxy('reload_content'));
},
/**
@@ -566,7 +566,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
return;
}
var self = this;
- return $.when(this.dataset.unlink(ids)).then(function () {
+ return $.when(this.dataset.unlink(ids)).done(function () {
_(ids).each(function (id) {
self.records.remove(self.records.get(id));
});
@@ -970,13 +970,13 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
// set) a human-readable version. m2o does not have this issue
// because the non-human-readable is just a number, where the
// human-readable version is a pair
- if (value && (ref_match = /([\w\.]+),(\d+)/.exec(value))) {
+ if (value && (ref_match = /^([\w\.]+),(\d+)$/.exec(value))) {
// reference values are in the shape "$model,$id" (as a
// string), we need to split and name_get this pair in order
// to get a correctly displayable value in the field
var model = ref_match[1],
id = parseInt(ref_match[2], 10);
- new instance.web.DataSet(this.view, model).name_get([id]).then(function(names) {
+ new instance.web.DataSet(this.view, model).name_get([id]).done(function(names) {
if (!names.length) { return; }
record.set(column.id, names[0][1]);
});
@@ -992,7 +992,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
// and let the various registered events handle refreshing the
// row
new instance.web.DataSet(this.view, column.relation)
- .name_get([value]).then(function (names) {
+ .name_get([value]).done(function (names) {
if (!names.length) { return; }
record.set(column.id, names[0]);
});
@@ -1015,7 +1015,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
ids = value;
}
new instance.web.Model(column.relation)
- .call('name_get', [ids]).then(function (names) {
+ .call('name_get', [ids]).done(function (names) {
record.set(column.id, _(names).pluck(1).join(', '));
})
}
@@ -1100,7 +1100,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
}, this);
if (!this.$current) { return; }
this.$current.remove();
- this.$current = null;
},
get_records: function () {
return this.records.map(function (record) {
@@ -1307,9 +1306,11 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
process_modifiers: false
});
} catch (e) {
- group_label = row_data[group_column.id].value;
+ group_label = _.str.escapeHTML(row_data[group_column.id].value);
}
- $group_column.text(_.str.sprintf("%s (%d)",
+ // group_label is html-clean (through format or explicit
+ // escaping if format failed), can inject straight into HTML
+ $group_column.html(_.str.sprintf("%s (%d)",
group_label, group.length));
if (group.length && group.openable) {
@@ -1384,43 +1385,45 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
var options = { offset: page * limit, limit: limit, context: {bin_size: true} };
//TODO xmo: investigate why we need to put the setTimeout
- $.async_when().then(function() {dataset.read_slice(fields, options).then(function (records) {
- // FIXME: ignominious hacks, parents (aka form view) should not send two ListView#reload_content concurrently
- if (self.records.length) {
- self.records.reset(null, {silent: true});
- }
- if (!self.datagroup.openable) {
- view.configure_pager(dataset);
- } else {
- if (dataset.size() == records.length) {
- // only one page
- self.$row.find('td.oe_list_group_pagination').empty();
+ $.async_when().done(function() {
+ dataset.read_slice(fields, options).done(function (records) {
+ // FIXME: ignominious hacks, parents (aka form view) should not send two ListView#reload_content concurrently
+ if (self.records.length) {
+ self.records.reset(null, {silent: true});
+ }
+ if (!self.datagroup.openable) {
+ view.configure_pager(dataset);
} else {
- var pages = Math.ceil(dataset.size() / limit);
- self.$row
- .find('.oe_list_pager_state')
- .text(_.str.sprintf(_t("%(page)d/%(page_count)d"), {
- page: page + 1,
- page_count: pages
- }))
- .end()
- .find('button[data-pager-action=previous]')
- .css('visibility',
- page === 0 ? 'hidden' : '')
- .end()
- .find('button[data-pager-action=next]')
- .css('visibility',
- page === pages - 1 ? 'hidden' : '');
+ if (dataset.size() == records.length) {
+ // only one page
+ self.$row.find('td.oe_list_group_pagination').empty();
+ } else {
+ var pages = Math.ceil(dataset.size() / limit);
+ self.$row
+ .find('.oe_list_pager_state')
+ .text(_.str.sprintf(_t("%(page)d/%(page_count)d"), {
+ page: page + 1,
+ page_count: pages
+ }))
+ .end()
+ .find('button[data-pager-action=previous]')
+ .css('visibility',
+ page === 0 ? 'hidden' : '')
+ .end()
+ .find('button[data-pager-action=next]')
+ .css('visibility',
+ page === pages - 1 ? 'hidden' : '');
+ }
}
- }
- self.records.add(records, {silent: true});
- list.render();
- d.resolve(list);
- if (_.isEmpty(records)) {
- view.no_result();
- }
- });});
+ self.records.add(records, {silent: true});
+ list.render();
+ d.resolve(list);
+ if (_.isEmpty(records)) {
+ view.no_result();
+ }
+ });
+ });
return d.promise();
},
setup_resequence_rows: function (list, dataset) {
@@ -1476,7 +1479,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
// Accounting > Taxes > Taxes, child tax accounts)
// when synchronous (without setTimeout)
(function (dataset, id, seq) {
- $.async_when().then(function () {
+ $.async_when().done(function () {
var attrs = {};
attrs[seqname] = seq;
dataset.write(id, attrs);
@@ -1501,7 +1504,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
self.render_groups(groups));
if (post_render) { post_render(); }
}, function (dataset) {
- self.render_dataset(dataset).then(function (list) {
+ self.render_dataset(dataset).done(function (list) {
self.children[null] = list;
self.elements =
[list.$current.replaceAll($el)[0]];
@@ -1561,7 +1564,7 @@ var DataGroup = instance.web.CallbackEnabled.extend({
list: function (fields, ifGroups, ifRecords) {
var self = this;
var query = this.model.query(fields).order_by(this.sort).group_by(this.group_by);
- $.when(query).then(function (querygroups) {
+ $.when(query).done(function (querygroups) {
// leaf node
if (!querygroups) {
var ds = new instance.web.DataSetSearch(self, self.model.name, self.model.context(), self.model.domain());
@@ -2011,6 +2014,7 @@ instance.web.list.columns = new instance.web.Registry({
'field.progressbar': 'instance.web.list.ProgressBar',
'field.handle': 'instance.web.list.Handle',
'button': 'instance.web.list.Button',
+ 'field.many2onebutton': 'instance.web.list.Many2OneButton',
});
instance.web.list.columns.for_ = function (id, field, node) {
var description = _.extend({tag: node.tag}, field, node.attrs);
@@ -2198,5 +2202,11 @@ instance.web.list.Handle = instance.web.list.Column.extend({
return '<div class="oe_list_handle">';
}
});
+instance.web.list.Many2OneButton = instance.web.list.Column.extend({
+ _format: function (row_data, options) {
+ this.has_value = !!row_data[this.id].value;
+ return QWeb.render('Many2OneButton.cell', {'widget': this});
+ },
+});
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index acc1d781976..3711bba16c1 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -12,6 +12,8 @@ openerp.web.list_editable = function (instance) {
var self = this;
this._super.apply(this, arguments);
+ this.saving_mutex = new $.Mutex();
+
this._force_editability = null;
this._context_editable = false;
this.editor = this.make_editor();
@@ -127,7 +129,7 @@ openerp.web.list_editable = function (instance) {
// restartable
this.editor = this.make_editor();
var editor_ready = this.editor.prependTo(this.$el)
- .then(this.proxy('setup_events'));
+ .done(this.proxy('setup_events'));
return $.when(result, editor_ready);
} else {
@@ -146,7 +148,7 @@ openerp.web.list_editable = function (instance) {
},
do_button_action: function (name, id, callback) {
var self = this, args = arguments;
- this.ensure_saved().then(function (done) {
+ this.ensure_saved().done(function (done) {
if (!id && done.created) {
id = done.record.get('id');
}
@@ -162,10 +164,13 @@ openerp.web.list_editable = function (instance) {
* @returns {$.Deferred}
*/
ensure_saved: function () {
- if (!this.editor.is_editing()) {
- return $.when();
- }
- return this.save_edition();
+ var self = this;
+ return this.saving_mutex.exec(function() {
+ if (!self.editor.is_editing()) {
+ return $.when();
+ }
+ return self.save_edition();
+ });
},
/**
* Set up the edition of a record of the list view "inline"
@@ -191,7 +196,7 @@ openerp.web.list_editable = function (instance) {
at: this.prepends_on_create() ? 0 : null});
}
- return this.ensure_saved().pipe(function () {
+ return this.ensure_saved().then(function () {
var $recordRow = self.groups.get_row_for(record);
var cells = self.get_cells_for($recordRow);
self.fields_for_resize.splice(0, self.fields_for_resize.length);
@@ -208,7 +213,7 @@ openerp.web.list_editable = function (instance) {
// FIXME: need better way to get the field back from bubbling (delegated) DOM events somehow
field.$el.attr('data-fieldname', field_name);
self.fields_for_resize.push({field: field, cell: cell});
- }, options).pipe(function () {
+ }, options).then(function () {
$recordRow.addClass('oe_edition');
self.resize_fields();
return record.attributes;
@@ -252,9 +257,10 @@ openerp.web.list_editable = function (instance) {
var position = $cell.position();
field.set_dimensions($cell.outerHeight(), $cell.outerWidth());
- field.$el.css({
- top: position.top,
- left: position.left,
+ field.$el.position({
+ my: 'left top',
+ at: 'left top',
+ of: $cell
});
},
/**
@@ -267,7 +273,7 @@ openerp.web.list_editable = function (instance) {
form: this.editor.form,
cancel: false
}, function () {
- return this.editor.save().pipe(function (attrs) {
+ return this.editor.save().then(function (attrs) {
var created = false;
var record = self.records.get(attrs.id);
if (!record) {
@@ -281,9 +287,9 @@ openerp.web.list_editable = function (instance) {
// record which has *just* been saved, so first perform all
// onwrites then do a final reload of the record
return self.handle_onwrite(record)
- .pipe(function () {
+ .then(function () {
return self.reload_record(record); })
- .pipe(function () {
+ .then(function () {
return { created: created, record: record }; });
});
});
@@ -299,7 +305,7 @@ openerp.web.list_editable = function (instance) {
form: this.editor.form,
cancel: false
}, function () {
- return this.editor.cancel(force).pipe(function (attrs) {
+ return this.editor.cancel(force).then(function (attrs) {
if (attrs.id) {
var record = self.records.get(attrs.id);
if (!record) {
@@ -343,7 +349,7 @@ openerp.web.list_editable = function (instance) {
message: _.str.sprintf("Event %s:before cancelled",
event_name)});
}
- return $.when(action.call(this)).then(function () {
+ return $.when(action.call(this)).done(function () {
self.trigger.apply(self, [event_name + ':after']
.concat(_.toArray(arguments)));
});
@@ -373,7 +379,7 @@ openerp.web.list_editable = function (instance) {
var on_write_callback = self.fields_view.arch.attrs.on_write;
if (!on_write_callback) { return $.when(); }
return this.dataset.call(on_write_callback, [source_record.get('id')])
- .pipe(function (ids) {
+ .then(function (ids) {
return $.when.apply(
null, _(ids).map(
_.bind(self.handle_onwrite_record, self, source_record)));
@@ -410,15 +416,15 @@ openerp.web.list_editable = function (instance) {
});
this.editor.$el.on('keyup keydown', function (e) {
- if (!self.editor.is_editing()) { return; }
+ if (!self.editor.is_editing()) { return true; }
var key = _($.ui.keyCode).chain()
.map(function (v, k) { return {name: k, code: v}; })
.find(function (o) { return o.code === e.which; })
.value();
- if (!key) { return; }
+ if (!key) { return true; }
var method = e.type + '_' + key.name;
- if (!(method in self)) { return; }
- self[method](e);
+ if (!(method in self)) { return true; }
+ return self[method](e);
});
},
/**
@@ -434,7 +440,7 @@ openerp.web.list_editable = function (instance) {
_next: function (next_record, options) {
next_record = next_record || 'succ';
var self = this;
- return this.save_edition().pipe(function (saveInfo) {
+ return this.save_edition().then(function (saveInfo) {
if (saveInfo.created) {
return self.start_edition();
}
@@ -446,7 +452,10 @@ openerp.web.list_editable = function (instance) {
keyup_ENTER: function () {
return this._next();
},
- keyup_ESCAPE: function () {
+ keydown_ESCAPE: function (e) {
+ return false;
+ },
+ keyup_ESCAPE: function (e) {
return this.cancel_edition();
},
/**
@@ -638,7 +647,7 @@ openerp.web.list_editable = function (instance) {
var _super = this._super();
this.form.embedded_view = this._validate_view(
this.delegate.edition_view(this));
- var form_ready = this.form.appendTo(this.$el).then(
+ var form_ready = this.form.appendTo(this.$el).done(
self.form.proxy('do_hide'));
return $.when(_super, form_ready);
},
@@ -719,9 +728,9 @@ openerp.web.list_editable = function (instance) {
var loaded = record
? form.trigger('load_record', _.extend({}, record))
: form.load_defaults();
- return $.when(loaded).pipe(function () {
+ return $.when(loaded).then(function () {
return form.do_show({reload: false});
- }).pipe(function () {
+ }).then(function () {
self.record = form.datarecord;
_(form.fields).each(function (field, name) {
configureField(name, field);
@@ -734,7 +743,7 @@ openerp.web.list_editable = function (instance) {
var self = this;
return this.form
.save(this.delegate.prepends_on_create())
- .pipe(function (result) {
+ .then(function (result) {
var created = result.created && !self.record.id;
if (created) {
self.record.id = result.result;
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index 05760420ba8..8265be77ba1 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()
- }).then(this.on_loaded);
+ }).done(this.on_loaded);
},
/**
* Returns the list of fields needed to correctly read objects.
@@ -63,12 +63,6 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}
return fields;
},
- store_record:function(records){
- var self = this;
- _(records).each(function (record) {
- self.records[record.id] = record;
- });
- },
on_loaded: function (fields_view) {
var self = this;
var has_toolbar = !!fields_view.arch.attrs.toolbar;
@@ -92,20 +86,18 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}));
this.$el.addClass(this.fields_view.arch.attrs['class']);
- this.dataset.read_slice(this.fields_list()).then(function(records) {
- self.store_record(records);
+ this.dataset.read_slice(this.fields_list()).done(function(records) {
if (!has_toolbar) {
// WARNING: will do a second read on the same ids, but only on
// first load so not very important
- self.render_data({'null':records})
- self.getdata(_.pluck(records,"id"));
+ self.getdata(null, _(records).pluck('id'));
return;
}
var $select = self.$el.find('select')
.change(function () {
var $option = $(this).find(':selected');
- self.getdata($option.val());
+ self.getdata($option.val(), $option.data('children'));
});
_(records).each(function (record) {
self.records[record.id] = record;
@@ -120,12 +112,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
$select.change();
}
});
- this.$el.find("#tree_view_expand").click(function(){
- self.expand_all();
- });
- this.$el.find("#tree_view_collapse").click(function(){
- self.collpase_all();
- });
+
// TODO store open nodes in url ?...
this.do_push_state({});
@@ -141,22 +128,6 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
return [color, py.parse(py.tokenize(expr)), expr];
}).value();
},
- expand_all: function(){
- var self = this;
- var tr = this.$el.find(".oe-treeview-table tbody tr[id^='treerow_']");
- _.each(tr,function(rec){
- self.showcontent($(rec).attr('data-id'),true);
- });
- },
- collpase_all: function(){
- var self = this;
- var root_tr = this.$el.find(".oe-treeview-table tbody tr[data-level='"+1+"']");
- _.each(root_tr,function(rec){
- if($(rec).hasClass('oe_open')){
- self.showcontent($(rec).attr('data-id'),false);
- }
- });
- },
/**
* Returns the color for the provided record in the current view (from the
* ``@colors`` attribute)
@@ -193,44 +164,50 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
});
this.$el.delegate('.treeview-tr', 'click', function () {
- var $this = $(this),
+ var is_loaded = 0,
+ $this = $(this),
record_id = $this.data('id'),
- bool = $this.parent().hasClass('oe_open');
- self.showcontent(record_id, !bool);
+ record = self.records[record_id],
+ children_ids = record[self.children_field];
+
+ _(children_ids).each(function(childid) {
+ if (self.$el.find('#treerow_' + childid).length) {
+ if (self.$el.find('#treerow_' + childid).is(':hidden')) {
+ is_loaded = -1;
+ } else {
+ is_loaded++;
+ }
+ }
+ });
+ if (is_loaded === 0) {
+ if (!$this.parent().hasClass('oe_open')) {
+ self.getdata(record_id, children_ids);
+ }
+ } else {
+ self.showcontent(record_id, is_loaded < 0);
+ }
});
},
// get child data of selected value
- getdata: function (id) {
+ getdata: function (id, children_ids) {
var self = this;
- var parent_child ={};
- id = _.isArray(id)?id:parseInt(id);
- var ir_model_data = new instance.web.Model(this.model,self.dataset.get_context() || {},[['id','child_of',id]]).query();
- ir_model_data._execute().then(function(records){
- self.store_record(records);
- _.each(records,function(rec){
- if(rec[self.children_field].length === 0)return;
- parent_child[rec.id] = [];
- _.each(rec[self.children_field],function(key){
- parent_child[rec.id].push(self.records[key]);
- });
- })
- self.render_data(parent_child);
- });
- },
- render_data: function(groupby){
- var self = this;
- _.each(_.keys(groupby),function(key){
- var $curr_node = self.$el.find('#treerow_' + key);
- var record = groupby[key];
+
+ self.dataset.read_ids(children_ids, this.fields_list()).done(function(records) {
+ _(records).each(function (record) {
+ self.records[record.id] = record;
+ });
+
+ var $curr_node = self.$el.find('#treerow_' + id);
var children_rows = QWeb.render('TreeView.rows', {
- 'records': record,
+ 'records': records,
'children_field': self.children_field,
'fields_view': self.fields_view.arch.children,
'fields': self.fields,
- 'level': ($curr_node.data('level') || 0) + 1,
+ 'level': $curr_node.data('level') || 0,
'render': instance.web.format_value,
'color_for': self.color_for
});
+
if ($curr_node.length) {
$curr_node.addClass('oe_open');
$curr_node.after(children_rows);
@@ -238,10 +215,8 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
self.$el.find('tbody').html(children_rows);
}
});
- self.collpase_all();
},
-
// Get details in listview
activate: function(id) {
var self = this;
@@ -254,7 +229,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
model: this.dataset.model,
context: new instance.web.CompoundContext(
this.dataset.get_context(), local_context)
- }).pipe(function (actions) {
+ }).then(function (actions) {
if (!actions.length) { return; }
var action = actions[0][2];
var c = new instance.web.CompoundContext(local_context);
@@ -263,7 +238,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}
return self.rpc('/web/session/eval_domain_and_context', {
contexts: [c], domains: []
- }).pipe(function (res) {
+ }).then(function (res) {
action.context = res.context;
return self.do_action(action);
}, null);
@@ -284,5 +259,13 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}, this);
},
+ do_show: function () {
+ this.$el.show();
+ },
+
+ do_hide: function () {
+ this.$el.hide();
+ this.hidden = true;
+ }
});
};
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index ebc7c326724..2f35ccf89b8 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -208,7 +208,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
if (run_action) {
this.null_action();
action_loaded = this.do_action(state.action);
- instance.webclient.menu.has_been_loaded.then(function() {
+ instance.webclient.menu.has_been_loaded.done(function() {
instance.webclient.menu.open_action(state.action);
});
}
@@ -226,14 +226,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
} else if (state.sa) {
// load session action
this.null_action();
- action_loaded = this.rpc('/web/session/get_session_action', {key: state.sa}).pipe(function(action) {
+ action_loaded = this.rpc('/web/session/get_session_action', {key: state.sa}).then(function(action) {
if (action) {
return self.do_action(action);
}
});
}
- $.when(action_loaded || null).then(function() {
+ $.when(action_loaded || null).done(function() {
if (self.inner_widget && self.inner_widget.do_load_state) {
self.inner_widget.do_load_state(state, warm);
}
@@ -247,11 +247,11 @@ instance.web.ActionManager = instance.web.Widget.extend({
action_menu_id: null,
});
if (_.isString(action) && instance.web.client_actions.contains(action)) {
- var action_client = { type: "ir.actions.client", tag: action };
+ var action_client = { type: "ir.actions.client", tag: action, params: {} };
return this.do_action(action_client, options);
} else if (_.isNumber(action) || _.isString(action)) {
var self = this;
- return self.rpc("/web/action/load", { action_id: action }).pipe(function(result) {
+ return self.rpc("/web/action/load", { action_id: action }).then(function(result) {
return self.do_action(result, options);
});
}
@@ -346,14 +346,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
if (!(ClientWidget.prototype instanceof instance.web.Widget)) {
var next;
- if (next = ClientWidget(this, action.params)) {
+ if (next = ClientWidget(this, action)) {
return this.do_action(next, options);
}
return $.when();
}
return this.ir_actions_common({
- widget: function () { return new ClientWidget(self, action.params); },
+ widget: function () { return new ClientWidget(self, action); },
action: action,
klass: 'oe_act_client',
post_process: function(widget) {
@@ -379,7 +379,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.rpc('/web/action/run', {
action_id: action.id,
context: action.context || {}
- }).then(function (action) {
+ }).done(function (action) {
self.do_action(action, options)
});
},
@@ -389,7 +389,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
self.rpc("/web/session/eval_domain_and_context", {
contexts: [action.context],
domains: []
- }).then(function(res) {
+ }).done(function(res) {
action = _.clone(action);
action.context = res.context;
self.session.get_file({
@@ -487,7 +487,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
} else if (this.searchview
&& self.flags.auto_search
&& view.controller.searchable !== false) {
- this.searchview.ready.then(this.searchview.do_search);
+ this.searchview.ready.done(this.searchview.do_search);
}
if (this.searchview) {
@@ -499,7 +499,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
.find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]')
.parent().addClass('active');
- r = $.when(view_promise).then(function () {
+ r = $.when(view_promise).done(function () {
_.each(_.keys(self.views), function(view_name) {
var controller = self.views[view_name].controller;
if (controller) {
@@ -551,11 +551,11 @@ instance.web.ViewManager = instance.web.Widget.extend({
var view_promise = controller.appendTo(container);
this.views[view_type].controller = controller;
this.views[view_type].deferred.resolve(view_type);
- return $.when(view_promise).then(function() {
+ return $.when(view_promise).done(function() {
if (self.searchview
&& self.flags.auto_search
&& view.controller.searchable !== false) {
- self.searchview.ready.then(self.searchview.do_search);
+ self.searchview.ready.done(self.searchview.do_search);
}
self.trigger("controller_inited",view_type,controller);
});
@@ -582,7 +582,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
var view_to_select = views[index];
var state = self.url_states[view_to_select];
self.do_push_state(state || {});
- $.when(self.switch_mode(view_to_select)).then(function() {
+ $.when(self.switch_mode(view_to_select)).done(function() {
self.$el.show();
});
},
@@ -661,7 +661,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
domains: [this.action.domain || []].concat(domains || []),
contexts: [action_context].concat(contexts || []),
group_by_seq: groupbys || []
- }).then(function (results) {
+ }).done(function (results) {
self.dataset._model = new instance.web.Model(
self.dataset.model, results.context, results.domain);
var groupby = results.group_by.length
@@ -786,7 +786,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
case 'perm_read':
var ids = current_view.get_selected_ids();
if (ids.length === 1) {
- this.dataset.call('perm_read', [ids]).then(function(result) {
+ this.dataset.call('perm_read', [ids]).done(function(result) {
var dialog = new instance.web.Dialog(this, {
title: _.str.sprintf(_t("View Log (%s)"), self.dataset.model),
width: 400
@@ -812,7 +812,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
});
break;
case 'fields':
- this.dataset.call('fields_get', [false, {}]).then(function (fields) {
+ this.dataset.call('fields_get', [false, {}]).done(function (fields) {
var $root = $('<dl>');
_(fields).each(function (attributes, name) {
$root.append($('<dt>').append($('<h4>').text(name)));
@@ -899,7 +899,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
switch_mode: function (view_type, no_store, options) {
var self = this;
- return $.when(this._super.apply(this, arguments)).then(function () {
+ return $.when(this._super.apply(this, arguments)).done(function () {
var controller = self.views[self.active_view].controller;
self.$el.find('.oe_debug_view').html(QWeb.render('ViewManagerDebug', {
view: controller,
@@ -938,13 +938,13 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
defs = [];
if (state.view_type && state.view_type !== this.active_view) {
defs.push(
- this.views[this.active_view].deferred.pipe(function() {
+ this.views[this.active_view].deferred.then(function() {
return self.switch_mode(state.view_type, true);
})
);
}
- $.when(defs).then(function() {
+ $.when(defs).done(function() {
self.views[self.active_view].controller.do_load_state(state, warm);
});
},
@@ -1051,7 +1051,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
},
on_item_action_clicked: function(item) {
var self = this;
- self.getParent().sidebar_context().then(function (context) {
+ self.getParent().sidebar_context().done(function (context) {
var ids = self.getParent().get_selected_ids();
if (ids.length == 0) {
instance.web.dialog($("<div />").text(_t("You must choose at least one record.")), { title: _t("Warning"), modal: true });
@@ -1065,7 +1065,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
self.rpc("/web/action/load", {
action_id: item.action.id,
context: additional_context
- }).then(function(result) {
+ }).done(function(result) {
result.context = _.extend(result.context || {},
additional_context);
result.flags = result.flags || {};
@@ -1087,7 +1087,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
} else {
var dom = [ ['res_model', '=', dataset.model], ['res_id', '=', model_id], ['type', 'in', ['binary', 'url']] ];
var ds = new instance.web.DataSetSearch(this, 'ir.attachment', dataset.get_context(), dom);
- ds.read_slice(['name', 'url', 'type'], {}).then(this.on_attachments_loaded);
+ ds.read_slice(['name', 'url', 'type'], {}).done(this.on_attachments_loaded);
}
},
on_attachments_loaded: function(attachments) {
@@ -1122,7 +1122,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
var self = this;
var $e = $(e.currentTarget);
if (confirm(_t("Do you really want to delete this attachment ?"))) {
- (new instance.web.DataSet(this, 'ir.attachment')).unlink([parseInt($e.attr('data-id'), 10)]).then(function() {
+ (new instance.web.DataSet(this, 'ir.attachment')).unlink([parseInt($e.attr('data-id'), 10)]).done(function() {
self.do_attachement_update(self.dataset, self.model_id);
});
}
@@ -1150,7 +1150,7 @@ instance.web.View = instance.web.Widget.extend({
var view_loaded;
if (this.embedded_view) {
view_loaded = $.Deferred();
- $.async_when().then(function() {
+ $.async_when().done(function() {
view_loaded.resolve(self.embedded_view);
});
} else {
@@ -1164,7 +1164,7 @@ instance.web.View = instance.web.Widget.extend({
context: this.dataset.get_context(context)
});
}
- return view_loaded.pipe(function(r) {
+ return view_loaded.then(function(r) {
self.trigger('view_loaded', r);
// add css classes that reflect the (absence of) access rights
self.$el.addClass('oe_view')
@@ -1220,7 +1220,7 @@ instance.web.View = instance.web.Widget.extend({
return self.rpc('/web/session/eval_domain_and_context', {
contexts: [ncontext],
domains: []
- }).pipe(function (results) {
+ }).then(function (results) {
action.context = results.context;
/* niv: previously we were overriding once more with action_data.context,
* I assumed this was not a correct behavior and removed it
@@ -1249,11 +1249,11 @@ instance.web.View = instance.web.Widget.extend({
}
}
args.push(context);
- return dataset.call_button(action_data.name, args).then(handler);
+ return dataset.call_button(action_data.name, args).done(handler);
} else if (action_data.type=="action") {
- return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}).then(handler);
+ return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}).done(handler);
} else {
- return dataset.exec_workflow(record_id, action_data.name).then(handler);
+ return dataset.exec_workflow(record_id, action_data.name).done(handler);
}
},
/**