[MERGE] forward port of branch saas-3 up to fdc6271
[odoo/odoo.git] / addons / web / static / src / js / chrome.js
index 3ad8c60..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);
 };
@@ -57,16 +59,6 @@ instance.web.action_warn = function(element, action) {
 instance.web.client_actions.add("action_warn", "instance.web.action_warn");
 
 /**
- * The very minimal function everything should call to create a dialog
- * in OpenERP Web Client.
- */
-instance.web.dialog = function(element) {
-    var result = element.dialog.apply(element, _.rest(_.toArray(arguments)));
-    result.dialog("widget").openerpClass();
-    return result;
-};
-
-/**
     A useful class to handle dialogs.
 
     Attributes:
@@ -81,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
@@ -94,57 +88,15 @@ instance.web.Dialog = instance.web.Widget.extend({
         this._super(parent);
         this.content_to_set = content;
         this.dialog_options = {
-            modal: true,
             destroy_on_close: true,
-            width: 900,
-            min_width: 0,
-            max_width: '95%',
-            height: 'auto',
-            min_height: 0,
-            max_height: $(window.top).height() - 200,
-            autoOpen: false,
-            position: [false, 40],
+            size: 'large', //'medium', 'small'
             buttons: null,
-            resizeStop: function() {
-                self.trigger("resized");
-            },
         };
         if (options) {
             _.extend(this.dialog_options, options);
         }
         this.on("closing", this, this._closing);
-        this.$buttons = $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"><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];
-            }
-        });
-        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);
-        }
+        this.$buttons = $('<div class="modal-footer"><span class="oe_dialog_custom_buttons"/></div>');
     },
     renderElement: function() {
         if (this.content_to_set) {
@@ -162,8 +114,10 @@ instance.web.Dialog = instance.web.Widget.extend({
         if (!this.dialog_inited) {
             this.init_dialog();
         }
-        this.$el.dialog('open');
-        this.$el.dialog("widget").append(this.$buttons);
+        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) {
@@ -188,31 +142,55 @@ instance.web.Dialog = instance.web.Widget.extend({
         @return The result returned by start().
     */
     init_dialog: function() {
-        var options = this._get_options();
+        var self = this;
+        var options = _.extend({}, this.dialog_options);
+        options.title = options.title || this.dialog_title;
         if (options.buttons) {
             this._add_buttons(options.buttons);
             delete(options.buttons);
         }
         this.renderElement();
-        instance.web.dialog(this.$el, options);
-        if (options.height === 'auto' && options.max_height) {
-            this.$el.css({ 'max-height': options.max_height, 'overflow-y': 'auto' });
+
+        this.$dialog_box = $(QWeb.render('Dialog', options)).appendTo("body");
+        this.$el.modal({
+            'backdrop': false,
+            'keyboard': true,
+        });
+        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');
+            }
         }
-        var self = this;
-        this.$el.on('dialogclose', function() { self.close(); });
+
+        this.$el.appendTo(this.$dialog_box.find(".modal-body"));
+        var $dialog_content = this.$dialog_box.find('.modal-content');
+        if (options.dialogClass){
+            $dialog_content.find(".modal-body").addClass(options.dialogClass);
+        }
+        $dialog_content.openerpClass();
+
+        this.$dialog_box.on('hidden.bs.modal', this, function() {
+            self.close();
+        });
+        this.$dialog_box.modal('show');
+
         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.trigger("closing", reason);
-            if (this.$el.is(":data(dialog)")) {     // may have been destroyed by closing signal
-                this.$el.dialog('close');
+        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() {
@@ -229,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();
         });
@@ -237,8 +216,22 @@ instance.web.Dialog = instance.web.Widget.extend({
             this.close(reason);
             this.__tmp_dialog_destroying = undefined;
         }
-        if (this.dialog_inited && !this.isDestroyed() && this.$el.is(":data(dialog)")) {
-            this.$el.dialog('destroy');
+        if (this.dialog_inited && !this.isDestroyed() && this.$el.is(":data(bs.modal)")) {
+            //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();
     }
@@ -262,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);
@@ -276,12 +268,13 @@ instance.web.CrashManager = instance.web.Class.extend({
         if (error.data.exception_type === "except_osv") {
             error = _.extend({}, error, {data: _.extend({}, error.data, {message: error.data.arguments[0] + "\n\n" + error.data.arguments[1]})});
         }
-        instance.web.dialog($('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>'), {
+        new instance.web.Dialog(this, {
+            size: 'medium',
             title: "OpenERP " + (_.str.capitalize(error.type) || "Warning"),
             buttons: [
-                {text: _t("Ok"), click: function() { $(this).dialog("close"); }}
-            ]
-        });
+                {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
+            ],
+        }, $('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>')).open();
     },
     show_error: function(error) {
         if (!this.active) {
@@ -289,17 +282,12 @@ instance.web.CrashManager = instance.web.Class.extend({
         }
         var buttons = {};
         buttons[_t("Ok")] = function() {
-            $(this).dialog("close");
+            this.parents('.modal').modal('hide');
         };
-        var dialog = new instance.web.Dialog(this, {
+        new instance.web.Dialog(this, {
             title: "OpenERP " + _.str.capitalize(error.type),
-            width: '80%',
-            height: '50%',
-            min_width: '800px',
-            min_height: '600px',
             buttons: buttons
-        }).open();
-        dialog.$el.html(QWeb.render('CrashManager.error', {session: instance.session, error: error}));
+        }, QWeb.render('CrashManager.error', {session: instance.session, error: error})).open();
     },
     show_message: function(exception) {
         this.show_error({
@@ -346,16 +334,17 @@ instance.web.RedirectWarningHandler = instance.web.Dialog.extend(instance.web.Ex
         error = this.error;
         error.data.message = error.data.arguments[0];
 
-        instance.web.dialog($('<div>' + QWeb.render('CrashManager.warning', {error: error}) + '</div>'), {
+        new instance.web.Dialog(this, {
+            size: 'medium',
             title: "OpenERP " + (_.str.capitalize(error.type) || "Warning"),
             buttons: [
-                {text: _t("Ok"), click: function() { $(this).dialog("close"); }},
+                {text: _t("Ok"), click: function() { this.$el.parents('.modal').modal('hide'); }},
                 {text: error.data.arguments[2], click: function() {
                     window.location.href='#action='+error.data.arguments[1];
-                    $(this).dialog("close");
+                    this.$el.parents('.modal').modal('hide');
                 }}
-            ]
-        });
+            ],
+        }, QWeb.render('CrashManager.warning', {error: error})).open();
         this.destroy();
     }
 });
@@ -502,20 +491,20 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
      * @param {String} error.error message of the error dialog
      */
     display_error: function (error) {
-        return instance.web.dialog($('<div>'), {
-            modal: true,
+        return new instance.web.Dialog(this, {
+            size: 'medium',
             title: error.title,
             buttons: [
-                {text: _t("Ok"), click: function() { $(this).dialog("close"); }}
+                {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
             ]
-        }).html(error.error);
+        }, $('<div>').html(error.error)).open();
     },
     do_create: function(form) {
         var self = this;
         var fields = $(form).serializeArray();
         self.rpc("/web/database/create", {'fields': fields}).done(function(result) {
             if (result) {
-                instance.web.redirect('/web')
+                instance.web.redirect('/web');
             } else {
                 alert("Failed to create database");
             }
@@ -719,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",{
@@ -735,13 +724,13 @@ instance.web.ChangePassword =  instance.web.Widget.extend({
        });
     },
     display_error: function (error) {
-        return instance.web.dialog($('<div>'), {
-            modal: true,
+        return new instance.web.Dialog(this, {
+            size: 'medium',
             title: error.title,
             buttons: [
-                {text: _t("Ok"), click: function() { $(this).dialog("close"); }}
+                {text: _t("Ok"), click: function() { this.parents('.modal').modal('hide'); }}
             ]
-        }).html(error.error);
+        }, $('<div>').html(error.error)).open();
     },
 });
 instance.web.client_actions.add("change_password", "instance.web.ChangePassword");
@@ -885,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
@@ -1059,8 +1052,11 @@ instance.web.UserMenu =  instance.web.Widget.extend({
                 e.preventDefault();
                 window.location = $.param.querystring( window.location.href, 'debug');
             });
-            instance.web.dialog($help, {autoOpen: true,
-                modal: true, width: 507, height: 290, resizable: false, title: _t("About")});
+            new instance.web.Dialog(this, {
+                size: 'medium',
+                dialogClass: 'oe_act_window',
+                title: _t("About"),
+            }, $help).open();
         });
     },
 });
@@ -1104,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();
@@ -1129,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');
             }
@@ -1483,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) {
@@ -1494,24 +1490,6 @@ instance.web.embed = function (origin, dbname, login, key, action, options) {
     client.insertAfter(currentScript);
 };
 
-openerp.web.LoginForm = openerp.web.Widget.extend({
-    init: function ($form) {
-        this._super(/* no parent */);
-        this.setElement($form);
-        this.$el.on('submit', this.on_submit);
-        this.start();
-    },
-    start: function () {
-        if (location.hash) {
-            this.$el.attr('action', this.$el.attr('action') + location.hash);
-        }
-        return this._super();
-    },
-    on_submit: function () {
-        return true;
-    },
-});
-
 })();
 
 // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: