diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-05-04 16:10:50 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-05-04 16:10:50 +0200 |
| commit | ac63dfc8f48fa6451b4ef94e24e784f252b84f8e (patch) | |
| tree | 768b741e1a34a94b95977d8ff869143aab73617e /addons/mail | |
| parent | 62705aee69460457c1b9257ac30363754c60c973 (diff) | |
| parent | 8dade01e2c5b560864291fb3c437ccf5999aee12 (diff) | |
[MERGE] forward port branch 11.0 up to 8dade01e2c5
Diffstat (limited to 'addons/mail')
| -rw-r--r-- | addons/mail/models/ir_model.py | 6 | ||||
| -rw-r--r-- | addons/mail/models/mail_activity.py | 2 | ||||
| -rw-r--r-- | addons/mail/models/res_users.py | 13 | ||||
| -rw-r--r-- | addons/mail/static/src/js/chat_window.js | 6 | ||||
| -rw-r--r-- | addons/mail/static/src/js/composer.js | 6 | ||||
| -rw-r--r-- | addons/mail/static/src/js/document_viewer.js | 16 | ||||
| -rw-r--r-- | addons/mail/static/src/js/thread.js | 1 | ||||
| -rw-r--r-- | addons/mail/static/src/less/composer.less | 1 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/thread.xml | 2 | ||||
| -rw-r--r-- | addons/mail/static/tests/chat_window_tests.js | 78 |
10 files changed, 117 insertions, 14 deletions
diff --git a/addons/mail/models/ir_model.py b/addons/mail/models/ir_model.py index 04529610f0e..0b029f3e1a1 100644 --- a/addons/mail/models/ir_model.py +++ b/addons/mail/models/ir_model.py @@ -52,12 +52,6 @@ class IrModel(models.Model): model_class._inherit = parents + ['mail.thread'] return model_class - def unlink(self): - # Delete followers for models that will be unlinked. - query = "DELETE FROM mail_followers WHERE res_model IN %s" - self.env.cr.execute(query, [tuple(self.mapped('model'))]) - return super(IrModel, self).unlink() - class IrModelField(models.Model): _inherit = 'ir.model.fields' diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index 47e0c37408f..209a05999be 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -88,7 +88,7 @@ class MailActivity(models.Model): summary = fields.Char('Summary') note = fields.Html('Note') feedback = fields.Html('Feedback') - date_deadline = fields.Date('Due Date', index=True, required=True, default=fields.Date.today) + date_deadline = fields.Date('Due Date', index=True, required=True, default=fields.Date.context_today) # description user_id = fields.Many2one( 'res.users', 'Assigned to', diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py index f397d19e506..c03c80cbb3b 100644 --- a/addons/mail/models/res_users.py +++ b/addons/mail/models/res_users.py @@ -128,16 +128,19 @@ class Users(models.Model): def activity_user_count(self): query = """SELECT m.id, count(*), act.res_model as model, CASE - WHEN now()::date - act.date_deadline::date = 0 Then 'today' - WHEN now()::date - act.date_deadline::date > 0 Then 'overdue' - WHEN now()::date - act.date_deadline::date < 0 Then 'planned' + WHEN %(today)s::date - act.date_deadline::date = 0 Then 'today' + WHEN %(today)s::date - act.date_deadline::date > 0 Then 'overdue' + WHEN %(today)s::date - act.date_deadline::date < 0 Then 'planned' END AS states FROM mail_activity AS act JOIN ir_model AS m ON act.res_model_id = m.id - WHERE user_id = %s + WHERE user_id = %(user_id)s GROUP BY m.id, states, act.res_model; """ - self.env.cr.execute(query, [self.env.uid]) + self.env.cr.execute(query, { + 'today': fields.Date.context_today(self), + 'user_id': self.env.uid, + }) activity_data = self.env.cr.dictfetchall() model_ids = [a['id'] for a in activity_data] model_names = {n[0]:n[1] for n in self.env['ir.model'].browse(model_ids).name_get()} diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js index 9f09eb390b0..9e080f3a248 100644 --- a/addons/mail/static/src/js/chat_window.js +++ b/addons/mail/static/src/js/chat_window.js @@ -16,7 +16,8 @@ var HEIGHT_FOLDED = '34px'; return Widget.extend({ template: "mail.ChatWindow", custom_events: { - escape_pressed: '_onEscapePressed' + escape_pressed: '_onEscapePressed', + document_viewer_closed: '_onDocumentViewerClose', }, events: { 'click .o_chat_composer': '_onComposerClick', @@ -182,6 +183,9 @@ return Widget.extend({ } this.focus_input(); }, + _onDocumentViewerClose: function (ev) { + this.focus_input(); + }, /** * @private */ diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index 3a7b9c320e1..8354fe610b5 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -565,6 +565,9 @@ var BasicComposer = Widget.extend({ on_click_add_attachment: function () { this.$('input.o_input_file').click(); this.$input.focus(); + // set ignoreEscape to avoid escape_pressed event when file selector dialog is opened + // when user press escape to cancel file selector dialog then escape_pressed event should not be trigerred + this.ignoreEscape = true; }, setState: function (state) { @@ -635,6 +638,8 @@ var BasicComposer = Widget.extend({ if (this.mention_manager.is_open()) { event.stopPropagation(); this.mention_manager.reset_suggestions(); + } else if (this.ignoreEscape) { + this.ignoreEscape = false; } else { this.trigger_up("escape_pressed"); } @@ -871,6 +876,7 @@ var BasicComposer = Widget.extend({ * @param {MouseEvent} event */ _onAttachmentView: function (event) { + event.stopPropagation(); var activeAttachmentID = $(event.currentTarget).data('id'); var attachments = this.get('attachment_ids'); if (activeAttachmentID) { diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js index 0aac950cf5b..d7c43b2d4f6 100644 --- a/addons/mail/static/src/js/document_viewer.js +++ b/addons/mail/static/src/js/document_viewer.js @@ -25,6 +25,7 @@ var DocumentViewer = Widget.extend({ 'DOMMouseScroll .o_viewer_content': '_onScroll', // Firefox 'mousewheel .o_viewer_content': '_onScroll', // Chrome, Safari, IE 'keydown': '_onKeydown', + 'keyup': '_onKeyUp', 'mousedown .o_viewer_img': '_onStartDrag', 'mousemove .o_viewer_content': '_onDrag', 'mouseup .o_viewer_content': '_onEndDrag' @@ -152,6 +153,7 @@ var DocumentViewer = Widget.extend({ _onClose: function (e) { e.preventDefault(); this.$el.modal('hide'); + this.trigger_up('document_viewer_closed'); }, /** * When popup close complete destroyed modal even DOM footprint too @@ -233,6 +235,20 @@ var DocumentViewer = Widget.extend({ } }, /** + * Close popup on ESCAPE keyup + * + * @private + * @param {KeyEvent} e + */ + _onKeyUp: function (e) { + switch (e.which) { + case $.ui.keyCode.ESCAPE: + e.preventDefault(); + this._onClose(e); + break; + } + }, + /** * @private * @param {MouseEvent} e */ diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 97b6bf4906f..f05134891e1 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -371,6 +371,7 @@ var Thread = Widget.extend({ * @param {MouseEvent} event */ _onAttachmentView: function (event) { + event.stopPropagation(); var activeAttachmentID = $(event.currentTarget).data('id'); if (activeAttachmentID) { var attachmentViewer = new DocumentViewer(this, this.attachments, activeAttachmentID); diff --git a/addons/mail/static/src/less/composer.less b/addons/mail/static/src/less/composer.less index 66b754c6d97..976473f6e1e 100644 --- a/addons/mail/static/src/less/composer.less +++ b/addons/mail/static/src/less/composer.less @@ -336,6 +336,7 @@ } .o_modal_fullscreen { + z-index: @o-chat-window-zindex + 1; // To overlap chat window .o_viewer_content { width: 100%; height: 100%; diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml index eef37598164..30d1f85c071 100644 --- a/addons/mail/static/src/xml/thread.xml +++ b/addons/mail/static/src/xml/thread.xml @@ -76,7 +76,7 @@ </t> <t t-name="DocumentViewer"> - <div class="modal o_modal_fullscreen" tabindex="-1" role="dialog" aria-hidden="true"> + <div class="modal o_modal_fullscreen" tabindex="-1" data-keyboard="false" role="dialog" aria-hidden="true"> <t t-call="DocumentViewer.Content"/> <t t-if="widget.attachment.length != 1"> diff --git a/addons/mail/static/tests/chat_window_tests.js b/addons/mail/static/tests/chat_window_tests.js index ab5a9f03538..05bbc418e70 100644 --- a/addons/mail/static/tests/chat_window_tests.js +++ b/addons/mail/static/tests/chat_window_tests.js @@ -61,6 +61,84 @@ QUnit.module('mail', { parent.destroy(); }); + QUnit.test('open document viewer and close using ESCAPE key should reset focus to chat window', function (assert) { + assert.expect(6); + + function createParent(params) { + var widget = new Widget(); + + testUtils.addMockEnvironment(widget, params); + return widget; + } + var messages = [{ + attachment_ids: [{ + filename: 'image1.jpg', + id:1, + mimetype: 'image/jpeg', + name: 'Test Image 1', + url: '/web/content/1?download=true' + }], + author_id: ["1", "John Doe"], + body: "A message", + date: moment("2016-12-20 09:35:40"), + displayed_author: "John Doe", + id: 1, + is_note: false, + is_starred: false, + model: 'partner', + res_id: 2 + }]; + var parent = createParent({ + mockRPC: function (route, args) { + if(_.str.contains(route, '/mail/attachment/preview/') || + _.str.contains(route, '/web/static/lib/pdfjs/web/viewer.html')){ + var canvas = document.createElement('canvas'); + return $.when(canvas.toDataURL()); + } + return this._super.apply(this, arguments); + }, + data: {}, + }); + + var chatWindow = new ChatWindow(parent, 1, "user", false, messages.length, {}); + chatWindow.appendTo($('#qunit-fixture')); + chatWindow.render(messages); + + testUtils.intercept(chatWindow, 'get_messages', function(event) { + event.stopPropagation(); + var requested_msgs = _.filter(messages, function (msg) { + return _.contains(event.data.options.ids, msg.id); + }); + event.data.callback($.when(requested_msgs)); + }, true); + + testUtils.intercept(chatWindow, 'get_bus', function(event) { + event.stopPropagation(); + event.data.callback(new Bus()); + }, true); + + chatWindow.on('document_viewer_closed', null, function () { + assert.ok(true, "chat window should trigger a close document viewer event"); + }); + assert.strictEqual(chatWindow.$('.o_thread_message .o_attachment').length, 1, + "there should be three attachment on message"); + // click on first image attachement + chatWindow.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first().click(); + // check focus is on document viewer popup and then press escape to close it + assert.strictEqual(document.activeElement, $('.o_modal_fullscreen')[0], "Modal popup should have focus"); + assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[src*="/web/image/1?unique=1"]').length, 1, + "Modal popup should open with first image src"); + // trigger ESCAPE keyup on document viewer popup + var upKeyEvent = jQuery.Event("keyup", {which: 27}); + $('.o_modal_fullscreen').trigger(upKeyEvent); + assert.strictEqual(document.activeElement, chatWindow.$input[0], + "input should be focused"); + var upKeyEvent = jQuery.Event( "keyup", {which: 27}); + chatWindow.$('.o_composer_input').trigger(upKeyEvent); + assert.strictEqual(chatWindow.folded, false, "Closed chat Window"); + parent.destroy(); + }); + QUnit.test('chat window\'s input can still be focused when the UI is blocked', function (assert) { assert.expect(2); |
