[FIX] Error while deleting a record when there is only one record in pageview
[odoo/odoo.git] / addons / web / static / src / js / views.js
index 87e3861..fd080c8 100644 (file)
@@ -16,8 +16,7 @@ session.web.client_actions = new session.web.Registry();
  */
 session.web.views = new session.web.Registry();
 
-session.web.ActionManager = session.web.Widget.extend({
-    identifier_prefix: "actionmanager",
+session.web.ActionManager = session.web.OldWidget.extend({
     init: function(parent) {
         this._super(parent);
         this.inner_action = null;
@@ -50,16 +49,15 @@ session.web.ActionManager = session.web.Widget.extend({
     do_push_state: function(state) {
         if (this.widget_parent && this.widget_parent.do_push_state) {
             if (this.inner_action) {
+                state['model'] = this.inner_action.res_model;
                 if (this.inner_action.id) {
                     state['action_id'] = this.inner_action.id;
-                } else {
-                    state['model'] = this.inner_action.res_model;
                 }
             }
             this.widget_parent.do_push_state(state);
         }
     },
-    do_load_state: function(state) {
+    do_load_state: function(state, warm) {
         var self = this,
             action_loaded;
         if (state.action_id) {
@@ -68,8 +66,7 @@ session.web.ActionManager = session.web.Widget.extend({
                 this.null_action();
                 action_loaded = this.do_action(state.action_id);
             }
-        }
-        else if (state.model && state.id) {
+        } else if (state.model && state.id) {
             // TODO handle context & domain ?
             this.null_action();
             var action = {
@@ -79,8 +76,7 @@ session.web.ActionManager = session.web.Widget.extend({
                 views: [[false, 'page'], [false, 'form']]
             };
             action_loaded = this.do_action(action);
-        }
-        else if (state.sa) {
+        } else if (state.sa) {
             // load session action
             var self = this;
             this.null_action();
@@ -89,15 +85,14 @@ session.web.ActionManager = session.web.Widget.extend({
                     return self.do_action(action);
                 }
             });
-        }
-        else if (state.client_action) {
+        } else if (state.client_action) {
             this.null_action();
             this.ir_actions_client(state.client_action);
         }
 
         $.when(action_loaded || null).then(function() {
             if (self.inner_viewmanager) {
-                self.inner_viewmanager.do_load_state(state);
+                self.inner_viewmanager.do_load_state(state, warm);
             }
         });
     },
@@ -205,7 +200,8 @@ session.web.ActionManager = session.web.Widget.extend({
                         on_closed();
                     }
                     self.dialog_stop();
-                }
+                },
+                error: session.webclient.crashmanager.on_rpc_error
             })
         });
     },
@@ -217,12 +213,11 @@ session.web.ActionManager = session.web.Widget.extend({
     }
 });
 
-session.web.ViewManager =  session.web.Widget.extend(/** @lends session.web.ViewManager# */{
-    identifier_prefix: "viewmanager",
+session.web.ViewManager =  session.web.OldWidget.extend(/** @lends session.web.ViewManager# */{
     template: "ViewManager",
     /**
      * @constructs session.web.ViewManager
-     * @extends session.web.Widget
+     * @extends session.web.OldWidget
      *
      * @param parent
      * @param dataset
@@ -320,11 +315,15 @@ session.web.ViewManager =  session.web.Widget.extend(/** @lends session.web.View
             this.views[view_type].deferred.resolve(view_type);
             $.when(view_promise).then(function() {
                 self.on_controller_inited(view_type, controller);
-                if (self.searchview && view.controller.searchable !== false) {
+                if (self.searchview
+                        && self.flags.auto_search
+                        && view.controller.searchable !== false) {
                     self.searchview.ready.then(self.searchview.do_search);
                 }
             });
-        } else if (this.searchview && view.controller.searchable !== false) {
+        } else if (this.searchview
+                && self.flags.auto_search
+                && view.controller.searchable !== false) {
             this.searchview.ready.then(this.searchview.do_search);
         }
 
@@ -359,17 +358,20 @@ session.web.ViewManager =  session.web.Widget.extend(/** @lends session.web.View
      * navigation history (the navigation history is appended to via
      * on_mode_switch)
      *
-     * @param {Boolean} [created=false] returning from a creation
+     * @param {Object} [options]
+     * @param {Boolean} [options.created=false] resource was created
+     * @param {String} [options.default=null] view to switch to if no previous view
      * @returns {$.Deferred} switching end signal
      */
-    on_prev_view: function (created) {
+    on_prev_view: function (options) {
+       options = options || {};
         var current_view = this.views_history.pop();
-        var previous_view = this.views_history[this.views_history.length - 1];
-        if (created && current_view === 'form' && previous_view === 'list') {
+        var previous_view = this.views_history[this.views_history.length - 1] || options['default'];
+        if (options.created && current_view === 'form' && previous_view === 'list') {
             // APR special case: "If creation mode from list (and only from a list),
             // after saving, go to page view (don't come back in list)"
             return this.on_mode_switch('page');
-        } else if (created && !previous_view && this.action && this.action.flags.default_view === 'form') {
+        } else if (options.created && !previous_view && this.action && this.action.flags.default_view === 'form') {
             // APR special case: "If creation from dashboard, we have no previous view
             return this.on_mode_switch('page');
         }
@@ -407,6 +409,9 @@ session.web.ViewManager =  session.web.Widget.extend(/** @lends session.web.View
             var groupby = results.group_by.length
                         ? results.group_by
                         : action_context.group_by;
+            if (_.isString(groupby)) {
+                groupby = [groupby];
+            }
             controller.do_search(results.domain, results.context, groupby || []);
         });
     },
@@ -458,6 +463,9 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
         // do not have it yet (and we don't, because we've not called our own
         // ``_super()``) rpc requests will blow up.
         var flags = action.flags || {};
+        if (!('auto_search' in flags)) {
+            flags.auto_search = action.auto_search !== false;
+        }
         if (action.res_model == 'board.board' && action.view_mode === 'form') {
             // Special case for Dashboards
             _.extend(flags, {
@@ -558,16 +566,44 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
             current_view = this.views[this.active_view].controller;
         switch (val) {
             case 'fvg':
-                var dialog = new session.web.Dialog(this, { title: "Fields View Get", width: '95%' }).open();
+                var dialog = new session.web.Dialog(this, { title: _t("Fields View Get"), width: '95%' }).open();
                 $('<pre>').text(session.web.json_node_to_xml(current_view.fields_view.arch, true)).appendTo(dialog.$element);
                 break;
-            case 'customize_object':
-                this.rpc('/web/dataset/search_read', {
-                    model: 'ir.model',
-                    fields: ['id'],
-                    domain: [['model', '=', this.dataset.model]]
-                }, function (result) {
-                    self.do_edit_resource('ir.model', result.ids[0], { name : "Customize Object" });
+            case 'perm_read':
+                var ids = current_view.get_selected_ids();
+                if (ids.length === 1) {
+                    this.dataset.call('perm_read', [ids]).then(function(result) {
+                        var dialog = new session.web.Dialog(this, {
+                            title: _.str.sprintf(_t("View Log (%s)"), self.dataset.model),
+                            width: 400
+                        }, QWeb.render('ViewManagerDebugViewLog', {
+                            perm : result[0],
+                            format : session.web.format_value
+                        })).open();
+                    });
+                }
+                break;
+            case 'fields':
+                this.dataset.call_and_eval(
+                        'fields_get', [false, {}], null, 1).then(function (fields) {
+                    var $root = $('<dl>');
+                    _(fields).each(function (attributes, name) {
+                        $root.append($('<dt>').append($('<h4>').text(name)));
+                        var $attrs = $('<dl>').appendTo(
+                                $('<dd>').appendTo($root));
+                        _(attributes).each(function (def, name) {
+                            if (def instanceof Object) {
+                                def = JSON.stringify(def);
+                            }
+                            $attrs
+                                .append($('<dt>').text(name))
+                                .append($('<dd style="white-space: pre-wrap;">').text(def));
+                        });
+                    });
+                    new session.web.Dialog(self, {
+                        title: _.str.sprintf(_t("Model %s fields"),
+                                             self.dataset.model),
+                        width: '95%'}, $root).open();
                 });
                 break;
             case 'manage_views':
@@ -575,7 +611,8 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
                     var view_editor = new session.web.ViewEditor(current_view, current_view.$element, this.dataset, current_view.fields_view.arch);
                     view_editor.start();
                 } else {
-                    this.do_warn("Manage Views", "Could not find current view declaration");
+                    this.do_warn(_t("Manage Views"),
+                            _t("Could not find current view declaration"));
                 }
                 break;
             case 'edit_workflow':
@@ -652,7 +689,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
             this.widget_parent.do_push_state(state);
         }
     },
-    do_load_state: function(state) {
+    do_load_state: function(state, warm) {
         var self = this,
             defs = [];
         if (state.view_type && state.view_type !== this.active_view) {
@@ -664,7 +701,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
         } 
 
         $.when(defs).then(function() {
-            self.views[self.active_view].controller.do_load_state(state);
+            self.views[self.active_view].controller.do_load_state(state, warm);
         });
     },
     shortcut_check : function(view) {
@@ -722,16 +759,21 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
         var $logs_list = $logs.find('ul').empty();
         $logs.toggleClass('oe-has-more', log_records.length > cutoff);
         _(log_records.reverse()).each(function (record) {
+            var context = {};
+            if (record.context) {
+                try { context = py.eval(record.context).toJSON(); }
+                catch (e) { /* TODO: what do I do now? */ }
+            }
             $(_.str.sprintf('<li><a href="#">%s</a></li>', record.name))
                 .appendTo($logs_list)
-                .delegate('a', 'click', function (e) {
+                .delegate('a', 'click', function () {
                     self.do_action({
                         type: 'ir.actions.act_window',
                         res_model: record.res_model,
                         res_id: record.res_id,
                         // TODO: need to have an evaluated context here somehow
-                        //context: record.context,
-                        views: [[false, 'form']]
+                        context: context,
+                        views: [[context.view_id || false, 'form']]
                     });
                     return false;
                 });
@@ -742,7 +784,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
     }
 });
 
-session.web.Sidebar = session.web.Widget.extend({
+session.web.Sidebar = session.web.OldWidget.extend({
     init: function(parent, element_id) {
         this._super(parent, element_id);
         this.items = {};
@@ -778,10 +820,6 @@ session.web.Sidebar = session.web.Widget.extend({
             }, {
                 label: _t("Export"),
                 callback: view.on_sidebar_export
-            }, {
-                label: _t("View Log"),
-                callback: view.on_sidebar_view_log,
-                classname: 'oe_hide oe_sidebar_view_log'
             }
         ]);
     },
@@ -820,18 +858,32 @@ session.web.Sidebar = session.web.Widget.extend({
         }
         return $section;
     },
-
+    /**
+     * For each item added to the section:
+     *
+     * ``label``
+     *     will be used as the item's name in the sidebar
+     *
+     * ``action``
+     *     descriptor for the action which will be executed, ``action`` and
+     *     ``callback`` should be exclusive
+     *
+     * ``callback``
+     *     function to call when the item is clicked in the sidebar, called
+     *     with the item descriptor as its first argument (so information
+     *     can be stored as additional keys on the object passed to
+     *     ``add_items``)
+     *
+     * ``classname`` (optional)
+     *     ``@class`` set on the sidebar serialization of the item
+     *
+     * ``title`` (optional)
+     *     will be set as the item's ``@title`` (tooltip)
+     *
+     * @param {String} section_code
+     * @param {Array<{label, action | callback[, classname][, title]}>} items
+     */
     add_items: function(section_code, items) {
-        // An item is a dictonary : {
-        //    label: label to be displayed for the link,
-        //    action: action to be launch when the link is clicked,
-        //    callback: a function to be executed when the link is clicked,
-        //    classname: optional dom class name for the line,
-        //    title: optional title for the link
-        // }
-        // Note: The item should have one action or/and a callback
-        //
-
         var self = this,
             $section = this.add_section(_.str.titleize(section_code.replace('_', ' ')), section_code),
             section_id = $section.attr('id');
@@ -911,8 +963,8 @@ session.web.TranslateDialog = session.web.Dialog.extend({
         // TODO fme: should add the language to fields_view_get because between the fields view get
         // and the moment the user opens the translation dialog, the user language could have been changed
         this.view_language = view.session.user_context.lang;
-        this['on_button' + _t("Save")] = this.on_button_Save;
-        this['on_button' + _t("Close")] = this.on_button_Close;
+        this['on_button_' + _t("Save")] = this.on_btn_save;
+        this['on_button_' + _t("Close")] = this.on_btn_close;
         this._super(view, {
             width: '80%',
             height: '80%'
@@ -993,9 +1045,10 @@ session.web.TranslateDialog = session.web.Dialog.extend({
             }
         });
     },
-    on_button_Save: function() {
+    on_btn_save: function() {
         var trads = {},
-            self = this;
+            self = this,
+            trads_mutex = new $.Mutex();
         self.$fields_form.find('.oe_trad_field.touched').each(function() {
             var field = $(this).attr('name').split('-');
             if (!trads[field[0]]) {
@@ -1008,13 +1061,14 @@ session.web.TranslateDialog = session.web.Dialog.extend({
                 _.each(data, function(value, field) {
                     self.view.fields[field].set_value(value);
                 });
-            } else {
-                self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
             }
+            trads_mutex.exec(function() {
+                return self.view.dataset.write(self.view.datarecord.id, data, { context : { 'lang': code } });
+            });
         });
         this.close();
     },
-    on_button_Close: function() {
+    on_btn_close: function() {
         this.close();
     }
 });
@@ -1023,6 +1077,12 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
     template: "EmptyComponent",
     // name displayed in view switchers
     display_name: '',
+    init: function(parent, dataset, view_id, options) {
+        this._super(parent);
+        this.dataset = dataset;
+        this.view_id = view_id;
+        this.set_default_options(options);
+    },
     set_default_options: function(options) {
         this.options = options || {};
         _.defaults(this.options, {
@@ -1132,7 +1192,7 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
             this.widget_parent.do_push_state(state);
         }
     },
-    do_load_state: function(state) {
+    do_load_state: function(state, warm) {
     },
     /**
      * Switches to a specific view type
@@ -1143,8 +1203,12 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
     },
     /**
      * Cancels the switch to the current view, switches to the previous one
+     *
+     * @param {Object} [options]
+     * @param {Boolean} [options.created=false] resource was created
+     * @param {String} [options.default=null] view to switch to if no previous view
      */
-    do_prev_view: function () { 
+    do_prev_view: function (options) {
     },
     do_search: function(view) {
     },
@@ -1169,8 +1233,6 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
             view_mode : "list"
         });
     },
-    on_sidebar_view_log: function() {
-    },
     sidebar_context: function () {
         return $.when();
     },
@@ -1185,7 +1247,7 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
 
 session.web.json_node_to_xml = function(node, human_readable, indent) {
     // For debugging purpose, this function will convert a json node back to xml
-    // Maybe usefull for xml view editor
+    // Maybe useful for xml view editor
     indent = indent || 0;
     var sindent = (human_readable ? (new Array(indent + 1).join('\t')) : ''),
         r = sindent + '<' + node.tag,