2019-07-11 10:48:52 +02:00
|
|
|
/**
|
|
|
|
* @module converse-minimize
|
2020-01-26 16:21:20 +01:00
|
|
|
* @copyright 2020, the Converse.js contributors
|
|
|
|
* @license Mozilla Public License (MPLv2)
|
2019-07-11 10:48:52 +02:00
|
|
|
*/
|
2018-10-23 03:41:38 +02:00
|
|
|
import "converse-chatview";
|
2019-09-19 16:54:55 +02:00
|
|
|
import { Model } from 'skeletor.js/src/model.js';
|
|
|
|
import { Overview } from "skeletor.js/src/overview";
|
|
|
|
import { View } from "skeletor.js/src/view";
|
2020-02-07 14:58:26 +01:00
|
|
|
import { __ } from '@converse/headless/i18n';
|
2020-03-24 12:26:34 +01:00
|
|
|
import { debounce, sum } from 'lodash';
|
2020-04-23 13:22:31 +02:00
|
|
|
import { converse } from "@converse/headless/converse-core";
|
2018-10-23 03:41:38 +02:00
|
|
|
import tpl_chats_panel from "templates/chats_panel.html";
|
|
|
|
import tpl_toggle_chats from "templates/toggle_chats.html";
|
|
|
|
import tpl_trimmed_chat from "templates/trimmed_chat.html";
|
|
|
|
|
2020-03-24 12:26:34 +01:00
|
|
|
const { dayjs } = converse.env;
|
2018-10-23 03:41:38 +02:00
|
|
|
const u = converse.env.utils;
|
|
|
|
|
2019-11-06 11:01:34 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
converse.plugins.add('converse-minimize', {
|
|
|
|
/* Optional dependencies are other plugins which might be
|
|
|
|
* overridden or relied upon, and therefore need to be loaded before
|
|
|
|
* this plugin. They are called "optional" because they might not be
|
|
|
|
* available, in which case any overrides applicable to them will be
|
|
|
|
* ignored.
|
|
|
|
*
|
|
|
|
* It's possible however to make optional dependencies non-optional.
|
|
|
|
* If the setting "strict_plugin_dependencies" is set to true,
|
|
|
|
* an error will be raised if the plugin is not found.
|
|
|
|
*
|
|
|
|
* NB: These plugins need to have already been loaded via require.js.
|
|
|
|
*/
|
2019-11-22 14:38:09 +01:00
|
|
|
dependencies: [
|
|
|
|
"converse-chatview",
|
|
|
|
"converse-controlbox",
|
|
|
|
"converse-muc-views",
|
|
|
|
"converse-headlines-view",
|
|
|
|
"converse-dragresize"
|
|
|
|
],
|
2018-10-23 03:41:38 +02:00
|
|
|
|
|
|
|
enabled (_converse) {
|
2020-03-30 16:29:09 +02:00
|
|
|
return _converse.api.settings.get("view_mode") === 'overlayed';
|
2018-10-23 03:41:38 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
overrides: {
|
|
|
|
// Overrides mentioned here will be picked up by converse.js's
|
|
|
|
// plugin architecture they will replace existing methods on the
|
|
|
|
// relevant objects or classes.
|
|
|
|
//
|
|
|
|
// New functions which don't exist yet can also be added.
|
|
|
|
|
|
|
|
ChatBox: {
|
|
|
|
initialize () {
|
|
|
|
this.__super__.initialize.apply(this, arguments);
|
|
|
|
this.on('show', this.maximize, this);
|
|
|
|
|
|
|
|
if (this.get('id') === 'controlbox') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.save({
|
|
|
|
'minimized': this.get('minimized') || false,
|
2019-05-06 11:16:56 +02:00
|
|
|
'time_minimized': this.get('time_minimized') || dayjs(),
|
2018-10-23 03:41:38 +02:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2019-04-16 16:36:58 +02:00
|
|
|
maybeShow (force) {
|
|
|
|
if (!force && this.get('minimized')) {
|
|
|
|
// Must return the chatbox
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return this.__super__.maybeShow.apply(this, arguments);
|
2019-04-16 13:38:46 +02:00
|
|
|
}
|
2017-11-02 15:30:24 +01:00
|
|
|
},
|
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
ChatBoxView: {
|
2019-07-12 00:46:17 +02:00
|
|
|
show () {
|
2018-10-23 03:41:38 +02:00
|
|
|
const { _converse } = this.__super__;
|
2020-03-30 16:29:09 +02:00
|
|
|
if (_converse.api.settings.get("view_mode") === 'overlayed' && this.model.get('minimized')) {
|
2019-06-26 16:32:23 +02:00
|
|
|
this.model.minimize();
|
2019-07-12 00:46:17 +02:00
|
|
|
return this;
|
|
|
|
} else {
|
|
|
|
return this.__super__.show.apply(this, arguments);
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
|
|
|
},
|
2016-03-28 16:52:00 +02:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
isNewMessageHidden () {
|
|
|
|
return this.model.get('minimized') ||
|
|
|
|
this.__super__.isNewMessageHidden.apply(this, arguments);
|
|
|
|
},
|
2017-05-03 09:06:28 +02:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
shouldShowOnTextMessage () {
|
|
|
|
return !this.model.get('minimized') &&
|
|
|
|
this.__super__.shouldShowOnTextMessage.apply(this, arguments);
|
|
|
|
},
|
2018-03-13 19:11:49 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
setChatBoxHeight (height) {
|
|
|
|
if (!this.model.get('minimized')) {
|
2019-10-09 16:01:38 +02:00
|
|
|
return this.__super__.setChatBoxHeight.call(this, height);
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
|
|
|
},
|
2016-03-28 16:08:50 +02:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
setChatBoxWidth (width) {
|
|
|
|
if (!this.model.get('minimized')) {
|
2019-10-09 16:01:38 +02:00
|
|
|
return this.__super__.setChatBoxWidth.call(this, width);
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
2020-02-10 11:23:55 +01:00
|
|
|
},
|
2019-05-24 13:52:15 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
initialize () {
|
|
|
|
/* The initialize function gets called as soon as the plugin is
|
|
|
|
* loaded by Converse.js's plugin machinery.
|
|
|
|
*/
|
2019-05-29 13:00:45 +02:00
|
|
|
const { _converse } = this;
|
2020-03-31 13:15:57 +02:00
|
|
|
const { api } = _converse;
|
2016-03-31 10:40:25 +02:00
|
|
|
|
2020-03-31 13:15:57 +02:00
|
|
|
api.settings.update({'no_trimming': false});
|
2019-05-24 13:52:15 +02:00
|
|
|
|
|
|
|
const minimizableChatBox = {
|
|
|
|
maximize () {
|
|
|
|
u.safeSave(this, {
|
|
|
|
'minimized': false,
|
|
|
|
'time_opened': (new Date()).getTime()
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
minimize () {
|
|
|
|
u.safeSave(this, {
|
|
|
|
'minimized': true,
|
|
|
|
'time_minimized': (new Date()).toISOString()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Object.assign(_converse.ChatBox.prototype, minimizableChatBox);
|
|
|
|
|
|
|
|
|
|
|
|
const minimizableChatBoxView = {
|
2019-06-11 12:16:27 +02:00
|
|
|
/**
|
2019-06-26 16:32:23 +02:00
|
|
|
* Handler which gets called when a {@link _converse#ChatBox} has it's
|
|
|
|
* `minimized` property set to false.
|
|
|
|
*
|
2019-06-11 12:16:27 +02:00
|
|
|
* Will trigger {@link _converse#chatBoxMaximized}
|
2019-06-26 16:32:23 +02:00
|
|
|
* @private
|
2019-06-11 12:16:27 +02:00
|
|
|
* @returns {_converse.ChatBoxView|_converse.ChatRoomView}
|
|
|
|
*/
|
2019-06-26 16:32:23 +02:00
|
|
|
onMaximized () {
|
2019-05-24 13:52:15 +02:00
|
|
|
const { _converse } = this.__super__;
|
|
|
|
this.insertIntoDOM();
|
|
|
|
|
|
|
|
if (!this.model.isScrolledUp()) {
|
|
|
|
this.model.clearUnreadMsgCounter();
|
|
|
|
}
|
2019-08-02 11:15:17 +02:00
|
|
|
this.model.setChatState(_converse.ACTIVE);
|
2019-05-24 13:52:15 +02:00
|
|
|
this.show();
|
|
|
|
/**
|
|
|
|
* Triggered when a previously minimized chat gets maximized
|
|
|
|
* @event _converse#chatBoxMaximized
|
|
|
|
* @type { _converse.ChatBoxView }
|
|
|
|
* @example _converse.api.listen.on('chatBoxMaximized', view => { ... });
|
|
|
|
*/
|
2020-03-31 13:15:57 +02:00
|
|
|
api.trigger('chatBoxMaximized', this);
|
2019-05-24 13:52:15 +02:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2019-06-11 12:16:27 +02:00
|
|
|
/**
|
2019-06-26 16:32:23 +02:00
|
|
|
* Handler which gets called when a {@link _converse#ChatBox} has it's
|
|
|
|
* `minimized` property set to true.
|
|
|
|
*
|
2019-06-11 12:16:27 +02:00
|
|
|
* Will trigger {@link _converse#chatBoxMinimized}
|
2019-06-26 16:32:23 +02:00
|
|
|
* @private
|
2019-06-11 12:16:27 +02:00
|
|
|
* @returns {_converse.ChatBoxView|_converse.ChatRoomView}
|
|
|
|
*/
|
2019-06-26 16:32:23 +02:00
|
|
|
onMinimized (ev) {
|
2019-05-24 13:52:15 +02:00
|
|
|
const { _converse } = this.__super__;
|
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
|
|
|
// save the scroll position to restore it on maximize
|
|
|
|
if (this.model.collection && this.model.collection.browserStorage) {
|
|
|
|
this.model.save({'scroll': this.content.scrollTop});
|
|
|
|
} else {
|
|
|
|
this.model.set({'scroll': this.content.scrollTop});
|
|
|
|
}
|
2019-07-10 09:47:13 +02:00
|
|
|
this.model.setChatState(_converse.INACTIVE);
|
2019-05-24 13:52:15 +02:00
|
|
|
this.hide();
|
|
|
|
/**
|
|
|
|
* Triggered when a previously maximized chat gets Minimized
|
|
|
|
* @event _converse#chatBoxMinimized
|
|
|
|
* @type { _converse.ChatBoxView }
|
|
|
|
* @example _converse.api.listen.on('chatBoxMinimized', view => { ... });
|
|
|
|
*/
|
2020-03-31 13:15:57 +02:00
|
|
|
api.trigger('chatBoxMinimized', this);
|
2019-06-11 12:16:27 +02:00
|
|
|
return this;
|
2019-05-24 13:52:15 +02:00
|
|
|
},
|
|
|
|
|
2019-06-26 16:32:23 +02:00
|
|
|
/**
|
|
|
|
* Minimizes a chat box.
|
|
|
|
* @returns {_converse.ChatBoxView|_converse.ChatRoomView}
|
|
|
|
*/
|
2020-02-27 11:16:45 +01:00
|
|
|
minimize (ev) {
|
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
2019-06-26 16:32:23 +02:00
|
|
|
this.model.minimize();
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2019-05-24 13:52:15 +02:00
|
|
|
onMinimizedChanged (item) {
|
|
|
|
if (item.get('minimized')) {
|
2019-06-26 16:32:23 +02:00
|
|
|
this.onMinimized();
|
2019-05-24 13:52:15 +02:00
|
|
|
} else {
|
2019-06-26 16:32:23 +02:00
|
|
|
this.onMaximized();
|
2019-05-24 13:52:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Object.assign(_converse.ChatBoxView.prototype, minimizableChatBoxView);
|
|
|
|
|
|
|
|
|
|
|
|
const chatTrimmer = {
|
2018-10-23 03:41:38 +02:00
|
|
|
getChatBoxWidth (view) {
|
2019-05-24 13:52:15 +02:00
|
|
|
if (view.model.get('id') === 'controlbox') {
|
|
|
|
const controlbox = this.get('controlbox');
|
|
|
|
// We return the width of the controlbox or its toggle,
|
|
|
|
// depending on which is visible.
|
|
|
|
if (!controlbox || !u.isVisible(controlbox.el)) {
|
|
|
|
return u.getOuterWidth(_converse.controlboxtoggle.el, true);
|
|
|
|
} else {
|
|
|
|
return u.getOuterWidth(controlbox.el, true);
|
|
|
|
}
|
|
|
|
} else if (!view.model.get('minimized') && u.isVisible(view.el)) {
|
2018-10-23 03:41:38 +02:00
|
|
|
return u.getOuterWidth(view.el, true);
|
2016-03-31 10:40:25 +02:00
|
|
|
}
|
2018-10-23 03:41:38 +02:00
|
|
|
return 0;
|
2016-03-28 16:08:50 +02:00
|
|
|
},
|
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
getShownChats () {
|
|
|
|
return this.filter((view) =>
|
|
|
|
// The controlbox can take a while to close,
|
|
|
|
// so we need to check its state. That's why we checked
|
|
|
|
// the 'closed' state.
|
|
|
|
!view.model.get('minimized') &&
|
|
|
|
!view.model.get('closed') &&
|
|
|
|
u.isVisible(view.el)
|
|
|
|
);
|
2016-03-14 17:04:27 +01:00
|
|
|
},
|
|
|
|
|
2019-07-12 12:41:21 +02:00
|
|
|
getMinimizedWidth () {
|
2020-03-24 12:26:34 +01:00
|
|
|
const minimized_el = _converse.minimized_chats?.el;
|
2020-03-06 15:19:48 +01:00
|
|
|
return this.model.pluck('minimized').includes(true) ? u.getOuterWidth(minimized_el, true) : 0;
|
2019-07-12 12:41:21 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
getBoxesWidth (newchat) {
|
|
|
|
const new_id = newchat ? newchat.model.get('id') : null;
|
|
|
|
const newchat_width = newchat ? u.getOuterWidth(newchat.el, true) : 0;
|
|
|
|
return Object.values(this.xget(new_id))
|
|
|
|
.reduce((memo, view) => memo + this.getChatBoxWidth(view), newchat_width);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is called when a newly created chat box will be shown.
|
|
|
|
* It checks whether there is enough space on the page to show
|
|
|
|
* another chat box. Otherwise it minimizes the oldest chat box
|
|
|
|
* to create space.
|
|
|
|
* @private
|
|
|
|
* @method _converse.ChatBoxViews#trimChats
|
2019-07-25 06:46:05 +02:00
|
|
|
* @param { _converse.ChatBoxView|_converse.ChatRoomView|_converse.ControlBoxView|_converse.HeadlinesBoxView } [newchat]
|
2019-07-12 12:41:21 +02:00
|
|
|
*/
|
|
|
|
async trimChats (newchat) {
|
2020-03-31 13:15:57 +02:00
|
|
|
if (api.settings.get('no_trimming') || !api.connection.connected() || api.settings.get("view_mode") !== 'overlayed') {
|
2019-05-24 15:49:25 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const shown_chats = this.getShownChats();
|
2019-07-12 12:41:21 +02:00
|
|
|
if (shown_chats.length <= 1) {
|
2018-10-23 03:41:38 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-07-12 12:41:21 +02:00
|
|
|
const body_width = u.getOuterWidth(document.querySelector('body'), true);
|
2018-10-23 03:41:38 +02:00
|
|
|
if (this.getChatBoxWidth(shown_chats[0]) === body_width) {
|
|
|
|
// If the chats shown are the same width as the body,
|
|
|
|
// then we're in responsive mode and the chats are
|
|
|
|
// fullscreen. In this case we don't trim.
|
|
|
|
return;
|
|
|
|
}
|
2020-03-31 13:15:57 +02:00
|
|
|
await api.waitUntil('minimizedChatsInitialized');
|
2020-03-24 12:26:34 +01:00
|
|
|
const minimized_el = _converse.minimized_chats?.el;
|
2018-10-24 18:28:28 +02:00
|
|
|
if (minimized_el) {
|
2019-07-12 12:41:21 +02:00
|
|
|
while ((this.getMinimizedWidth() + this.getBoxesWidth(newchat)) > body_width) {
|
|
|
|
const new_id = newchat ? newchat.model.get('id') : null;
|
2018-10-24 18:28:28 +02:00
|
|
|
const oldest_chat = this.getOldestMaximizedChat([new_id]);
|
|
|
|
if (oldest_chat) {
|
|
|
|
// We hide the chat immediately, because waiting
|
|
|
|
// for the event to fire (and letting the
|
|
|
|
// ChatBoxView hide it then) causes race
|
|
|
|
// conditions.
|
|
|
|
const view = this.get(oldest_chat.get('id'));
|
|
|
|
if (view) {
|
|
|
|
view.hide();
|
2016-03-28 16:52:00 +02:00
|
|
|
}
|
2018-10-24 18:28:28 +02:00
|
|
|
oldest_chat.minimize();
|
2019-07-12 12:41:21 +02:00
|
|
|
} else {
|
|
|
|
break;
|
2016-03-14 17:04:27 +01:00
|
|
|
}
|
|
|
|
}
|
2018-10-24 18:28:28 +02:00
|
|
|
}
|
2019-07-12 12:41:21 +02:00
|
|
|
},
|
2018-10-23 03:41:38 +02:00
|
|
|
|
|
|
|
getOldestMaximizedChat (exclude_ids) {
|
|
|
|
// Get oldest view (if its id is not excluded)
|
|
|
|
exclude_ids.push('controlbox');
|
|
|
|
let i = 0;
|
|
|
|
let model = this.model.sort().at(i);
|
2020-03-06 15:19:48 +01:00
|
|
|
while (exclude_ids.includes(model.get('id')) || model.get('minimized') === true) {
|
2018-10-23 03:41:38 +02:00
|
|
|
i++;
|
|
|
|
model = this.model.at(i);
|
|
|
|
if (!model) {
|
|
|
|
return null;
|
|
|
|
}
|
2016-03-14 17:04:27 +01:00
|
|
|
}
|
2018-10-23 03:41:38 +02:00
|
|
|
return model;
|
2016-03-14 17:04:27 +01:00
|
|
|
}
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
2019-05-24 13:52:15 +02:00
|
|
|
Object.assign(_converse.ChatBoxViews.prototype, chatTrimmer);
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
|
2020-03-31 13:15:57 +02:00
|
|
|
api.promises.add('minimizedChatsInitialized');
|
2018-10-23 03:41:38 +02:00
|
|
|
|
2019-09-19 16:54:55 +02:00
|
|
|
_converse.MinimizedChatBoxView = View.extend({
|
2018-10-23 03:41:38 +02:00
|
|
|
tagName: 'div',
|
|
|
|
events: {
|
|
|
|
'click .close-chatbox-button': 'close',
|
|
|
|
'click .restore-chat': 'restore'
|
|
|
|
},
|
2016-12-20 11:42:20 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
initialize () {
|
2019-09-06 14:34:59 +02:00
|
|
|
this.listenTo(this.model, 'change:num_unread', this.render)
|
|
|
|
this.listenTo(this.model, 'change:name', this.render)
|
|
|
|
this.listenTo(this.model, 'change:fullname', this.render)
|
|
|
|
this.listenTo(this.model, 'change:jid', this.render)
|
|
|
|
this.listenTo(this.model, 'destroy', this.remove)
|
2019-10-22 18:33:54 +02:00
|
|
|
/**
|
|
|
|
* Triggered once a {@link _converse.MinimizedChatBoxView } has been initialized
|
|
|
|
* @event _converse#minimizedChatViewInitialized
|
|
|
|
* @type { _converse.MinimizedChatBoxView }
|
|
|
|
* @example _converse.api.listen.on('minimizedChatViewInitialized', view => { ... });
|
|
|
|
*/
|
2020-03-31 13:15:57 +02:00
|
|
|
api.trigger('minimizedChatViewInitialized', this);
|
2018-10-23 03:41:38 +02:00
|
|
|
},
|
2016-12-20 11:42:20 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
render () {
|
2019-04-29 09:07:15 +02:00
|
|
|
const data = Object.assign(
|
2019-05-29 13:00:45 +02:00
|
|
|
this.model.toJSON(), {
|
|
|
|
'tooltip': __('Click to restore this chat'),
|
|
|
|
'title': this.model.getDisplayName()
|
|
|
|
});
|
2018-10-23 03:41:38 +02:00
|
|
|
this.el.innerHTML = tpl_trimmed_chat(data);
|
|
|
|
return this.el;
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
close (ev) {
|
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
|
|
|
this.remove();
|
|
|
|
const view = _converse.chatboxviews.get(this.model.get('id'));
|
|
|
|
if (view) {
|
|
|
|
// This will call model.destroy(), removing it from the
|
|
|
|
// collection and will also emit 'chatBoxClosed'
|
|
|
|
view.close();
|
|
|
|
} else {
|
|
|
|
this.model.destroy();
|
2020-03-31 13:15:57 +02:00
|
|
|
api.trigger('chatBoxClosed', this);
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2020-03-24 12:26:34 +01:00
|
|
|
restore: debounce(function (ev) {
|
2018-10-23 03:41:38 +02:00
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
|
|
|
this.model.off('change:num_unread', null, this);
|
|
|
|
this.remove();
|
|
|
|
this.model.maximize();
|
|
|
|
}, 200, {'leading': true})
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2019-05-23 14:26:20 +02:00
|
|
|
_converse.MinimizedChats = Overview.extend({
|
2018-10-23 03:41:38 +02:00
|
|
|
tagName: 'div',
|
|
|
|
id: "minimized-chats",
|
|
|
|
className: 'hidden',
|
|
|
|
events: {
|
|
|
|
"click #toggle-minimized-chats": "toggle"
|
|
|
|
},
|
2016-12-20 10:30:20 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
initialize () {
|
|
|
|
this.render();
|
|
|
|
this.initToggle();
|
|
|
|
this.addMultipleChats(this.model.where({'minimized': true}));
|
2019-09-06 14:34:59 +02:00
|
|
|
this.listenTo(this.model, "add", this.onChanged)
|
|
|
|
this.listenTo(this.model, "destroy", this.removeChat)
|
|
|
|
this.listenTo(this.model, "change:minimized", this.onChanged)
|
|
|
|
this.listenTo(this.model, 'change:num_unread', this.updateUnreadMessagesCounter)
|
2018-10-23 03:41:38 +02:00
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
render () {
|
|
|
|
if (!this.el.parentElement) {
|
|
|
|
this.el.innerHTML = tpl_chats_panel();
|
|
|
|
_converse.chatboxviews.insertRowColumn(this.el);
|
2016-03-14 17:04:27 +01:00
|
|
|
}
|
2018-10-23 03:41:38 +02:00
|
|
|
if (this.keys().length === 0) {
|
|
|
|
this.el.classList.add('hidden');
|
|
|
|
} else if (this.keys().length > 0 && !u.isVisible(this.el)) {
|
|
|
|
this.el.classList.remove('hidden');
|
|
|
|
}
|
|
|
|
return this.el;
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
initToggle () {
|
2019-12-17 13:39:32 +01:00
|
|
|
const id = `converse.minchatstoggle-${_converse.bare_jid}`;
|
2018-10-23 03:41:38 +02:00
|
|
|
this.toggleview = new _converse.MinimizedChatsToggleView({
|
|
|
|
'model': new _converse.MinimizedChatsToggle({'id': id})
|
|
|
|
});
|
2019-12-17 13:39:32 +01:00
|
|
|
this.toggleview.model.browserStorage = _converse.createStore(id);
|
2018-10-23 03:41:38 +02:00
|
|
|
this.toggleview.model.fetch();
|
|
|
|
},
|
|
|
|
|
|
|
|
toggle (ev) {
|
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
|
|
|
this.toggleview.model.save({'collapsed': !this.toggleview.model.get('collapsed')});
|
|
|
|
u.slideToggleElement(this.el.querySelector('.minimized-chats-flyout'), 200);
|
|
|
|
},
|
|
|
|
|
|
|
|
onChanged (item) {
|
|
|
|
if (item.get('id') === 'controlbox') {
|
|
|
|
// The ControlBox has it's own minimize toggle
|
|
|
|
return;
|
2016-03-14 17:04:27 +01:00
|
|
|
}
|
2018-10-23 03:41:38 +02:00
|
|
|
if (item.get('minimized')) {
|
|
|
|
this.addChat(item);
|
|
|
|
} else if (this.get(item.get('id'))) {
|
|
|
|
this.removeChat(item);
|
|
|
|
}
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
addChatView (item) {
|
|
|
|
const existing = this.get(item.get('id'));
|
|
|
|
if (existing && existing.el.parentNode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const view = new _converse.MinimizedChatBoxView({model: item});
|
|
|
|
this.el.querySelector('.minimized-chats-flyout').insertAdjacentElement('beforeEnd', view.render());
|
|
|
|
this.add(item.get('id'), view);
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
addMultipleChats (items) {
|
2019-09-07 22:00:28 +02:00
|
|
|
items.forEach(item => this.addChatView(item));
|
2018-10-23 03:41:38 +02:00
|
|
|
this.toggleview.model.set({'num_minimized': this.keys().length});
|
|
|
|
this.render();
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
addChat (item) {
|
|
|
|
this.addChatView(item);
|
|
|
|
this.toggleview.model.set({'num_minimized': this.keys().length});
|
|
|
|
this.render();
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
removeChat (item) {
|
|
|
|
this.remove(item.get('id'));
|
|
|
|
this.toggleview.model.set({'num_minimized': this.keys().length});
|
|
|
|
this.render();
|
|
|
|
},
|
2016-03-14 17:04:27 +01:00
|
|
|
|
2018-10-23 03:41:38 +02:00
|
|
|
updateUnreadMessagesCounter () {
|
2020-03-24 12:26:34 +01:00
|
|
|
this.toggleview.model.save({'num_unread': sum(this.model.pluck('num_unread'))});
|
2018-10-23 03:41:38 +02:00
|
|
|
this.render();
|
|
|
|
}
|
|
|
|
});
|
2017-08-16 12:31:17 +02:00
|
|
|
|
2018-05-30 17:16:26 +02:00
|
|
|
|
2019-09-19 16:54:55 +02:00
|
|
|
_converse.MinimizedChatsToggle = Model.extend({
|
2018-10-23 03:41:38 +02:00
|
|
|
defaults: {
|
|
|
|
'collapsed': false,
|
|
|
|
'num_minimized': 0,
|
|
|
|
'num_unread': 0
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2019-09-19 16:54:55 +02:00
|
|
|
_converse.MinimizedChatsToggleView = View.extend({
|
2019-08-02 14:22:38 +02:00
|
|
|
_setElement (){
|
|
|
|
this.el = _converse.root.querySelector('#toggle-minimized-chats');
|
|
|
|
},
|
2018-10-23 03:41:38 +02:00
|
|
|
|
|
|
|
initialize () {
|
2019-09-06 14:34:59 +02:00
|
|
|
this.listenTo(this.model, 'change:num_minimized', this.render)
|
|
|
|
this.listenTo(this.model, 'change:num_unread', this.render)
|
2018-10-23 03:41:38 +02:00
|
|
|
this.flyout = this.el.parentElement.querySelector('.minimized-chats-flyout');
|
|
|
|
},
|
|
|
|
|
|
|
|
render () {
|
|
|
|
this.el.innerHTML = tpl_toggle_chats(
|
2019-04-29 09:07:15 +02:00
|
|
|
Object.assign(this.model.toJSON(), {
|
2018-10-23 03:41:38 +02:00
|
|
|
'Minimized': __('Minimized')
|
|
|
|
})
|
|
|
|
);
|
|
|
|
if (this.model.get('collapsed')) {
|
|
|
|
u.hideElement(this.flyout);
|
|
|
|
} else {
|
|
|
|
u.showElement(this.flyout);
|
|
|
|
}
|
|
|
|
return this.el;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-12-17 13:39:32 +01:00
|
|
|
function initMinimizedChats () {
|
|
|
|
_converse.minimized_chats = new _converse.MinimizedChats({model: _converse.chatboxes});
|
2019-03-29 21:36:49 +01:00
|
|
|
/**
|
2020-01-07 18:19:52 +01:00
|
|
|
* Triggered once the _converse.MinimizedChats instance has been initialized
|
2019-03-29 21:36:49 +01:00
|
|
|
* @event _converse#minimizedChatsInitialized
|
|
|
|
* @example _converse.api.listen.on('minimizedChatsInitialized', () => { ... });
|
|
|
|
*/
|
2020-03-31 13:15:57 +02:00
|
|
|
api.trigger('minimizedChatsInitialized');
|
2019-12-17 13:39:32 +01:00
|
|
|
}
|
2018-05-30 17:16:26 +02:00
|
|
|
|
2020-04-06 17:21:38 +02:00
|
|
|
function addMinimizeButtonToChat (view, buttons) {
|
|
|
|
const data = {
|
|
|
|
'a_class': 'toggle-chatbox-button',
|
|
|
|
'handler': ev => view.minimize(ev),
|
|
|
|
'i18n_text': __('Minimize'),
|
|
|
|
'i18n_title': __('Minimize this chat'),
|
|
|
|
'icon_class': "fa-minus",
|
|
|
|
'name': 'minimize',
|
|
|
|
'standalone': _converse.api.settings.get("view_mode") === 'overlayed'
|
|
|
|
}
|
|
|
|
const names = buttons.map(t => t.name);
|
|
|
|
const idx = names.indexOf('close');
|
|
|
|
return idx > -1 ? [...buttons.slice(0, idx), data, ...buttons.slice(idx)] : [data, ...buttons];
|
|
|
|
}
|
|
|
|
|
|
|
|
function addMinimizeButtonToMUC (view, buttons) {
|
|
|
|
const data = {
|
|
|
|
'a_class': 'toggle-chatbox-button',
|
|
|
|
'handler': ev => view.minimize(ev),
|
|
|
|
'i18n_text': __('Minimize'),
|
|
|
|
'i18n_title': __('Minimize this groupchat'),
|
|
|
|
'icon_class': "fa-minus",
|
|
|
|
'name': 'minimize',
|
|
|
|
'standalone': _converse.api.settings.get("view_mode") === 'overlayed'
|
|
|
|
}
|
|
|
|
const names = buttons.map(t => t.name);
|
|
|
|
const idx = names.indexOf('signout');
|
|
|
|
return idx > -1 ? [...buttons.slice(0, idx), data, ...buttons.slice(idx)] : [data, ...buttons];
|
|
|
|
}
|
|
|
|
|
2019-12-17 13:39:32 +01:00
|
|
|
/************************ BEGIN Event Handlers ************************/
|
2020-03-31 13:15:57 +02:00
|
|
|
api.listen.on('chatBoxInsertedIntoDOM', view => _converse.chatboxviews.trimChats(view));
|
2020-04-06 17:20:55 +02:00
|
|
|
api.listen.on('chatBoxViewsInitialized', () => initMinimizedChats());
|
2020-03-31 13:15:57 +02:00
|
|
|
api.listen.on('controlBoxOpened', view => _converse.chatboxviews.trimChats(view));
|
2020-04-06 17:20:55 +02:00
|
|
|
api.listen.on('chatBoxViewInitialized', v => v.listenTo(v.model, 'change:minimized', v.onMinimizedChanged));
|
|
|
|
|
|
|
|
api.listen.on('chatRoomViewInitialized', view => {
|
|
|
|
view.listenTo(view.model, 'change:minimized', view.onMinimizedChanged)
|
|
|
|
view.model.get('minimized') && view.hide();
|
|
|
|
});
|
2019-12-17 13:39:32 +01:00
|
|
|
|
2020-04-06 17:21:38 +02:00
|
|
|
api.listen.on('getHeadingButtons', (view, buttons) => {
|
|
|
|
if (view.model.get('type') === _converse.CHATROOMS_TYPE) {
|
|
|
|
return addMinimizeButtonToMUC(view, buttons);
|
|
|
|
} else {
|
|
|
|
return addMinimizeButtonToChat(view, buttons);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-03-24 12:26:34 +01:00
|
|
|
const debouncedTrimChats = debounce(() => _converse.chatboxviews.trimChats(), 250);
|
2020-03-31 13:15:57 +02:00
|
|
|
api.listen.on('registeredGlobalEventHandlers', () => window.addEventListener("resize", debouncedTrimChats));
|
|
|
|
api.listen.on('unregisteredGlobalEventHandlers', () => window.removeEventListener("resize", debouncedTrimChats));
|
2019-05-24 13:52:15 +02:00
|
|
|
/************************ END Event Handlers ************************/
|
2018-10-23 03:41:38 +02:00
|
|
|
}
|
|
|
|
});
|