summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2015-12-30 11:15:04 +0100
committerAaron Bohy <aab@odoo.com>2016-01-14 11:22:25 +0100
commit18fccd9d6c612e0a2ff9ddfa37f877cfa51e5c0d (patch)
tree57003be9e947fe38eb28548cc1b0ff2407c0f231
parent37238d343ad2c58a1d7f8f65c89df31939853949 (diff)
[IMP] mail: put chat windows in a dropdown in case of overflow
Former algorithm to display chat windows was pretty basic: each window was positionned 5 pixels to the left of the previous one, starting from the bottom right corner of the screen. Thus, when there were too many chat windows to fit in the screen, they overflowed to the left. This rev. handles this case by hidding overflowing chat windows and making them available in a dropdown positionned 5 pixels to the left of the last visible chat window.
-rw-r--r--addons/mail/static/src/js/chat_window.js23
-rw-r--r--addons/mail/static/src/js/window_manager.js113
-rw-r--r--addons/mail/static/src/less/chat_window.less44
-rw-r--r--addons/mail/static/src/xml/chat_window.xml44
4 files changed, 202 insertions, 22 deletions
diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js
index ca36b430791..e76e2405b43 100644
--- a/addons/mail/static/src/js/chat_window.js
+++ b/addons/mail/static/src/js/chat_window.js
@@ -29,6 +29,7 @@ return Widget.extend({
display_stars: true,
});
this.unread_msgs = unread_msgs || 0;
+ this.is_hidden = false;
},
start: function () {
this.$content = this.$('.o_chat_content');
@@ -50,23 +51,17 @@ return Widget.extend({
return $.when(this._super(), def);
},
render: function (messages) {
- this.update_header();
+ this.update_unread(this.unread_msgs);
this.thread.render(messages, {display_load_more: false});
},
- update_header: function () {
- var title = this.unread_msgs > 0 ?
- this.title + ' (' + this.unread_msgs + ')' : this.title;
- this.$('.o_chat_title').text(title);
- },
update_unread: function (counter) {
this.unread_msgs = counter;
- this.update_header();
+ this.$('.o_unread_counter').text(counter > 0 ? '(' + counter + ')' : '');
},
scrollBottom: function () {
this.$content.scrollTop(this.$content[0].scrollHeight);
},
fold: function () {
- this.update_header();
this.$el.animate({
height: this.folded ? HEIGHT_FOLDED : HEIGHT_OPEN
});
@@ -79,6 +74,18 @@ return Widget.extend({
}
this.fold();
},
+ do_show: function () {
+ this.is_hidden = false;
+ this._super.apply(this, arguments);
+ },
+ do_hide: function () {
+ this.is_hidden = true;
+ this._super.apply(this, arguments);
+ },
+ do_toggle: function (display) {
+ this.is_hidden = _.isBoolean(display) ? !display : !this.is_hidden;
+ this._super.apply(this, arguments);
+ },
on_keydown: function (event) {
// ENTER key (avoid requiring jquery ui for external livechat)
if (event.which === 13) {
diff --git a/addons/mail/static/src/js/window_manager.js b/addons/mail/static/src/js/window_manager.js
index f217d929c20..7c26dc88c82 100644
--- a/addons/mail/static/src/js/window_manager.js
+++ b/addons/mail/static/src/js/window_manager.js
@@ -5,16 +5,26 @@ var chat_manager = require('mail.chat_manager');
var ChatWindow = require('mail.ChatWindow');
var core = require('web.core');
+var utils = require('web.utils');
var web_client = require('web.web_client');
+var QWeb = core.qweb;
// chat window management
//----------------------------------------------------------------
+var CHAT_WINDOW_WIDTH = 300 + 5; // 5 pixels between windows
var chat_sessions = [];
-var CHAT_WINDOW_WIDTH = 300;
+var display_state = {
+ hidden_sessions: [],
+ hidden_unread_counter: 0, // total number of unread msgs in hidden chat windows
+ nb_slots: 0,
+ space_left: 0,
+ windows_dropdown_is_open: false, // used to keep dropdown open when closing chat windows
+};
function open_chat (session) {
- if (!_.findWhere(chat_sessions, {id: session.id})) {
+ var chat_session = _.findWhere(chat_sessions, {id: session.id});
+ if (!chat_session) {
var channel = chat_manager.get_channel(session.id);
var chat_session = {
id: session.id,
@@ -58,7 +68,10 @@ function open_chat (session) {
}
});
- chat_sessions.push(chat_session);
+ // insert chat_session such that it will be the right-most visible window
+ compute_available_slots(chat_sessions.length+1);
+ chat_sessions.splice(display_state.nb_slots-1, 0, chat_session);
+
chat_session.window.appendTo($('body'))
.then(reposition_windows)
.then(function () {
@@ -67,6 +80,8 @@ function open_chat (session) {
chat_session.window.render(messages);
chat_session.window.scrollBottom();
});
+ } else if (chat_session.window.is_hidden) {
+ make_session_visible(chat_session);
}
}
@@ -86,16 +101,92 @@ function toggle_fold_chat (channel) {
}
}
-function reposition_windows () {
+function compute_available_slots (nb_windows) {
+ var width = window.innerWidth;
+ var nb_slots = Math.floor(width/CHAT_WINDOW_WIDTH);
+ var space_left = width - (Math.min(nb_slots, nb_windows)*CHAT_WINDOW_WIDTH);
+ if (nb_slots < nb_windows && space_left < 50) {
+ nb_slots--; // leave at least 50px for the hidden windows dropdown button
+ space_left += CHAT_WINDOW_WIDTH;
+ }
+ display_state.nb_slots = nb_slots;
+ display_state.space_left = space_left;
+}
+
+var reposition_windows = _.debounce(function () {
+ compute_available_slots(chat_sessions.length);
+ var hidden_sessions = [];
+ var hidden_unread_counter = 0;
+ var nb_slots = display_state.nb_slots;
_.each(chat_sessions, function (session, index) {
- session.window.$el.css({right: (CHAT_WINDOW_WIDTH + 5) * index, bottom: 0});
+ if (index < nb_slots) {
+ session.window.$el.css({right: CHAT_WINDOW_WIDTH*index, bottom: 0});
+ session.window.do_show();
+ } else {
+ hidden_sessions.push(session);
+ hidden_unread_counter += session.window.unread_msgs;
+ session.window.do_hide();
+ }
});
+ display_state.hidden_sessions = hidden_sessions;
+ display_state.hidden_unread_counter = hidden_unread_counter;
+
+ if (display_state.$hidden_windows_dropdown) {
+ display_state.$hidden_windows_dropdown.remove();
+ }
+ if (hidden_sessions.length) {
+ display_state.$hidden_windows_dropdown = render_hidden_sessions_dropdown();
+ var $hidden_windows_dropdown = display_state.$hidden_windows_dropdown;
+ $hidden_windows_dropdown.css({right: CHAT_WINDOW_WIDTH * nb_slots, bottom: 0})
+ .appendTo($('body'));
+ reposition_hidden_sessions_dropdown();
+ display_state.windows_dropdown_is_open = false;
+
+ $hidden_windows_dropdown.on('click', '.o_chat_header', function (event) {
+ var session_id = $(event.currentTarget).data('session-id');
+ var session = _.findWhere(hidden_sessions, {id: session_id});
+ if (session) {
+ make_session_visible(session);
+ }
+ });
+ $hidden_windows_dropdown.on('click', '.o_chat_window_close', function (event) {
+ var session_id = $(event.currentTarget).closest('.o_chat_header').data('session-id');
+ var session = _.findWhere(hidden_sessions, {id: session_id});
+ if (session) {
+ session.window.on_click_close(event);
+ display_state.windows_dropdown_is_open = true; // keep the dropdown open
+ }
+ });
+ }
+}, 100);
+
+function make_session_visible (session) {
+ utils.swap(chat_sessions, session, chat_sessions[display_state.nb_slots-1]);
+ session.window.toggle_fold(false);
+ reposition_windows();
+}
+
+function render_hidden_sessions_dropdown () {
+ var $dropdown = $(QWeb.render("mail.ChatWindowsDropdown", {
+ sessions: display_state.hidden_sessions,
+ open: display_state.windows_dropdown_is_open,
+ unread_counter: display_state.hidden_unread_counter,
+ }));
+ return $dropdown;
+}
+
+function reposition_hidden_sessions_dropdown () {
+ // Unfold dropdown to the left if there is enough place
+ var $dropdown_ul = display_state.$hidden_windows_dropdown.children('ul');
+ if (display_state.space_left > $dropdown_ul.width() + 10) {
+ $dropdown_ul.addClass('dropdown-menu-right');
+ }
}
function update_sessions (message, scrollBottom) {
_.each(chat_sessions, function (session) {
if (_.contains(message.channel_ids, session.id)) {
- if (!session.window.folded) {
+ if (!session.window.folded && !session.window.is_hidden) {
chat_manager.mark_channel_as_seen(chat_manager.get_channel(session.id));
}
chat_manager.get_messages({channel_id: session.id}).then(function (messages) {
@@ -139,11 +230,19 @@ core.bus.on('web_client_ready', null, function () {
});
chat_manager.bus.on('update_channel_unread_counter', null, function (channel) {
+ display_state.hidden_unread_counter = 0;
_.each(chat_sessions, function (session) {
if (channel.id === session.id) {
session.window.update_unread(channel.unread_counter);
}
+ if (session.window.is_hidden) {
+ display_state.hidden_unread_counter += session.window.unread_msgs;
+ }
});
+ if (display_state.$hidden_windows_dropdown) {
+ display_state.$hidden_windows_dropdown.html(render_hidden_sessions_dropdown().html());
+ reposition_hidden_sessions_dropdown();
+ }
});
chat_manager.is_ready.then(function() {
@@ -153,6 +252,8 @@ core.bus.on('web_client_ready', null, function () {
}
});
});
+
+ core.bus.on('resize', null, reposition_windows);
});
});
diff --git a/addons/mail/static/src/less/chat_window.less b/addons/mail/static/src/less/chat_window.less
index ca2e8ca74f1..bd9a2452113 100644
--- a/addons/mail/static/src/less/chat_window.less
+++ b/addons/mail/static/src/less/chat_window.less
@@ -1,10 +1,11 @@
@o-chat-window-bg: white;
+@o-chat-window-width: 300px;
.o_chat_window {
.o-flex-display();
.o-flex-flow(column, nowrap);
position: fixed;
- width: 300px;
+ width: @o-chat-window-width;
max-width: 100%;
height: 400px;
max-height: 100%;
@@ -28,11 +29,13 @@
.o_chat_title {
cursor: pointer;
.o-flex(1, 1, auto);
+ .o-text-overflow();
}
.o_chat_window_close {
color: white;
padding: 3px;
+ margin-left: 5px;
&:hover {
background-color: darken(@odoo-brand-primary, 10%);
}
@@ -67,3 +70,42 @@
}
}
}
+
+.o_chat_window_dropdown {
+ width: auto;
+ height: 28px;
+ color: white;
+ background-color: @odoo-brand-primary;
+ cursor: pointer;
+
+ .o_chat_window_dropdown_toggler {
+ padding: 5px;
+
+ .o_total_unread_counter {
+ .o-position-absolute(-10px, 0, auto, auto);
+ background-color: @odoo-brand-optional;
+ padding: 0 2px;
+ font-size: smaller;
+ }
+ }
+ &.open .o_chat_window_dropdown_toggler .o_total_unread_counter {
+ display: none;
+ }
+
+ > ul {
+ max-width: @o-chat-window-width;
+ padding: 0;
+
+ > li.o_chat_header {
+ font-size: 12px;
+ padding: 3px 5px;
+ &~li.o_chat_header {
+ border-top: 1px solid white;
+ }
+ &:hover {
+ background-color: darken(@odoo-brand-primary, 10%);
+ color: white;
+ }
+ }
+ }
+}
diff --git a/addons/mail/static/src/xml/chat_window.xml b/addons/mail/static/src/xml/chat_window.xml
index 01e475a6eb8..58d04c19838 100644
--- a/addons/mail/static/src/xml/chat_window.xml
+++ b/addons/mail/static/src/xml/chat_window.xml
@@ -1,16 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
-
<t t-name="mail.ChatWindow">
<div class="o_chat_window">
<div class="o_chat_header">
- <span class="o_chat_title">
- <t t-esc="widget.title"/>
- </span>
- <span>
- <a href="#" class="o_chat_window_close fa fa-close"></a>
- </span>
+ <t t-call="mail.ChatWindowHeaderContent">
+ <t t-set="title" t-value="widget.title"/>
+ <t t-set="unread_counter" t-value="widget.unread_msgs"/>
+ </t>
</div>
<div class="o_chat_content">
</div>
@@ -20,4 +17,37 @@
</div>
</t>
+ <t t-name="mail.ChatWindowsDropdown">
+ <div t-attf-class="o_chat_window o_chat_window_dropdown dropup #{open ? 'open' : ''}">
+ <span class="o_chat_window_dropdown_toggler dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-comments-o"/> <t t-esc="sessions.length"/>
+ <span class="o_total_unread_counter">
+ <t t-if="unread_counter"><t t-esc="unread_counter"/></t>
+ </span>
+ </span>
+ <ul class="dropdown-menu">
+ <t t-foreach="sessions" t-as="session">
+ <li class="o_chat_header" t-att-data-session-id="session.id">
+ <t t-call="mail.ChatWindowHeaderContent">
+ <t t-set="title" t-value="session.name"/>
+ <t t-set="unread_counter" t-value="session.window.unread_msgs"/>
+ </t>
+ </li>
+ </t>
+ </ul>
+ </div>
+ </t>
+
+ <t t-name="mail.ChatWindowHeaderContent">
+ <span class="o_chat_title">
+ <t t-esc="title"/>
+ <span class="o_unread_counter">
+ <t t-if="unread_counter">(<t t-esc="unread_counter"/>)</t>
+ </span>
+ </span>
+ <span>
+ <a href="#" class="o_chat_window_close fa fa-close"/>
+ </span>
+ </t>
+
</templates>