summaryrefslogtreecommitdiff
path: root/addons/mail
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-05-04 16:10:50 +0200
committerChristophe Simonis <chs@odoo.com>2018-05-04 16:10:50 +0200
commitac63dfc8f48fa6451b4ef94e24e784f252b84f8e (patch)
tree768b741e1a34a94b95977d8ff869143aab73617e /addons/mail
parent62705aee69460457c1b9257ac30363754c60c973 (diff)
parent8dade01e2c5b560864291fb3c437ccf5999aee12 (diff)
[MERGE] forward port branch 11.0 up to 8dade01e2c5
Diffstat (limited to 'addons/mail')
-rw-r--r--addons/mail/models/ir_model.py6
-rw-r--r--addons/mail/models/mail_activity.py2
-rw-r--r--addons/mail/models/res_users.py13
-rw-r--r--addons/mail/static/src/js/chat_window.js6
-rw-r--r--addons/mail/static/src/js/composer.js6
-rw-r--r--addons/mail/static/src/js/document_viewer.js16
-rw-r--r--addons/mail/static/src/js/thread.js1
-rw-r--r--addons/mail/static/src/less/composer.less1
-rw-r--r--addons/mail/static/src/xml/thread.xml2
-rw-r--r--addons/mail/static/tests/chat_window_tests.js78
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);