summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorHarry (OpenERP) <hmo@tinyerp.com>2012-11-12 14:55:13 +0530
committerHarry (OpenERP) <hmo@tinyerp.com>2012-11-12 14:55:13 +0530
commitd8034fa4f4afe2fdfc81194167ededa4a4ee27a6 (patch)
treec09c9449b7cb83f4fc4739caad611529177474bb /addons/web/static/src
parent47e028f6c94c82e50cac026a6a9e72df211fa8c9 (diff)
parent0074bc4b3d8b1fc9d80f7a76f8f5412818de4e7c (diff)
[MERGE]
bzr revid: hmo@tinyerp.com-20121112092513-ngonx9bv68uw2gb5
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css6
-rw-r--r--addons/web/static/src/css/base.sass10
-rw-r--r--addons/web/static/src/js/chrome.js84
-rw-r--r--addons/web/static/src/js/corelib.js261
-rw-r--r--addons/web/static/src/js/coresetup.js60
-rw-r--r--addons/web/static/src/js/data.js37
-rw-r--r--addons/web/static/src/js/data_export.js10
-rw-r--r--addons/web/static/src/js/search.js121
-rw-r--r--addons/web/static/src/js/test_support.js8
-rw-r--r--addons/web/static/src/js/view_form.js555
-rw-r--r--addons/web/static/src/js/view_list.js120
-rw-r--r--addons/web/static/src/js/view_list_editable.js48
-rw-r--r--addons/web/static/src/js/view_tree.js111
-rw-r--r--addons/web/static/src/js/views.js61
-rw-r--r--addons/web/static/src/xml/base.xml23
15 files changed, 801 insertions, 714 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 30fe4d415cf..94d02758ad0 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -25,7 +25,6 @@
display: none !important;
}
}
-
.openerp.openerp_webclient_container {
height: 100%;
}
@@ -2566,7 +2565,7 @@
background-color: #eeeeee;
}
.openerp .oe_list_editable .oe_list_content td.oe_list_field_cell {
- padding: 4px 6px 3px 6px;
+ padding: 4px 6px 3px;
}
.openerp .oe_list.oe_list_editable.oe_editing .oe_edition .oe_list_field_cell:not(.oe_readonly) {
color: transparent;
@@ -2647,6 +2646,9 @@
margin: 0 !important;
padding: 0;
}
+.openerp .oe_list .oe_form .oe_form_field_boolean {
+ padding: 1px 6px 3px;
+}
.openerp .oe_list .oe_list_content .oe_group_header {
background-color: #fcfcfc;
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede));
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index e388ad16727..f911929e159 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -2030,10 +2030,8 @@ $sheet-padding: 16px
background-color: #eee
$row-height: 27px
- .oe_list_editable
- .oe_list_content
- td.oe_list_field_cell
- padding: 4px 6px 3px 6px
+ .oe_list_editable .oe_list_content td.oe_list_field_cell
+ padding: 4px 6px 3px
.oe_list.oe_list_editable.oe_editing
.oe_edition .oe_list_field_cell:not(.oe_readonly)
*
@@ -2106,6 +2104,10 @@ $sheet-padding: 16px
position: absolute
margin: 0 !important // dammit
padding: 0
+ .oe_form_field_boolean
+ // use padding similar to actual cell to correctly position the
+ // checkbox
+ padding: 1px 6px 3px
.oe_list_content .oe_group_header
@include vertical-gradient(#fcfcfc, #dedede)
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 08ef8c4f9bf..69dafa08c02 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,14 +182,14 @@ 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();
}
});
-instance.web.CrashManager = instance.web.CallbackEnabled.extend({
+instance.web.CrashManager = instance.web.Class.extend({
rpc_error: function(error) {
if (error.data.fault_code) {
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
@@ -294,18 +301,18 @@ 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;
+ self.db_list = result;
},
function (_, ev) {
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;
@@ -541,7 +548,7 @@ instance.web.Login = instance.web.Widget.extend({
return d;
},
on_db_loaded: function (result) {
- this.db_list = result.db_list;
+ this.db_list = result;
this.$("[name=db]").replaceWith(QWeb.render('Login.dblist', { db_list: this.db_list, selected_db: this.selected_db}));
if(this.db_list.length === 0) {
this.do_action("database_manager");
@@ -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);
@@ -664,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;
@@ -703,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);
});
},
@@ -873,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);
@@ -884,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');
@@ -900,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();
@@ -920,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();
@@ -987,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');
});
@@ -1056,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')); });
},
@@ -1072,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();
@@ -1085,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);
@@ -1100,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)
});
});
@@ -1118,11 +1125,12 @@ instance.web.WebClient = instance.web.Client.extend({
var url = '#' + $.param(state);
this._current_state = _.clone(state);
$.bbq.pushState(url);
+ this.trigger('state_pushed', state);
},
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..4012be526e6 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -243,15 +243,17 @@ instance.web.ParentedMixin = {
/**
* Backbone's events. Do not ever use it directly, use EventDispatcherMixin instead.
+ *
+ * This class just handle the dispatching of events, it is not meant to be extended,
+ * nor used directly. All integration with parenting and automatic unregistration of
+ * events is done in EventDispatcherMixin.
+ *
+ * Copyright notice for the following Class:
*
* (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
* Backbone may be freely distributed under the MIT license.
* For all details and documentation:
* http://backbonejs.org
- *
- * This class just handle the dispatching of events, it is not meant to be extended,
- * nor used directly. All integration with parenting and automatic unregistration of
- * events is done in EventDispatcherMixin.
*
*/
var Events = instance.web.Class.extend({
@@ -334,7 +336,6 @@ var Events = instance.web.Class.extend({
return this;
}
});
-// end of Jeremy Ashkenas' code
instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, {
__eventDispatcherMixin: true,
@@ -426,66 +427,94 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
}
});
-instance.web.CallbackEnabledMixin = _.extend({}, instance.web.PropertiesMixin, {
- init: function() {
- instance.web.PropertiesMixin.init.call(this);
- var self = this;
- // Transform on_/do_* methods into callbacks
- var callback_maker = function(fn) {
- return function() {
- return fn.apply(self, arguments);
- }
- };
- for (var name in this) {
- if(typeof(this[name]) == "function") {
- if((/^on_|^do_/).test(name)) {
- this[name] = callback_maker(this[name]);
- }
- }
- }
- },
+// Classes
+
+/**
+ * Base class for all visual components. Provides a lot of functionalities helpful
+ * for the management of a part of the DOM.
+ *
+ * Widget handles:
+ * - Rendering with QWeb.
+ * - Life-cycle management and parenting (when a parent is destroyed, all its children are
+ * destroyed too).
+ * - Insertion in DOM.
+ *
+ * Guide to create implementations of the Widget class:
+ * ==============================================
+ *
+ * Here is a sample child class:
+ *
+ * MyWidget = instance.base.Widget.extend({
+ * // the name of the QWeb template to use for rendering
+ * template: "MyQWebTemplate",
+ *
+ * init: function(parent) {
+ * this._super(parent);
+ * // stuff that you want to init before the rendering
+ * },
+ * start: function() {
+ * // stuff you want to make after the rendering, `this.$el` holds a correct value
+ * this.$el.find(".my_button").click(/* an example of event binding * /);
+ *
+ * // if you have some asynchronous operations, it's a good idea to return
+ * // a promise in start()
+ * var promise = this.rpc(...);
+ * return promise;
+ * }
+ * });
+ *
+ * Now this class can simply be used with the following syntax:
+ *
+ * var my_widget = new MyWidget(this);
+ * my_widget.appendTo($(".some-div"));
+ *
+ * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the
+ * DOM inside the ".some-div" div and its events were binded.
+ *
+ * And of course, when you don't need that widget anymore, just do:
+ *
+ * my_widget.destroy();
+ *
+ * That will kill the widget in a clean way and erase its content from the dom.
+ */
+instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
+ // Backbone-ish API
+ tagName: 'div',
+ id: null,
+ className: null,
+ attributes: {},
+ events: {},
/**
- * Proxies a method of the object, in order to keep the right ``this`` on
- * method invocations.
- *
- * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
- * even more so to ``jQuery.proxy`` with a fundamental difference: its
- * resolution of the method being called is lazy, meaning it will use the
- * method as it is when the proxy is called, not when the proxy is created.
- *
- * Other methods will fix the bound method to what it is when creating the
- * binding/proxy, which is fine in most javascript code but problematic in
- * OpenERP Web where developers may want to replace existing callbacks with
- * theirs.
- *
- * The semantics of this precisely replace closing over the method call.
+ * The name of the QWeb template that will be used for rendering. Must be
+ * redefined in subclasses or the default render() method can not be used.
*
- * @param {String|Function} method function or name of the method to invoke
- * @returns {Function} proxied method
+ * @type string
*/
- proxy: function (method) {
- var self = this;
- return function () {
- var fn = (typeof method === 'string') ? self[method] : method;
- return fn.apply(self, arguments);
- }
- }
-});
-
-instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, {
+ template: null,
/**
* Constructs the widget and sets its parent if a parent is given.
*
* @constructs instance.web.Widget
- * @extends instance.web.CallbackEnabled
*
* @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
* When that widget is destroyed by calling destroy(), the current instance will be
* destroyed too. Can be null.
*/
init: function(parent) {
- instance.web.CallbackEnabledMixin.init.call(this);
+ instance.web.PropertiesMixin.init.call(this);
this.setParent(parent);
+ // Bind on_/do_* methods to this
+ // We might remove this automatic binding in the future
+ for (var name in this) {
+ if(typeof(this[name]) == "function") {
+ if((/^on_|^do_/).test(name)) {
+ this[name] = this[name].bind(this);
+ }
+ }
+ }
+ // FIXME: this should not be
+ this.setElement(this._make_descriptive());
+ this.session = instance.session;
},
/**
* Destroys the current widget, also destroys all its children before destroying itself.
@@ -574,94 +603,32 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, {
*/
start: function() {
return $.when();
- }
-});
-
-// Classes
-
-instance.web.CallbackEnabled = instance.web.Class.extend(instance.web.CallbackEnabledMixin, {
- init: function() {
- instance.web.CallbackEnabledMixin.init.call(this);
- }
-});
-
-/**
- * Base class for all visual components. Provides a lot of functionalities helpful
- * for the management of a part of the DOM.
- *
- * Widget handles:
- * - Rendering with QWeb.
- * - Life-cycle management and parenting (when a parent is destroyed, all its children are
- * destroyed too).
- * - Insertion in DOM.
- *
- * Guide to create implementations of the Widget class:
- * ==============================================
- *
- * Here is a sample child class:
- *
- * MyWidget = instance.base.Widget.extend({
- * // the name of the QWeb template to use for rendering
- * template: "MyQWebTemplate",
- *
- * init: function(parent) {
- * this._super(parent);
- * // stuff that you want to init before the rendering
- * },
- * start: function() {
- * // stuff you want to make after the rendering, `this.$el` holds a correct value
- * this.$el.find(".my_button").click(/* an example of event binding * /);
- *
- * // if you have some asynchronous operations, it's a good idea to return
- * // a promise in start()
- * var promise = this.rpc(...);
- * return promise;
- * }
- * });
- *
- * Now this class can simply be used with the following syntax:
- *
- * var my_widget = new MyWidget(this);
- * my_widget.appendTo($(".some-div"));
- *
- * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the
- * DOM inside the ".some-div" div and its events were binded.
- *
- * And of course, when you don't need that widget anymore, just do:
- *
- * my_widget.destroy();
- *
- * That will kill the widget in a clean way and erase its content from the dom.
- */
-instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
- // Backbone-ish API
- tagName: 'div',
- id: null,
- className: null,
- attributes: {},
- events: {},
+ },
/**
- * The name of the QWeb template that will be used for rendering. Must be
- * redefined in subclasses or the default render() method can not be used.
+ * Proxies a method of the object, in order to keep the right ``this`` on
+ * method invocations.
*
- * @type string
- */
- template: null,
- /**
- * Constructs the widget and sets its parent if a parent is given.
+ * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
+ * even more so to ``jQuery.proxy`` with a fundamental difference: its
+ * resolution of the method being called is lazy, meaning it will use the
+ * method as it is when the proxy is called, not when the proxy is created.
*
- * @constructs instance.web.Widget
- * @extends instance.web.CallbackEnabled
+ * Other methods will fix the bound method to what it is when creating the
+ * binding/proxy, which is fine in most javascript code but problematic in
+ * OpenERP Web where developers may want to replace existing callbacks with
+ * theirs.
*
- * @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
- * When that widget is destroyed by calling destroy(), the current instance will be
- * destroyed too. Can be null.
+ * The semantics of this precisely replace closing over the method call.
+ *
+ * @param {String|Function} method function or name of the method to invoke
+ * @returns {Function} proxied method
*/
- init: function(parent) {
- instance.web.WidgetMixin.init.call(this,parent);
- // FIXME: this should not be
- this.setElement(this._make_descriptive());
- this.session = instance.session;
+ proxy: function (method) {
+ var self = this;
+ return function () {
+ var fn = (typeof method === 'string') ? self[method] : method;
+ return fn.apply(self, arguments);
+ }
},
/**
* Renders the element. The default implementation renders the widget using QWeb,
@@ -678,7 +645,6 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
}
this.replaceElement($el);
},
-
/**
* Re-sets the widget's root element and replaces the old root element
* (if any) by the new one in the DOM.
@@ -809,12 +775,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);
});
@@ -941,7 +907,7 @@ instance.web.Registry = instance.web.Class.extend({
}
});
-instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
+instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
triggers: {
'request': 'Request sent',
'response': 'Response received',
@@ -950,13 +916,12 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
},
/**
* @constructs instance.web.JsonRPC
- * @extends instance.web.CallbackEnabled
*
* @param {String} [server] JSON-RPC endpoint hostname
* @param {String} [port] JSON-RPC endpoint port
*/
init: function() {
- this._super();
+ instance.web.PropertiesMixin.init.call(this);
this.server = null;
this.debug = ($.deparam($.param.querystring()).debug != undefined);
},
@@ -1287,7 +1252,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 +1265,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 +1353,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 220b9b63d5c..5ff47aa32fa 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.load_qweb.bind(self));
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,28 @@ 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) {
- var lang = self.user_context.lang,
- all_modules = _.uniq(self.module_list.concat(result));
- var params = { mods: all_modules, lang: lang};
+ return this.rpc('/web/session/modules', {}).then(function(result) {
+ var all_modules = _.uniq(self.module_list.concat(result));
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) {
- instance.web._t.database.set_bundle(trans);
- });
- var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
+ var loaded = self.load_translations();
+ var datejs_locale = "/web/static/lib/datejs/globalization/" + self.user_context.lang.replace("_", "-") + ".js";
+
+ var file_list = [ datejs_locale ];
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.load_css.bind(self)),
+ self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.load_qweb.bind(self)),
+ self.rpc('/web/webclient/jslist', {mods: to_load}).done(function(files) {
file_list = file_list.concat(files);
})
);
}
- return loaded.pipe(function () {
- return self.do_load_js(file_list);
- }).then(function() {
+ return loaded.then(function () {
+ return self.load_js(file_list);
+ }).done(function() {
self.on_modules_loaded();
self.trigger('module_loaded');
if (!Date.CultureInfo.pmDesignator) {
@@ -190,7 +188,13 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
});
});
},
- do_load_css: function (files) {
+ load_translations: function() {
+ var params = { mods: this.module_list, lang: this.user_context.lang };
+ return this.rpc('/web/webclient/translations', params).done(function(trans) {
+ instance.web._t.database.set_bundle(trans);
+ });
+ },
+ load_css: function (files) {
var self = this;
_.each(files, function (file) {
$('head').append($('<link>', {
@@ -200,7 +204,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
}));
});
},
- do_load_js: function(files) {
+ load_js: function(files) {
var self = this;
var d = $.Deferred();
if(files.length != 0) {
@@ -212,7 +216,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.load_js(files).done(function () {
d.resolve();
});
};
@@ -223,11 +227,11 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
}
return d;
},
- do_load_qweb: function(files) {
+ load_qweb: function(files) {
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 +466,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 +478,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 +487,7 @@ $.async_when = function() {
action();
else
setTimeout(action, 0);
- }, function() {
+ }).fail(function() {
var args = arguments;
var action = function() {
def.reject.apply(def, args);
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index 63c90f53758..dcdeb749672 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 || {};
@@ -358,17 +358,16 @@ instance.web.Model = instance.web.Class.extend({
},
});
-instance.web.DataSet = instance.web.CallbackEnabled.extend({
+instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin, {
/**
* Collection of OpenERP records, used to share records and the current selection between views.
*
* @constructs instance.web.DataSet
- * @extends instance.web.CallbackEnabled
*
* @param {String} model the OpenERP model this dataset will manage
*/
init: function(parent, model, context) {
- this._super(parent);
+ instance.web.PropertiesMixin.init.call(this);
this.model = model;
this.context = context || {};
this.index = null;
@@ -443,7 +442,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 +455,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];
});
@@ -493,7 +492,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
*/
write: function (id, data, options) {
options = options || {};
- return this._model.call('write', [[id], data], {context: this.get_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 +500,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.get_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
@@ -607,7 +606,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
model: this.model,
ids: ids,
context: this.get_context(options.context),
- }).pipe(function (results) {
+ }).then(function (results) {
return results;
});
},
@@ -682,9 +681,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 +692,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 +721,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 +773,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 +835,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 +990,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 d005c79e9b2..e84ea66ff9a 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -236,7 +236,7 @@ my.FacetView = instance.web.Widget.extend({
start: function () {
var self = this;
var $e = this.$('> span:last-child');
- return $.when(this._super()).pipe(function () {
+ return $.when(this._super()).then(function () {
return $.when.apply(null, self.model.values.map(function (value) {
return new my.FacetValueView(self, value).appendTo($e);
}));
@@ -271,15 +271,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
this.$('.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
- 'autocompleteopen': function () {
- var menu = this.$el.data('autocomplete').menu;
- menu.activate(
- $.Event({ type: "mouseenter" }),
- menu.element.children().first());
- },
// search button
'click button.oe_searchview_search': function (e) {
e.stopImmediatePropagation();
@@ -356,7 +347,7 @@ 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);
@@ -417,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.$('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`)
@@ -480,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));
});
},
@@ -548,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
@@ -656,12 +635,12 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
// 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();
});
@@ -1430,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) {
@@ -1453,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]);
})
@@ -1500,7 +1479,7 @@ 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.$('li.oe_selected').removeClass('oe_selected');
@@ -1523,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,7 +1537,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
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;
}
@@ -1570,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
@@ -1647,18 +1626,18 @@ 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.$('ul')).then(function () {
+ .appendTo(this.$('ul')).done(function () {
self.$('button.oe_apply').prop('disabled', false);
});
},
@@ -1723,7 +1702,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
this.value = null;
},
start: function () {
- return this._super().then(this.proxy('changed'));
+ return this._super().done(this.proxy('changed'));
},
changed: function() {
var nval = this.$(".searchview_extended_prop_field").val();
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 15eca0b70f0..022c99d65c1 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);
@@ -200,7 +201,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.$el.find(".oe_form_group_row,.oe_form_field,label").on('click', function (e) {
if(self.get("actual_mode") == "view") {
var $button = self.options.$buttons.find(".oe_form_button_edit");
- $button.effect('bounce', {distance: 18, times: 5}, 150);
+ $button.css('box-sizing', 'content-box').effect('bounce', {distance: 18, times: 5}, 150);
e.stopPropagation();
instance.web.bus.trigger('click', e);
}
@@ -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);
});
}
@@ -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,67 +493,72 @@ 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 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.pipe(function(response) {
- if (widget.field['change_default']) {
- var fieldname = widget.name
- var value_;
- if (response.value && (fieldname in response.value)) {
- // Use value from onchange if onchange executed
- value_ = response.value[fieldname];
- } else {
- // otherwise get form value for field
- value_ = self.fields[fieldname].get_value();
- }
- var condition = fieldname + '=' + value_;
-
- if (value_) {
- return self.rpc('/web/dataset/call', {
- model: 'ir.values',
- method: 'get_defaults',
- args: [self.model, condition]
- }).pipe(function (results) {
- if (!results.length) {
- return response;
- }
- if (!response.value) {
- response.value = {};
- }
- for(var i=0; i<results.length; ++i) {
- // [whatever, key, value]
- var triplet = results[i];
- response.value[triplet[1]] = triplet[2];
- }
- return response;
- });
- }
- }
- return response;
- }).pipe(function(response) {
- return self.on_processed_onchange(response, processed);
+ 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
});
- } catch(e) {
- console.error(e);
- instance.webclient.crashmanager.show_message(e);
- return $.Deferred().reject();
+ } else {
+ def = $.when({});
}
- });
+ return def.then(function(response) {
+ if (widget.field['change_default']) {
+ var fieldname = widget.name
+ var value_;
+ if (response.value && (fieldname in response.value)) {
+ // Use value from onchange if onchange executed
+ value_ = response.value[fieldname];
+ } else {
+ // otherwise get form value for field
+ value_ = self.fields[fieldname].get_value();
+ }
+ var condition = fieldname + '=' + value_;
+
+ if (value_) {
+ return self.rpc('/web/dataset/call', {
+ model: 'ir.values',
+ method: 'get_defaults',
+ args: [self.model, condition]
+ }).then(function (results) {
+ if (!results.length) {
+ return response;
+ }
+ if (!response.value) {
+ response.value = {};
+ }
+ for(var i=0; i<results.length; ++i) {
+ // [whatever, key, value]
+ var triplet = results[i];
+ response.value[triplet[1]] = triplet[2];
+ }
+ return response;
+ });
+ }
+ }
+ 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();
+ }
},
on_processed_onchange: function(result, processed) {
try {
@@ -588,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) {
@@ -611,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);
});
},
@@ -681,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();
});
@@ -701,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();
}
@@ -716,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();
})
}
@@ -765,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;
@@ -795,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) {
@@ -804,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()
@@ -839,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;
});
@@ -878,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});
});
@@ -905,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);
});
}
@@ -916,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;
@@ -935,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();
});
@@ -945,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();
});
},
@@ -966,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;
@@ -1042,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(); });
}}
]
});
@@ -1085,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,
@@ -1096,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());
},
});
@@ -1798,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) {
@@ -1806,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;
@@ -1871,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");
@@ -1886,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();
}
@@ -1979,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() {},
};
/**
@@ -2105,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);
});
},
@@ -2122,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();
+ },
});
/**
@@ -2218,6 +2262,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
+ });
}
});
@@ -2444,6 +2495,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);
}
});
@@ -2504,7 +2559,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
@@ -2586,22 +2641,18 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({
}
});
+/**
+ The progressbar field expect a float from 0 to 100.
+*/
instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({
template: 'FieldProgressBar',
- start: function() {
- this._super.apply(this, arguments);
+ render_value: function() {
this.$el.progressbar({
- value: this.get('value'),
+ value: this.get('value') || 0,
disabled: this.get("effective_readonly")
});
- },
- render_value: function() {
- var show_value = Number(this.get('value'));
- if (isNaN(show_value)) {
- show_value = 0;
- }
- var formatted_value = instance.web.format_value(show_value, { type : 'float' }, '0');
- this.$el.progressbar('option', 'value', show_value).find('span').html(formatted_value + '%');
+ var formatted_value = instance.web.format_value(this.get('value') || 0, { type : 'float' });
+ this.$('span').html(formatted_value + '%');
}
});
@@ -2666,6 +2717,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
+ });
}
});
@@ -2722,7 +2780,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) {
@@ -2741,7 +2799,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);
});
},
@@ -2782,7 +2840,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();
@@ -2979,7 +3037,7 @@ 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');
@@ -2989,7 +3047,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
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);
@@ -3019,7 +3077,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);
});
},
@@ -3070,7 +3128,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);
});
@@ -3148,6 +3206,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', 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();
+ },
});
/*
@@ -3223,11 +3337,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();
});
});
@@ -3237,10 +3351,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;
@@ -3300,10 +3411,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) {
@@ -3335,22 +3446,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") {
@@ -3362,7 +3473,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(), []);
@@ -3435,7 +3546,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;});
@@ -3452,33 +3562,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])
@@ -3519,13 +3620,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();
});
},
@@ -3546,7 +3647,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;
}
});
@@ -3610,10 +3711,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);
@@ -3636,7 +3737,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();
});
},
@@ -3659,12 +3760,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);
});
},
@@ -3701,7 +3802,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();
@@ -3724,7 +3825,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; };
@@ -3786,7 +3887,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();
});
}));
@@ -3807,7 +3908,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() {
@@ -3820,11 +3921,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",
@@ -3839,7 +3940,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: {
@@ -3863,9 +3964,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");
@@ -3885,7 +3985,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});
@@ -3897,7 +3997,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) {
@@ -3924,7 +4024,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
return;
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;
@@ -3935,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([]);
}
@@ -3979,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();
});
});
@@ -4024,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;
@@ -4032,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();
});
},
@@ -4093,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();
});
@@ -4124,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();
});
});
@@ -4165,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;
@@ -4173,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(), []);
});
},
@@ -4209,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();
});
},
@@ -4282,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});
@@ -4337,15 +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 saved');
+ return fct.call(this, id, data, options).done(function(r) {
+ self.trigger('write_completed saved', r);
});
};
this.dataset.parent_view = this.options.parent_view;
@@ -4393,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();
});
@@ -4401,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();
});
@@ -4427,7 +4527,9 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
},
destroy: function () {
this.trigger('closed');
- this.$el.dialog('close');
+ if (this.$el.is(":data(dialog)")) {
+ this.$el.dialog('close');
+ }
this._super();
},
});
@@ -4477,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);
@@ -4519,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() {
@@ -4549,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);
});
},
@@ -5026,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 || "{}");
@@ -5050,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]);
}
@@ -5074,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();
});
});
@@ -5111,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});
});
},
@@ -5140,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',
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index ab50ae933d9..97efb983235 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));
});
@@ -976,7 +976,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
// 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]);
});
@@ -1000,7 +1000,8 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
} else if (column.type === 'many2many') {
value = record.get(column.id);
// non-resolved (string) m2m values are arrays
- if (value instanceof Array && !_.isEmpty(value)) {
+ if (value instanceof Array && !_.isEmpty(value)
+ && !record.get(column.id + '__display')) {
var ids;
// they come in two shapes:
if (value[0] instanceof Array) {
@@ -1015,9 +1016,14 @@ 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) {
- record.set(column.id, _(names).pluck(1).join(', '));
- })
+ .call('name_get', [ids]).done(function (names) {
+ // FIXME: nth horrible hack in this poor listview
+ record.set(column.id + '__display',
+ _(names).pluck(1).join(', '));
+ record.set(column.id, ids);
+ });
+ // temp empty value
+ record.set(column.id, false);
}
}
return column.format(record.toForm().data, {
@@ -1385,43 +1391,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) {
@@ -1477,7 +1485,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);
@@ -1502,7 +1510,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]];
@@ -1549,9 +1557,8 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
}
});
-var DataGroup = instance.web.CallbackEnabled.extend({
+var DataGroup = instance.web.Class.extend({
init: function(parent, model, domain, context, group_by, level) {
- this._super(parent, null);
this.model = new instance.web.Model(model, context, domain);
this.group_by = group_by;
this.context = context;
@@ -1562,7 +1569,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());
@@ -2012,6 +2019,8 @@ 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',
+ 'field.many2many': 'instance.web.list.Many2Many'
});
instance.web.list.columns.for_ = function (id, field, node) {
var description = _.extend({tag: node.tag}, field, node.attrs);
@@ -2199,5 +2208,20 @@ 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});
+ },
+});
+instance.web.list.Many2Many = instance.web.list.Column.extend({
+ _format: function (row_data, options) {
+ if (!_.isEmpty(row_data[this.id].value)) {
+ // If value, use __display version for printing
+ row_data[this.id] = row_data[this.id + '__display'];
+ }
+ return this._super(row_data, options);
+ }
+});
};
// 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 021e5549c18..37ce8c4f8b4 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;
@@ -237,7 +242,9 @@ openerp.web.list_editable = function (instance) {
if (!this.editor.is_editing()) { return; }
for(var i=0, len=this.fields_for_resize.length; i<len; ++i) {
var item = this.fields_for_resize[i];
- this.resize_field(item.field, item.cell);
+ if (!item.field.get('invisible')) {
+ this.resize_field(item.field, item.cell);
+ }
}
},
/**
@@ -249,7 +256,6 @@ openerp.web.list_editable = function (instance) {
*/
resize_field: function (field, cell) {
var $cell = $(cell);
- var position = $cell.position();
field.set_dimensions($cell.outerHeight(), $cell.outerWidth());
field.$el.position({
@@ -268,7 +274,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) {
@@ -282,9 +288,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 }; });
});
});
@@ -300,7 +306,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) {
@@ -344,7 +350,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)));
});
@@ -374,7 +380,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)));
@@ -435,7 +441,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();
}
@@ -642,7 +648,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);
},
@@ -723,9 +729,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);
@@ -738,7 +744,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 a4fe86c516d..53132e454d1 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -200,7 +200,12 @@ instance.web.ActionManager = instance.web.Widget.extend({
action_loaded;
if (state.action) {
if (_.isString(state.action) && instance.web.client_actions.contains(state.action)) {
- var action_client = {type: "ir.actions.client", tag: state.action, params: state};
+ var action_client = {
+ type: "ir.actions.client",
+ tag: state.action,
+ params: state,
+ _push_me: state._push_me,
+ };
this.null_action();
action_loaded = this.do_action(action_client);
} else {
@@ -208,7 +213,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 +231,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);
}
@@ -251,7 +256,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
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);
});
}
@@ -379,7 +384,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 +394,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 +492,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 +504,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 +556,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 +587,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 +666,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 +791,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 +817,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 +904,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 +943,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 +1056,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 +1070,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 +1092,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 +1127,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 +1155,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 +1169,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 +1225,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 +1254,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);
}
},
/**
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 99af729d04f..b5c40c53fde 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -567,16 +567,14 @@
</t>
<t t-name="TreeView">
- <div class = "tree_header">
- <select t-if="toolbar" ></select>
- <button id = "tree_view_collapse">Collapse All</button>
- <button id = "tree_view_expand">Expand All</button>
- </div>
- <table class="oe-treeview-table">
+ <select t-if="toolbar" style="width: 30%">
+ </select>
+ <table class="oe_tree_table oe-treeview-table">
<thead>
<tr>
<th t-foreach="fields_view" t-as="field"
- t-if="!field.attrs.modifiers.tree_invisible">
+ t-if="!field.attrs.modifiers.tree_invisible"
+ class="treeview-header">
<t t-esc="field_value.attrs.string || fields[field.attrs.name].string" />
</th>
</tr>
@@ -588,11 +586,11 @@
<tr t-name="TreeView.rows"
t-foreach="records" t-as="record"
t-att-id="'treerow_' + record.id"
- t-att-data-id="record.id" t-att-data-level="level">
+ t-att-data-id="record.id" t-att-data-level="level + 1">
<t t-set="children" t-value="record[children_field]"/>
<t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/>
<t t-set="rank" t-value="'oe-treeview-first'"/>
- <t t-set="style" t-value="'background-position: ' + 19*(level-1) + 'px; padding-left: ' + (4 + 19*(level-1)) + 'px;'"/>
+ <t t-set="style" t-value="'background-position: ' + 19*(level) + 'px; padding-left: ' + (4 + 19*(level)) + 'px;'"/>
<td t-foreach="fields_view" t-as="field"
t-if="!field.attrs.modifiers.tree_invisible"
@@ -1032,6 +1030,13 @@
</t>
</span>
</t>
+<t t-name="Many2OneButton">
+ <span class="oe_form_field">
+ </span>
+</t>
+<t t-name="Many2OneButton.cell"
+ ><img t-attf-src="#{_s}/web/static/src/img/icons/gtk-#{widget.has_value ? 'yes' : 'no'}.png" width="16" height="16"/>
+</t>
<t t-name="FieldMany2ManyTags">
<div class="oe_form_field oe_tags" t-att-style="widget.node.attrs.style">
<t t-if="! widget.get('effective_readonly')">