[MERGE] forward port of branch saas-3 up to fdc6271
[odoo/odoo.git] / addons / web / static / src / js / chrome.js
index f9085af..f965879 100644 (file)
@@ -46,6 +46,8 @@ instance.web.Notification =  instance.web.Widget.extend({
     }
 });
 
+var opened_modal = [];
+
 instance.web.action_notify = function(element, action) {
     element.do_notify(action.params.title, action.params.text, action.params.sticky);
 };
@@ -71,6 +73,8 @@ instance.web.Dialog = instance.web.Widget.extend({
         @param {Widget} parent
         @param {dictionary} options A dictionary that will be forwarded to jQueryUI Dialog. Additionaly, that
             dictionary can contain the following keys:
+            - size: one of the following: 'large', 'medium', 'small'
+            - dialogClass: class to add to the body of dialog
             - buttons: Deprecated. The buttons key is not propagated to jQueryUI Dialog. It must be a dictionary (key = button
                 label, value = click handler) or a list of dictionaries (each element in the dictionary is send to the
                 corresponding method of a jQuery element targeting the <button> tag). It is deprecated because all dialogs
@@ -81,19 +85,11 @@ instance.web.Dialog = instance.web.Widget.extend({
     */
     init: function (parent, options, content) {
         var self = this;
-        this.css_layout_outer = ['width','min_width','max_width'];
-        this.css_layout_inner = ['height','min_height','max_height'];
         this._super(parent);
         this.content_to_set = content;
         this.dialog_options = {
             destroy_on_close: true,
-            width: 900,
-            min_width: 0,
-            max_width: '95%',
-            height: 'auto',
-            min_height: 0,
-            max_height: $(window.top).height() - 200,
-            resizable: true,
+            size: 'large', //'medium', 'small'
             buttons: null,
         };
         if (options) {
@@ -102,51 +98,6 @@ instance.web.Dialog = instance.web.Widget.extend({
         this.on("closing", this, this._closing);
         this.$buttons = $('<div class="modal-footer"><span class="oe_dialog_custom_buttons"/></div>');
     },
-    _get_options: function() {
-        var self = this;
-        var o = _.extend({}, this.dialog_options);
-        var sizes = {
-            width: $(window.top).width(),
-            height: $(window.top).height(),
-        };
-        _.each(sizes, function(available_size, unit) {
-            o[unit] = self._get_size(o[unit], available_size);
-            o['min_' + unit] = self._get_size(o['min_' + unit] || 0, available_size);
-            o['max_' + unit] = self._get_size(o['max_' + unit] || 0, available_size);
-            if (o[unit] !== 'auto' && o['min_' + unit] && o[unit] < o['min_' + unit]) {
-                o[unit] = o['min_' + unit];
-            }
-            if (o[unit] !== 'auto' && o['max_' + unit] && o[unit] > o['max_' + unit]) {
-                o[unit] = o['max_' + unit];
-            }
-        });
-        var layout_inner = {};
-        var layout_outer = {};
-        _.each(o, function(value,key){
-            if (_.contains(self.css_layout_inner, ''+key+'')){
-                layout_inner[key] = value;
-                delete o[key];
-            }
-            if (_.contains(self.css_layout_outer, ''+key+'')){
-                layout_outer[key] = value;
-                delete o[key];
-            }
-        });
-        o.layout_inner = layout_inner;
-        o.layout_outer = layout_outer;
-        o.title = o.title || this.dialog_title;
-        return o;
-    },
-    _get_size: function(val, available_size) {
-        val = val.toString();
-        if (val === 'auto') {
-            return val;
-        } else if (val.slice(-1) === "%") {
-            return Math.round(available_size / 100 * parseInt(val.slice(0, -1), 10));
-        } else {
-            return parseInt(val, 10);
-        }
-    },
     renderElement: function() {
         if (this.content_to_set) {
             this.setElement(this.content_to_set);
@@ -164,6 +115,9 @@ instance.web.Dialog = instance.web.Widget.extend({
             this.init_dialog();
         }
         this.$buttons.insertAfter(this.$dialog_box.find(".modal-body"));
+        $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal is opened
+        //add to list of currently opened modal
+        opened_modal.push(this.$dialog_box);
         return this;
     },
     _add_buttons: function(buttons) {
@@ -189,7 +143,8 @@ instance.web.Dialog = instance.web.Widget.extend({
     */
     init_dialog: function() {
         var self = this;
-        var options = this._get_options();
+        var options = _.extend({}, this.dialog_options);
+        options.title = options.title || this.dialog_title;
         if (options.buttons) {
             this._add_buttons(options.buttons);
             delete(options.buttons);
@@ -201,46 +156,41 @@ instance.web.Dialog = instance.web.Widget.extend({
             'backdrop': false,
             'keyboard': true,
         });
-        this.$el.appendTo(this.$dialog_box.find(".modal-body"));
-        var dialog_body = this.$dialog_box.find('.modal-content');
-        if (options.layout_outer || options.layout_inner){
-            dialog_body.parent().css(options.layout_outer);
-            dialog_body.css(options.layout_inner);
+        if (options.size !== 'large'){
+            var dialog_class_size = this.$dialog_box.find('.modal-lg').removeClass('modal-lg');
+            if (options.size === 'small'){
+                dialog_class_size.addClass('modal-sm');
+            }
         }
+
+        this.$el.appendTo(this.$dialog_box.find(".modal-body"));
+        var $dialog_content = this.$dialog_box.find('.modal-content');
         if (options.dialogClass){
-            dialog_body.find(".modal-body").addClass(options.dialogClass);
+            $dialog_content.find(".modal-body").addClass(options.dialogClass);
         }
-        dialog_body.openerpClass();
-        dialog_body.draggable({ handle: ".modal-header", containment: "window" });
-        this.$dialog_box.on('hidden.bs.modal',this,function(){
-            self.trigger("closing");
+        $dialog_content.openerpClass();
+
+        this.$dialog_box.on('hidden.bs.modal', this, function() {
+            self.close();
         });
         this.$dialog_box.modal('show');
 
-        if (options.layout_inner.height === 'auto' && options.layout_inner.max_height) {
-            this.$el.css({ 'max-height': options.layout_inner.max_height, 'overflow-y': 'auto' });
-        }
-        var dialog_body = this.$dialog_box.find('.modal-content');
-        if (options.resizable){
-            dialog_body.resizable({ handles: 'n, e, s, w, ne, se, sw, nw' });
-        }
-        dialog_body.resize(function() {
-            var main_modal = dialog_body.parent();
-            var modal_body = main_modal.find(".modal-body .in");
-            var modal_content = main_modal.find(".modal-content").height();
-            modal_body.height(modal_content - 150);
-            main_modal.find(".modal-content").height((modal_body.height() + main_modal.find(".modal-header").height() + main_modal.find(".modal-footer").height()) + 85);
-        });
         this.dialog_inited = true;
         var res = this.start();
         return res;
     },
     /**
-        Closes the popup, if destroy_on_close was passed to the constructor, it is also destroyed.
+        Closes (hide) the popup, if destroy_on_close was passed to the constructor, it will be destroyed instead.
     */
     close: function(reason) {
-        if (this.dialog_inited && this.$el.is(":data(bs.modal)")) {
-            this.$el.parents('.modal').modal('hide');
+        if (this.dialog_inited && !this.__tmp_dialog_hiding) {
+            $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal has disappeared
+            if (this.$el.is(":data(bs.modal)")) {     // may have been destroyed by closing signal
+                this.__tmp_dialog_hiding = true;
+                this.$dialog_box.modal('hide');
+                this.__tmp_dialog_hiding = undefined;
+            }
+            this.trigger("closing", reason);
         }
     },
     _closing: function() {
@@ -257,6 +207,7 @@ instance.web.Dialog = instance.web.Widget.extend({
     */
     destroy: function (reason) {
         this.$buttons.remove();
+        var self = this;
         _.each(this.getChildren(), function(el) {
             el.destroy();
         });
@@ -266,7 +217,21 @@ instance.web.Dialog = instance.web.Widget.extend({
             this.__tmp_dialog_destroying = undefined;
         }
         if (this.dialog_inited && !this.isDestroyed() && this.$el.is(":data(bs.modal)")) {
-            this.$el.parents('.modal').remove();
+            //we need this to put the instruction to remove modal from DOM at the end
+            //of the queue, otherwise it might already have been removed before the modal-backdrop
+            //is removed when pressing escape key
+            var $element = this.$dialog_box;
+            setTimeout(function () {
+                //remove modal from list of opened modal since we just destroy it
+                var modal_list_index = $.inArray($element, opened_modal);
+                if (modal_list_index > -1){
+                    opened_modal.splice(modal_list_index,1)[0].remove();
+                }
+                if (opened_modal.length > 0){
+                    //we still have other opened modal so we should focus it
+                    opened_modal[opened_modal.length-1].focus();
+                }
+            },0);
         }
         this._super();
     }
@@ -290,8 +255,7 @@ instance.web.CrashManager = instance.web.Class.extend({
             this.show_warning({type: "Session Expired", data: { message: _t("Your OpenERP session expired. Please refresh the current web page.") }});
             return;
         }
-        if (error.data.exception_type === "except_osv" || error.data.exception_type === "warning"
-                || error.data.exception_type === "access_error") {
+        if (error.data.exception_type === "except_osv" || error.data.exception_type === "warning" || error.data.exception_type === "access_error") {
             this.show_warning(error);
         } else {
             this.show_error(error);
@@ -305,6 +269,7 @@ instance.web.CrashManager = instance.web.Class.extend({
             error = _.extend({}, error, {data: _.extend({}, error.data, {message: error.data.arguments[0] + "\n\n" + error.data.arguments[1]})});
         }
         new instance.web.Dialog(this, {
+            size: 'medium',
             title: "OpenERP " + (_.str.capitalize(error.type) || "Warning"),
             buttons: [
                 {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
@@ -321,7 +286,6 @@ instance.web.CrashManager = instance.web.Class.extend({
         };
         new instance.web.Dialog(this, {
             title: "OpenERP " + _.str.capitalize(error.type),
-            width: '80%',
             buttons: buttons
         }, QWeb.render('CrashManager.error', {session: instance.session, error: error})).open();
     },
@@ -371,6 +335,7 @@ instance.web.RedirectWarningHandler = instance.web.Dialog.extend(instance.web.Ex
         error.data.message = error.data.arguments[0];
 
         new instance.web.Dialog(this, {
+            size: 'medium',
             title: "OpenERP " + (_.str.capitalize(error.type) || "Warning"),
             buttons: [
                 {text: _t("Ok"), click: function() { this.$el.parents('.modal').modal('hide'); }},
@@ -379,7 +344,7 @@ instance.web.RedirectWarningHandler = instance.web.Dialog.extend(instance.web.Ex
                     this.$el.parents('.modal').modal('hide');
                 }}
             ],
-        }, QWeb.render('CrashManager.warning', {error: error}));
+        }, QWeb.render('CrashManager.warning', {error: error})).open();
         this.destroy();
     }
 });
@@ -527,9 +492,10 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
      */
     display_error: function (error) {
         return new instance.web.Dialog(this, {
+            size: 'medium',
             title: error.title,
             buttons: [
-                {text: _t("Ok"), click: function() { this.$el.parents('.modal').modal('hide'); }}
+                {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
             ]
         }, $('<div>').html(error.error)).open();
     },
@@ -742,7 +708,7 @@ instance.web.ChangePassword =  instance.web.Widget.extend({
         var $button = self.$el.find('.oe_form_button');
         $button.appendTo(this.getParent().$buttons);
         $button.eq(2).click(function(){
-           self.getParent().close();
+           self.$el.parents('.modal').modal('hide');
         });
         $button.eq(0).click(function(){
           self.rpc("/web/session/change_password",{
@@ -759,9 +725,10 @@ instance.web.ChangePassword =  instance.web.Widget.extend({
     },
     display_error: function (error) {
         return new instance.web.Dialog(this, {
+            size: 'medium',
             title: error.title,
             buttons: [
-                {text: _t("Ok"), click: function() { this.$el.parents('.modal').modal('hide'); }}
+                {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
             ]
         }, $('<div>').html(error.error)).open();
     },
@@ -907,6 +874,10 @@ instance.web.Menu =  instance.web.Widget.extend({
                 $clicked_menu.parent().addClass('active');
             }
         }
+        // add a tooltip to cropped menu items
+        this.$secondary_menus.find('.oe_secondary_submenu li a span').each(function() {
+            $(this).tooltip(this.scrollWidth > this.clientWidth ? {title: $(this).text().trim(), placement: 'auto right'} :'destroy');
+       });
     },
     /**
      * Call open_menu with the first menu_item matching an action_id
@@ -1037,7 +1008,7 @@ instance.web.UserMenu =  instance.web.Widget.extend({
         this.update_promise = this.update_promise.then(fct, fct);
     },
     on_menu_help: function() {
-        window.open('http://help.openerp.com', '_blank');
+        window.open('http://help.odoo.com', '_blank');
     },
     on_menu_logout: function() {
         this.trigger('user_logout');
@@ -1066,7 +1037,10 @@ instance.web.UserMenu =  instance.web.Widget.extend({
                     state: JSON.stringify(state),
                     scope: 'userinfo',
                 };
-                instance.web.redirect('https://accounts.openerp.com/oauth2/auth?'+$.param(params));
+                instance.web.redirect('https://accounts.odoo.com/oauth2/auth?'+$.param(params));
+            }).fail(function(result, ev){
+                ev.preventDefault();
+                instance.web.redirect('https://accounts.odoo.com/web');
             });
         }
     },
@@ -1079,9 +1053,9 @@ instance.web.UserMenu =  instance.web.Widget.extend({
                 window.location = $.param.querystring( window.location.href, 'debug');
             });
             new instance.web.Dialog(this, {
-                resizable: false,
+                size: 'medium',
+                dialogClass: 'oe_act_window',
                 title: _t("About"),
-                width: 507, height: 290,
             }, $help).open();
         });
     },
@@ -1126,8 +1100,8 @@ instance.web.Client = instance.web.Widget.extend({
     },
     bind_events: function() {
         var self = this;
-        this.$el.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() {
-            $(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter');
+        this.$el.on('mouseenter', '.oe_systray > div:not([data-toggle=tooltip])', function() {
+            $(this).attr('data-toggle', 'tooltip').tooltip().trigger('mouseenter');
         });
         this.$el.on('click', '.oe_dropdown_toggle', function(ev) {
             ev.preventDefault();
@@ -1151,7 +1125,7 @@ instance.web.Client = instance.web.Widget.extend({
             }, 0);
         });
         instance.web.bus.on('click', this, function(ev) {
-            $.fn.tipsy.clear();
+            $('.tooltip').remove();
             if (!$(ev.target).is('input[type=file]')) {
                 self.$el.find('.oe_dropdown_menu.oe_opened, .oe_dropdown_toggle.oe_opened').removeClass('oe_opened');
             }
@@ -1505,7 +1479,7 @@ instance.web.embed = function (origin, dbname, login, key, action, options) {
     $('head').append($('<link>', {
         'rel': 'stylesheet',
         'type': 'text/css',
-        'href': origin +'/web/webclient/css'
+        'href': origin +'/web/css/web.assets_webclient'
     }));
     var currentScript = document.currentScript;
     if (!currentScript) {