[MERGE] forward port of branch 8.0 up to 2b192be
[odoo/odoo.git] / addons / web / static / src / js / views.js
index dc9f706..2484363 100644 (file)
@@ -271,7 +271,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
                     }
                     action_loaded = this.do_action(state.action, { additional_context: add_context });
                     $.when(action_loaded || null).done(function() {
-                        instance.webclient.menu.has_been_loaded.done(function() {
+                        instance.webclient.menu.is_bound.done(function() {
                             if (self.inner_action && self.inner_action.id) {
                                 instance.webclient.menu.open_action(self.inner_action.id);
                             }
@@ -339,11 +339,18 @@ instance.web.ActionManager = instance.web.Widget.extend({
             return this.do_action(action_client, options);
         } else if (_.isNumber(action) || _.isString(action)) {
             var self = this;
-            return self.rpc("/web/action/load", { action_id: action }).then(function(result) {
+            var additional_context = {
+                active_id : options.additional_context.active_id,
+                active_ids : options.additional_context.active_ids,
+                active_model : options.additional_context.active_model
+            };
+            return self.rpc("/web/action/load", { action_id: action, additional_context : additional_context }).then(function(result) {
                 return self.do_action(result, options);
             });
         }
 
+        instance.web.bus.trigger('action', action);
+
         // Ensure context & domain are evaluated and can be manipulated/used
         var ncontext = new instance.web.CompoundContext(options.additional_context, action.context || {});
         action.context = instance.web.pyeval.eval('context', ncontext);
@@ -405,15 +412,36 @@ instance.web.ActionManager = instance.web.Widget.extend({
         }
         var widget = executor.widget();
         if (executor.action.target === 'new') {
+            var pre_dialog = (this.dialog && !this.dialog.isDestroyed()) ? this.dialog : null;
+            if (pre_dialog){
+                // prevent previous dialog to consider itself closed,
+                // right now, as we're opening a new one (prevents
+                // reload of original form view)
+                pre_dialog.off('closing', null, pre_dialog.on_close);
+            }
             if (this.dialog_widget && !this.dialog_widget.isDestroyed()) {
                 this.dialog_widget.destroy();
             }
+            // explicitly passing a closing action to dialog_stop() prevents
+            // it from reloading the original form view
             this.dialog_stop(executor.action);
             this.dialog = new instance.web.Dialog(this, {
                 title: executor.action.name,
                 dialogClass: executor.klass,
             });
-            this.dialog.on("closing", null, options.on_close);
+
+            // chain on_close triggers with previous dialog, if any
+            this.dialog.on_close = function(){
+                options.on_close.apply(null, arguments);
+                if (pre_dialog && pre_dialog.on_close){
+                    // no parameter passed to on_close as this will
+                    // only be called when the last dialog is truly
+                    // closing, and *should* trigger a reload of the
+                    // underlying form view (see comments above)
+                    pre_dialog.on_close();
+                }
+            };
+            this.dialog.on("closing", null, this.dialog.on_close);
             if (widget instanceof instance.web.ViewManager) {
                 _.extend(widget.flags, {
                     $buttons: this.dialog.$buttons,
@@ -426,6 +454,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
             this.dialog.open();
             return initialized;
         } else  {
+            // explicitly passing a closing action to dialog_stop() prevents
+            // it from reloading the original form view - we're opening a
+            // completely new action anyway
             this.dialog_stop(executor.action);
             this.inner_action = executor.action;
             this.inner_widget = widget;
@@ -451,6 +482,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
     ir_actions_client: function (action, options) {
         var self = this;
         var ClientWidget = instance.web.client_actions.get_object(action.tag);
+        if (!ClientWidget) {
+            return self.do_warn("Action Error", "Could not find client action '" + action.tag + "'.");
+        }
 
         if (!(ClientWidget.prototype instanceof instance.web.Widget)) {
             var next;
@@ -581,7 +615,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         var self = this;
         this.$el.find('.oe_view_manager_switch a').click(function() {
             self.switch_mode($(this).data('view-type'));
-        }).tipsy();
+        }).tooltip();
         var views_ids = {};
         _.each(this.views_src, function(view) {
             self.views[view.view_type] = $.extend({}, view, {
@@ -595,7 +629,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
                     action_views_ids : views_ids
                 }, self.flags, self.flags[view.view_type] || {}, view.options || {})
             });
-            
+
             views_ids[view.view_type] = view.view_id;
         });
         if (this.flags.views_switcher === false) {
@@ -603,11 +637,10 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         }
         // If no default view defined, switch to the first one in sequence
         var default_view = this.flags.default_view || this.views_src[0].view_type;
-  
 
         return this.switch_mode(default_view, null, this.flags[default_view] && this.flags[default_view].options);
-      
-        
+
+
     },
     switch_mode: function(view_type, no_store, view_options) {
         var self = this;
@@ -615,7 +648,6 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         var view_promise;
         var form = this.views['form'];
         if (!view || (form && form.controller && !form.controller.can_be_discarded())) {
-            self.trigger('switch_mode', view_type, no_store, view_options);
             return $.Deferred().reject();
         }
         if (!no_store) {
@@ -644,7 +676,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
             _.each(_.keys(self.views), function(view_name) {
                 var controller = self.views[view_name].controller;
                 if (controller) {
-                    var container = self.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_name);
+                    var container = self.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_name);
                     if (view_name === view_type) {
                         container.show();
                         controller.do_show(view_options || {});
@@ -686,12 +718,12 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         }
         controller.on('switch_mode', self, this.switch_mode);
         controller.on('previous_view', self, this.prev_view);
-        
-        var container = this.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_type);
+
+        var container = this.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_type);
         var view_promise = controller.appendTo(container);
         this.views[view_type].controller = controller;
-        this.views[view_type].deferred.resolve(view_type);
         return $.when(view_promise).done(function() {
+            self.views[view_type].deferred.resolve(view_type);
             if (self.searchview
                     && self.flags.auto_search
                     && view.controller.searchable !== false) {
@@ -702,6 +734,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
             self.trigger("controller_inited",view_type,controller);
         });
     },
+
     /**
      * @returns {Number|Boolean} the view id of the given type, false if not found
      */
@@ -723,6 +756,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
                 }
                 views.push(mode);
             }
+            instance.web.bus.trigger('view_switch_mode', self, mode);
         });
         var item = _.extend({
             widget: this,
@@ -797,6 +831,7 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         if (this.searchview) {
             this.searchview.destroy();
         }
+
         var options = {
             hidden: this.flags.search_view === false,
             disable_custom_filters: this.flags.search_disable_custom_filters,
@@ -804,7 +839,8 @@ instance.web.ViewManager =  instance.web.Widget.extend({
         this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, options);
 
         this.searchview.on('search_data', self, this.do_searchview_search);
-        return this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search"));
+        return this.searchview.appendTo(this.$(".oe_view_manager_view_search"),
+                                      this.$(".oe_searchview_drawer_container"));
     },
     do_searchview_search: function(domains, contexts, groupbys) {
         var self = this,
@@ -882,7 +918,20 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
         this._super(parent, null, action.views, flags);
         this.session = parent.session;
         this.action = action;
-        var dataset = new instance.web.DataSetSearch(this, action.res_model, action.context, action.domain);
+        var context = action.context;
+        if (action.target === 'current'){
+            var active_context = {
+                active_model: action.res_model,
+            };
+            context = new instance.web.CompoundContext(context, active_context).eval();
+            delete context['active_id'];
+            delete context['active_ids'];
+            if (action.res_id){
+                context['active_id'] = action.res_id;
+                context['active_ids'] = [action.res_id];
+            }
+        }
+        var dataset = new instance.web.DataSetSearch(this, action.res_model, context, action.domain);
         if (action.res_id) {
             dataset.ids.push(action.res_id);
             dataset.index = 0;
@@ -937,12 +986,12 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
                     url: '/web/tests?mod=*'
                 });
                 break;
-            case 'perm_read':
+            case 'get_metadata':
                 var ids = current_view.get_selected_ids();
                 if (ids.length === 1) {
-                    this.dataset.call('perm_read', [ids]).done(function(result) {
+                    this.dataset.call('get_metadata', [ids]).done(function(result) {
                         var dialog = new instance.web.Dialog(this, {
-                            title: _.str.sprintf(_t("View Log (%s)"), self.dataset.model),
+                            title: _.str.sprintf(_t("Metadata (%s)"), self.dataset.model),
                             size: 'medium',
                         }, QWeb.render('ViewManagerDebugViewLog', {
                             perm : result[0],
@@ -1103,9 +1152,9 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
                     return self.switch_mode(state.view_type, true);
                 })
             );
-        } 
+        }
 
-        $.when(defs).done(function() {
+        $.when(this.views[this.active_view] ? this.views[this.active_view].deferred : $.when(), defs).done(function() {
             self.views[self.active_view].controller.do_load_state(state, warm);
         });
     },
@@ -1157,10 +1206,8 @@ instance.web.Sidebar = instance.web.Widget.extend({
         this.$('.oe_form_dropdown_section').each(function() {
             $(this).toggle(!!$(this).find('li').length);
         });
-
-        self.$("[title]").tipsy({
-            'html': true,
-            'delayIn': 500,
+        self.$("[title]").tooltip({
+            delay: { show: 500, hide: 0}
         });
     },
     /**
@@ -1191,7 +1238,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
     add_items: function(section_code, items) {
         var self = this;
         if (items) {
-            this.items[section_code].push.apply(this.items[section_code],items);
+            this.items[section_code].unshift.apply(this.items[section_code],items);
             this.redraw();
         }
     },
@@ -1427,12 +1474,12 @@ instance.web.View = instance.web.Widget.extend({
         if (action_data.special === 'cancel') {
             return handler({"type":"ir.actions.act_window_close"});
         } else if (action_data.type=="object") {
-            var args = [[record_id]], additional_args = [];
+            var args = [[record_id]];
             if (action_data.args) {
                 try {
                     // Warning: quotes and double quotes problem due to json and xml clash
                     // Maybe we should force escaping in xml or do a better parse of the args array
-                    additional_args = JSON.parse(action_data.args.replace(/'/g, '"'));
+                    var additional_args = JSON.parse(action_data.args.replace(/'/g, '"'));
                     args = args.concat(additional_args);
                 } catch(e) {
                     console.error("Could not JSON.parse arguments", action_data.args);
@@ -1447,7 +1494,7 @@ instance.web.View = instance.web.Widget.extend({
         } else if (action_data.type=="action") {
             return this.rpc('/web/action/load', {
                 action_id: action_data.name,
-                context: _.extend({'active_model': dataset.model, 'active_ids': dataset.ids, 'active_id': record_id}, instance.web.pyeval.eval('context', context)),
+                context: _.extend(instance.web.pyeval.eval('context', context), {'active_model': dataset.model, 'active_ids': dataset.ids, 'active_id': record_id}),
                 do_not_eval: true
             }).then(handler);
         } else  {
@@ -1466,6 +1513,7 @@ instance.web.View = instance.web.Widget.extend({
     },
     do_show: function () {
         this.$el.show();
+        instance.web.bus.trigger('view_shown', this);
     },
     do_hide: function () {
         this.$el.hide();
@@ -1501,18 +1549,10 @@ instance.web.View = instance.web.Widget.extend({
     /**
      * Switches to a specific view type
      */
-    do_switch_view: function() { 
+    do_switch_view: function() {
         this.trigger.apply(this, ['switch_mode'].concat(_.toArray(arguments)));
     },
-    /**
-     * 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_search: function(view) {
+    do_search: function(domain, context, group_by) {
     },
     on_sidebar_export: function() {
         new instance.web.DataExport(this, this.dataset).open();
@@ -1573,7 +1613,12 @@ instance.web.fields_view_get = function(args) {
     if (typeof model === 'string') {
         model = new instance.web.Model(args.model, args.context);
     }
-    return args.model.call('fields_view_get', [args.view_id, args.view_type, args.context, args.toolbar]).then(function(fvg) {
+    return args.model.call('fields_view_get', {
+        view_id: args.view_id,
+        view_type: args.view_type,
+        context: args.context,
+        toolbar: args.toolbar
+    }).then(function(fvg) {
         return postprocess(fvg);
     });
 };