flectra.define('mail.window_manager', function (require) { "use strict"; var chat_manager = require('mail.chat_manager'); var ExtendedChatWindow = require('mail.ExtendedChatWindow'); var config = require('web.config'); var core = require('web.core'); var utils = require('web.utils'); var web_client = require('web.web_client'); var _t = core._t; var QWeb = core.qweb; // chat window management //---------------------------------------------------------------- var CHAT_WINDOW_WIDTH = 325 + 5; // 5 pixels between windows var chat_sessions = []; var new_chat_session; var display_state = { chat_windows_hidden: false, // chat windows aren't displayed when the client action is open 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 add_chat_session (chat_session) { // adds chat_session such that it will be the left-most visible window compute_available_slots(chat_sessions.length+1); chat_sessions.splice(display_state.nb_slots-1, 0, chat_session); } // options.passively: if set to true, open the chat window without focusing the // input and marking messages as read if it is not open yet, and do nothing // otherwise function open_chat (session, options) { if (!session) { open_chat_without_session(); return; } options = options || {}; var chat_session = _.findWhere(chat_sessions, {id: session.id}); if (!chat_session) { var prefix = !session.is_chat ? "#" : ""; var window_options = { autofocus: !options.passively, input_less: session.mass_mailing, status: session.status, }; chat_session = { id: session.id, uuid: session.uuid, name: session.name, keep_unread: options.passively, // don't automatically mark unread messages as seen window: new ExtendedChatWindow(web_client, session.id, prefix + session.name, session.is_folded, session.unread_counter, window_options), }; chat_session.window.on("close_chat_session", null, function () { close_chat(chat_session); chat_manager.close_chat_session(chat_session.id); }); chat_session.window.on("toggle_star_status", null, function (message_id) { chat_manager.toggle_star_status(message_id); }); chat_session.window.on("fold_channel", null, function (channel_id, folded) { chat_manager.fold_channel(channel_id, folded); }); chat_session.window.on("post_message", null, function (message, channel_id) { chat_manager .post_message(message, {channel_id: channel_id}) .then(function () { chat_session.window.thread.scroll_to(); }); }); chat_session.window.on("redirect", null, function (res_model, res_id) { chat_manager.redirect(res_model, res_id, open_chat); }); chat_session.window.on("redirect_to_channel", null, function (channel_id) { var session = _.findWhere(chat_sessions, {id: channel_id}); if (!session) { chat_manager.join_channel(channel_id).then(function (channel) { chat_manager.detach_channel(channel); }); } else { session.window.toggle_fold(false); } }); var remove_new_chat = false; if (options.passively) { chat_sessions.push(chat_session); // simply insert the window to the left } else if (new_chat_session && new_chat_session.partner_id && new_chat_session.partner_id === session.direct_partner_id) { // the window takes the place of the 'new_chat_session' window chat_sessions[_.indexOf(chat_sessions, new_chat_session)] = chat_session; remove_new_chat = true; } else { add_chat_session(chat_session); // add session such that window is visible } chat_session.window.appendTo($('body')) .then(function () { reposition_windows({remove_new_chat: remove_new_chat}); return chat_manager.get_messages({channel_id: chat_session.id}); }).then(function (messages) { chat_session.window.render(messages); chat_session.window.thread.scroll_to(); setTimeout(function () { chat_session.window.thread.$el.on("scroll", null, _.debounce(function () { if (!chat_session.keep_unread && chat_session.window.thread.is_at_bottom()) { chat_manager.mark_channel_as_seen(session); } }, 100)); }, 0); // setTimeout to prevent to execute handler on first scroll_to, which is asynchronous if (options.passively) { // mark first unread messages as seen when focusing the window, then on scroll to bottom as usual chat_session.window.$('.o_mail_thread, .o_chat_composer').one('click', function () { chat_manager.mark_channel_as_seen(session); }); } else if (!display_state.chat_windows_hidden && !session.is_folded) { chat_manager.mark_channel_as_seen(session); } }); } else if (!options.passively) { if (chat_session.window.is_hidden) { make_session_visible(chat_session); } else if (session.is_folded !== chat_session.window.folded) { chat_session.window.toggle_fold(session.is_folded); } } } function open_chat_without_session () { if (!new_chat_session) { new_chat_session = { id: '_open', window: new ExtendedChatWindow(web_client, undefined, _t('New message'), false, 0, {thread_less: true}), }; new_chat_session.window.on("close_chat_session", null, close_new_chat); new_chat_session.window.on('open_dm_session', null, function (partner_id) { new_chat_session.partner_id = partner_id; var dm = chat_manager.get_dm_from_partner_id(partner_id); if (!dm) { chat_manager.open_and_detach_dm(partner_id); } else { var dm_session = _.findWhere(chat_sessions, {id: dm.id}); if (!dm_session) { chat_manager.detach_channel(dm); } else { close_chat(dm_session); dm.is_folded = false; open_chat(dm); } } }); add_chat_session(new_chat_session); new_chat_session.window.appendTo($('body')).then(reposition_windows); } else { if (new_chat_session.window.is_hidden) { make_session_visible(new_chat_session); } else if (new_chat_session.window.folded) { new_chat_session.window.toggle_fold(false); } } } function close_chat (chat_session, options) { if (options && options.keep_open_if_unread && chat_session.keep_unread) { return; } chat_sessions = _.without(chat_sessions, chat_session); chat_session.window.destroy(); reposition_windows(); } function close_new_chat () { chat_sessions = _.without(chat_sessions, new_chat_session); reposition_windows({remove_new_chat: true}); } function destroy_new_chat () { new_chat_session.window.destroy(); new_chat_session = undefined; } function toggle_fold_chat (channel) { var session = _.find(chat_sessions, {id: channel.id}); if (session) { session.window.toggle_fold(channel.is_folded); } } function compute_available_slots (nb_windows) { if (config.device.size_class === config.device.SIZES.XS) { display_state.nb_slots = 1; // one chat window full screen in mobile return; } 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 = function (options) { if (options && options.remove_new_chat) { destroy_new_chat(); } if (display_state.chat_windows_hidden) { return; } 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) { 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 } }); } }; function make_session_visible (session) { utils.swap(chat_sessions, session, chat_sessions[display_state.nb_slots-1]); reposition_windows(); session.window.toggle_fold(false); } 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, widget: {isMobile: config.device.isMobile}, })); 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)) { var message_visible = !display_state.chat_windows_hidden && !session.window.folded && !session.window.is_hidden && session.window.thread.is_at_bottom(); if (message_visible && !session.keep_unread) { chat_manager.mark_channel_as_seen(chat_manager.get_channel(session.id)); } chat_manager.get_messages({channel_id: session.id}).then(function (messages) { session.window.render(messages); if (scrollBottom && message_visible) { session.window.thread.scroll_to(); } }); } }); } core.bus.on('web_client_ready', null, function () { chat_manager.bus.on('open_chat', null, open_chat); chat_manager.bus.on('close_chat', null, function (channel, options) { var session = _.find(chat_sessions, {id: channel.id}); if (session) { close_chat(session, options); } }); chat_manager.bus.on('channel_toggle_fold', null, toggle_fold_chat); chat_manager.bus.on('new_message', null, function (message) { update_sessions(message, true); }); chat_manager.bus.on('update_message', null, function (message) { update_sessions(message, false); }); chat_manager.bus.on('anyone_listening', null, function (channel, query) { _.each(chat_sessions, function (session) { if (channel.id === session.id && session.window.thread.is_at_bottom() && !session.window.is_hidden) { query.is_displayed = true; } }); }); chat_manager.bus.on('unsubscribe_from_channel', null, function (channel_id) { _.each(chat_sessions, function (session) { if (channel_id === session.id) { close_chat(session); } }); }); 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 (channel.unread_counter === 0) { session.keep_unread = false; } } 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.bus.on('update_dm_presence', null, function (channel) { _.each(chat_sessions, function (session) { if (channel.id === session.id) { session.window.update_status(channel.status); } }); }); chat_manager.is_ready.then(function() { _.each(chat_manager.get_channels(), function (channel) { if (channel.is_detached) { open_chat(channel); } }); }); chat_manager.bus.on('detach_channel', null, function (channel) { var chat_session = _.findWhere(chat_sessions, {id: channel.id}); if (!chat_session || chat_session.window.folded) { chat_manager.detach_channel(channel); } else if (chat_session.window.is_hidden) { make_session_visible(chat_session); } else { chat_session.window.focus_input(); } }); chat_manager.bus.on('client_action_open', null, function (open) { display_state.chat_windows_hidden = open; if (open) { $('body').addClass('o_no_chat_window'); } else { $('body').removeClass('o_no_chat_window'); reposition_windows(); } }); core.bus.on('resize', null, _.debounce(reposition_windows, 100)); }); });