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