2016-02-20 16:06:12 +01:00
|
|
|
// Converse.js (A browser based XMPP chat client)
|
|
|
|
// http://conversejs.org
|
|
|
|
//
|
2017-02-02 19:29:38 +01:00
|
|
|
// Copyright (c) 2012-2017, Jan-Carel Brand <jc@opkode.com>
|
2016-02-20 16:06:12 +01:00
|
|
|
// Licensed under the Mozilla Public License (MPLv2)
|
|
|
|
//
|
2017-04-21 15:52:16 +02:00
|
|
|
/*global define */
|
2016-02-20 16:06:12 +01:00
|
|
|
|
|
|
|
(function (root, factory) {
|
2018-01-03 17:49:08 +01:00
|
|
|
define(["converse-core",
|
2017-08-15 16:46:55 +02:00
|
|
|
"lodash.fp",
|
2016-09-23 10:54:55 +02:00
|
|
|
"tpl!add_contact_dropdown",
|
|
|
|
"tpl!add_contact_form",
|
2017-09-09 11:20:28 +02:00
|
|
|
"tpl!converse_brand_heading",
|
2016-09-23 10:54:55 +02:00
|
|
|
"tpl!controlbox",
|
|
|
|
"tpl!controlbox_toggle",
|
|
|
|
"tpl!login_panel",
|
|
|
|
"tpl!search_contact",
|
|
|
|
"converse-chatview",
|
2017-11-17 13:32:03 +01:00
|
|
|
"converse-rosterview",
|
|
|
|
"converse-profile"
|
2016-03-13 17:16:53 +01:00
|
|
|
], factory);
|
2016-09-23 10:54:55 +02:00
|
|
|
}(this, function (
|
2016-12-20 11:42:20 +01:00
|
|
|
converse,
|
2017-08-15 16:46:55 +02:00
|
|
|
fp,
|
2016-09-23 10:54:55 +02:00
|
|
|
tpl_add_contact_dropdown,
|
|
|
|
tpl_add_contact_form,
|
2017-09-09 11:20:28 +02:00
|
|
|
tpl_brand_heading,
|
2016-09-23 10:54:55 +02:00
|
|
|
tpl_controlbox,
|
|
|
|
tpl_controlbox_toggle,
|
|
|
|
tpl_login_panel,
|
2017-12-13 22:39:41 +01:00
|
|
|
tpl_search_contact
|
2016-09-23 10:54:55 +02:00
|
|
|
) {
|
2016-02-20 16:06:12 +01:00
|
|
|
"use strict";
|
2016-09-23 10:54:55 +02:00
|
|
|
|
2017-06-12 20:30:58 +02:00
|
|
|
const CHATBOX_TYPE = 'chatbox';
|
2018-01-03 17:49:08 +01:00
|
|
|
const { Strophe, Backbone, Promise, _, moment } = converse.env;
|
|
|
|
const u = converse.env.utils;
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2017-09-22 18:55:02 +02:00
|
|
|
const CONNECTION_STATUS_CSS_CLASS = {
|
|
|
|
'Error': 'error',
|
|
|
|
'Connecting': 'info',
|
|
|
|
'Connection failure': 'error',
|
|
|
|
'Authenticating': 'info',
|
|
|
|
'Authentication failure': 'error',
|
|
|
|
'Connected': 'info',
|
|
|
|
'Disconnected': 'error',
|
|
|
|
'Disconnecting': 'warn',
|
|
|
|
'Attached': 'info',
|
|
|
|
'Redirect': 'info',
|
|
|
|
'Reconnecting': 'warn'
|
|
|
|
};
|
|
|
|
|
|
|
|
const PRETTY_CONNECTION_STATUS = {
|
|
|
|
0: 'Error',
|
|
|
|
1: 'Connecting',
|
|
|
|
2: 'Connection failure',
|
|
|
|
3: 'Authenticating',
|
|
|
|
4: 'Authentication failure',
|
|
|
|
5: 'Connected',
|
|
|
|
6: 'Disconnected',
|
|
|
|
7: 'Disconnecting',
|
|
|
|
8: 'Attached',
|
|
|
|
9: 'Redirect',
|
|
|
|
10: 'Reconnecting'
|
|
|
|
};
|
|
|
|
|
|
|
|
const REPORTABLE_STATUSES = [
|
|
|
|
0, // ERROR'
|
|
|
|
1, // CONNECTING
|
|
|
|
2, // CONNFAIL
|
|
|
|
3, // AUTHENTICATING
|
|
|
|
4, // AUTHFAIL
|
|
|
|
7, // DISCONNECTING
|
|
|
|
10 // RECONNECTING
|
|
|
|
];
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2016-12-20 11:42:20 +01:00
|
|
|
converse.plugins.add('converse-controlbox', {
|
2018-01-10 14:26:35 +01:00
|
|
|
/* Plugin dependencies are other plugins which might be
|
|
|
|
* overridden or relied upon, and therefore need to be loaded before
|
|
|
|
* this plugin.
|
|
|
|
*
|
|
|
|
* If the setting "strict_plugin_dependencies" is set to true,
|
|
|
|
* an error will be raised if the plugin is not found. By default it's
|
|
|
|
* false, which means these plugins are only loaded opportunistically.
|
|
|
|
*
|
|
|
|
* NB: These plugins need to have already been loaded via require.js.
|
|
|
|
*/
|
2018-02-15 15:50:55 +01:00
|
|
|
dependencies: ["converse-chatboxes", "converse-rosterview"],
|
2016-02-28 20:24:06 +01: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.
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
_tearDown () {
|
2016-08-31 12:06:17 +02:00
|
|
|
this.__super__._tearDown.apply(this, arguments);
|
2016-02-29 22:18:28 +01:00
|
|
|
if (this.rosterview) {
|
|
|
|
// Removes roster groups
|
|
|
|
this.rosterview.model.off().reset();
|
2016-11-02 14:13:49 +01:00
|
|
|
this.rosterview.each(function (groupview) {
|
|
|
|
groupview.removeAll();
|
|
|
|
groupview.remove();
|
|
|
|
});
|
2016-11-03 10:44:37 +01:00
|
|
|
this.rosterview.removeAll().remove();
|
2016-02-29 22:18:28 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
clearSession () {
|
2016-08-31 12:06:17 +02:00
|
|
|
this.__super__.clearSession.apply(this, arguments);
|
2018-01-22 12:36:58 +01:00
|
|
|
const chatboxes = _.get(this, 'chatboxes', null);
|
|
|
|
if (!_.isNil(chatboxes)) {
|
|
|
|
const controlbox = chatboxes.get('controlbox');
|
|
|
|
if (controlbox &&
|
|
|
|
controlbox.collection &&
|
|
|
|
controlbox.collection.browserStorage) {
|
|
|
|
controlbox.save({'connected': false});
|
|
|
|
}
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
ChatBoxes: {
|
2017-07-10 17:46:22 +02:00
|
|
|
chatBoxMayBeShown (chatbox) {
|
2016-08-31 12:06:17 +02:00
|
|
|
return this.__super__.chatBoxMayBeShown.apply(this, arguments) &&
|
2016-03-14 17:04:27 +01:00
|
|
|
chatbox.get('id') !== 'controlbox';
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
onChatBoxesFetched (collection, resp) {
|
2016-08-31 12:06:17 +02:00
|
|
|
this.__super__.onChatBoxesFetched.apply(this, arguments);
|
2017-08-16 12:24:20 +02:00
|
|
|
const { _converse } = this.__super__;
|
2017-03-03 15:25:05 +01:00
|
|
|
if (!_.includes(_.map(collection, 'id'), 'controlbox')) {
|
2017-08-16 14:16:24 +02:00
|
|
|
_converse.addControlBox();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2017-08-16 14:16:24 +02:00
|
|
|
this.get('controlbox').save({connected:true});
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
ChatBoxViews: {
|
2017-07-10 17:46:22 +02:00
|
|
|
onChatBoxAdded (item) {
|
|
|
|
const { _converse } = this.__super__;
|
2016-03-29 17:41:27 +02:00
|
|
|
if (item.get('box_id') === 'controlbox') {
|
2017-07-10 17:46:22 +02:00
|
|
|
let view = this.get(item.get('id'));
|
2016-03-29 17:41:27 +02:00
|
|
|
if (view) {
|
|
|
|
view.model = item;
|
|
|
|
view.initialize();
|
|
|
|
return view;
|
|
|
|
} else {
|
2016-12-20 10:30:20 +01:00
|
|
|
view = new _converse.ControlBoxView({model: item});
|
2016-03-29 17:41:27 +02:00
|
|
|
return this.add(item.get('id'), view);
|
|
|
|
}
|
2016-02-28 20:24:06 +01:00
|
|
|
} else {
|
2016-08-31 12:06:17 +02:00
|
|
|
return this.__super__.onChatBoxAdded.apply(this, arguments);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
closeAllChatBoxes () {
|
|
|
|
const { _converse } = this.__super__;
|
2016-02-28 20:24:06 +01:00
|
|
|
this.each(function (view) {
|
2017-02-14 18:23:22 +01:00
|
|
|
if (view.model.get('id') === 'controlbox' &&
|
|
|
|
(_converse.disconnection_cause !== _converse.LOGOUT || _converse.show_controlbox_by_default)) {
|
|
|
|
return;
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2017-02-14 18:23:22 +01:00
|
|
|
view.close();
|
2016-02-28 20:24:06 +01:00
|
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
getChatBoxWidth (view) {
|
|
|
|
const { _converse } = this.__super__;
|
|
|
|
const controlbox = this.get('controlbox');
|
2016-02-28 20:24:06 +01:00
|
|
|
if (view.model.get('id') === 'controlbox') {
|
|
|
|
/* We return the width of the controlbox or its toggle,
|
|
|
|
* depending on which is visible.
|
|
|
|
*/
|
2018-01-03 17:49:08 +01:00
|
|
|
if (!controlbox || !u.isVisible(controlbox.el)) {
|
|
|
|
return u.getOuterWidth(_converse.controlboxtoggle.el, true);
|
2016-02-28 20:24:06 +01:00
|
|
|
} else {
|
2018-01-03 17:49:08 +01:00
|
|
|
return u.getOuterWidth(controlbox.el, true);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
} else {
|
2016-08-31 12:06:17 +02:00
|
|
|
return this.__super__.getChatBoxWidth.apply(this, arguments);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
ChatBox: {
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize () {
|
2016-02-28 20:24:06 +01:00
|
|
|
if (this.get('id') === 'controlbox') {
|
2017-05-23 18:15:28 +02:00
|
|
|
this.set({'time_opened': moment(0).valueOf()});
|
2016-02-28 20:24:06 +01:00
|
|
|
} else {
|
2016-08-31 12:06:17 +02:00
|
|
|
this.__super__.initialize.apply(this, arguments);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
ChatBoxView: {
|
2018-02-15 15:50:55 +01:00
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
insertIntoDOM () {
|
2017-08-29 11:08:37 +02:00
|
|
|
const view = this.__super__._converse.chatboxviews.get("controlbox");
|
|
|
|
if (view) {
|
|
|
|
view.el.insertAdjacentElement('afterend', this.el)
|
|
|
|
} else {
|
|
|
|
this.__super__.insertIntoDOM.apply(this, arguments);
|
|
|
|
}
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize () {
|
2016-02-28 20:24:06 +01:00
|
|
|
/* The initialize function gets called as soon as the plugin is
|
|
|
|
* loaded by converse.js's plugin machinery.
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
const { _converse } = this,
|
|
|
|
{ __ } = _converse;
|
2016-12-20 11:42:20 +01:00
|
|
|
|
2017-07-05 11:03:13 +02:00
|
|
|
_converse.api.settings.update({
|
2016-03-17 13:24:26 +01:00
|
|
|
allow_logout: true,
|
|
|
|
default_domain: undefined,
|
2017-08-15 10:23:57 +02:00
|
|
|
locked_domain: undefined,
|
2016-02-28 20:24:06 +01:00
|
|
|
show_controlbox_by_default: false,
|
2016-03-31 11:16:21 +02:00
|
|
|
sticky_controlbox: false,
|
2016-03-17 13:24:26 +01:00
|
|
|
xhr_user_search: false,
|
|
|
|
xhr_user_search_url: ''
|
2016-03-13 17:22:42 +01:00
|
|
|
});
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2017-09-16 19:17:54 +02:00
|
|
|
_converse.api.promises.add('controlboxInitialized');
|
|
|
|
|
2017-06-12 20:30:58 +02:00
|
|
|
const LABEL_CONTACTS = __('Contacts');
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2017-08-16 14:16:24 +02:00
|
|
|
_converse.addControlBox = () => {
|
|
|
|
_converse.chatboxes.add({
|
2016-02-28 20:24:06 +01:00
|
|
|
id: 'controlbox',
|
|
|
|
box_id: 'controlbox',
|
2017-06-12 20:30:58 +02:00
|
|
|
type: 'controlbox',
|
2016-12-20 10:30:20 +01:00
|
|
|
closed: !_converse.show_controlbox_by_default
|
2017-08-16 14:16:24 +02:00
|
|
|
})
|
2017-08-16 12:24:20 +02:00
|
|
|
};
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.ControlBoxView = _converse.ChatBoxView.extend({
|
2016-02-28 20:24:06 +01:00
|
|
|
tagName: 'div',
|
2017-09-27 00:36:19 +02:00
|
|
|
className: 'chatbox',
|
2016-02-28 20:24:06 +01:00
|
|
|
id: 'controlbox',
|
|
|
|
events: {
|
2018-02-15 15:50:55 +01:00
|
|
|
'click a.close-chatbox-button': 'close'
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize () {
|
2017-08-29 11:08:37 +02:00
|
|
|
if (_.isUndefined(_converse.controlboxtoggle)) {
|
|
|
|
_converse.controlboxtoggle = new _converse.ControlBoxToggle();
|
|
|
|
}
|
2018-02-15 15:50:55 +01:00
|
|
|
_converse.controlboxtoggle.el.insertAdjacentElement('afterend', this.el);
|
|
|
|
|
2016-02-28 20:24:06 +01:00
|
|
|
this.model.on('change:connected', this.onConnected, this);
|
|
|
|
this.model.on('destroy', this.hide, this);
|
|
|
|
this.model.on('hide', this.hide, this);
|
|
|
|
this.model.on('show', this.show, this);
|
|
|
|
this.model.on('change:closed', this.ensureClosedState, this);
|
|
|
|
this.render();
|
2017-08-16 14:16:24 +02:00
|
|
|
if (this.model.get('connected')) {
|
|
|
|
_converse.api.waitUntil('rosterViewInitialized')
|
|
|
|
.then(this.insertRoster.bind(this))
|
|
|
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
|
|
|
}
|
2017-11-10 15:53:59 +01:00
|
|
|
_converse.emit('controlboxInitialized', this);
|
2017-02-15 08:46:24 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
render () {
|
2017-02-15 08:46:24 +01:00
|
|
|
if (this.model.get('connected')) {
|
2017-02-14 18:23:22 +01:00
|
|
|
if (_.isUndefined(this.model.get('closed'))) {
|
|
|
|
this.model.set('closed', !_converse.show_controlbox_by_default);
|
|
|
|
}
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2017-05-16 11:54:20 +02:00
|
|
|
this.el.innerHTML = tpl_controlbox(
|
2016-03-31 11:16:21 +02:00
|
|
|
_.extend(this.model.toJSON(), {
|
2017-05-16 11:54:20 +02:00
|
|
|
'sticky_controlbox': _converse.sticky_controlbox
|
|
|
|
}));
|
|
|
|
|
2018-02-15 15:50:55 +01:00
|
|
|
if (!this.model.get('closed')) {
|
|
|
|
this.show();
|
|
|
|
} else {
|
|
|
|
this.hide();
|
|
|
|
}
|
2017-05-16 11:54:20 +02:00
|
|
|
if (!_converse.connection.connected ||
|
|
|
|
!_converse.connection.authenticated ||
|
|
|
|
_converse.connection.disconnecting) {
|
2016-02-28 20:24:06 +01:00
|
|
|
this.renderLoginPanel();
|
2017-05-16 11:54:20 +02:00
|
|
|
} else if (this.model.get('connected') &&
|
2018-02-15 15:50:55 +01:00
|
|
|
(!this.controlbox_pane || !u.isVisible(this.controlbox_pane.el))) {
|
|
|
|
this.renderControlBoxPane();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
onConnected () {
|
2016-02-28 20:24:06 +01:00
|
|
|
if (this.model.get('connected')) {
|
2017-08-16 12:31:17 +02:00
|
|
|
this.render();
|
|
|
|
_converse.api.waitUntil('rosterViewInitialized')
|
|
|
|
.then(this.insertRoster.bind(this))
|
|
|
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
2017-03-03 14:43:13 +01:00
|
|
|
this.model.save();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
insertRoster () {
|
2017-09-22 10:45:03 +02:00
|
|
|
/* Place the rosterview inside the "Contacts" panel. */
|
2018-02-15 15:50:55 +01:00
|
|
|
this.controlbox_pane.el.insertAdjacentElement(
|
2017-09-22 10:45:03 +02:00
|
|
|
'beforeEnd',
|
|
|
|
_converse.rosterview.el
|
|
|
|
);
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-09-22 10:45:03 +02:00
|
|
|
createBrandHeadingHTML () {
|
2017-09-17 01:30:52 +02:00
|
|
|
return tpl_brand_heading();
|
|
|
|
},
|
|
|
|
|
|
|
|
insertBrandHeading () {
|
2017-09-22 10:45:03 +02:00
|
|
|
const heading_el = this.el.querySelector('.brand-heading-container');
|
|
|
|
if (_.isNull(heading_el)) {
|
|
|
|
const el = this.el.querySelector('.controlbox-head');
|
|
|
|
el.insertAdjacentHTML('beforeend', this.createBrandHeadingHTML());
|
|
|
|
} else {
|
|
|
|
heading_el.outerHTML = this.createBrandHeadingHTML();
|
|
|
|
}
|
2017-09-09 11:20:28 +02:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
renderLoginPanel () {
|
2017-09-09 11:20:28 +02:00
|
|
|
this.el.classList.add("logged-out");
|
2018-02-15 15:50:55 +01:00
|
|
|
this.el.classList.remove("col-xl-2");
|
|
|
|
this.el.classList.remove("col-md-3");
|
2017-09-22 10:45:03 +02:00
|
|
|
if (_.isNil(this.loginpanel)) {
|
2017-09-22 18:55:02 +02:00
|
|
|
this.loginpanel = new _converse.LoginPanel({
|
|
|
|
'model': new _converse.LoginPanelModel()
|
|
|
|
});
|
2017-09-22 10:45:03 +02:00
|
|
|
const panes = this.el.querySelector('.controlbox-panes');
|
|
|
|
panes.innerHTML = '';
|
|
|
|
panes.appendChild(this.loginpanel.render().el);
|
|
|
|
this.insertBrandHeading();
|
|
|
|
} else {
|
|
|
|
this.loginpanel.render();
|
|
|
|
}
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2018-02-15 15:50:55 +01:00
|
|
|
renderControlBoxPane () {
|
2017-09-22 10:45:03 +02:00
|
|
|
/* Renders the "Contacts" panel of the controlbox.
|
|
|
|
*
|
|
|
|
* This will only be called after the user has already been
|
|
|
|
* logged in.
|
|
|
|
*/
|
|
|
|
if (this.loginpanel) {
|
|
|
|
this.loginpanel.remove();
|
|
|
|
delete this.loginpanel;
|
|
|
|
}
|
|
|
|
this.el.classList.remove("logged-out");
|
2018-02-15 15:50:55 +01:00
|
|
|
this.el.classList.add("col-xl-2");
|
|
|
|
this.el.classList.add("col-md-3");
|
2017-09-22 10:45:03 +02:00
|
|
|
|
2018-02-15 15:50:55 +01:00
|
|
|
this.controlbox_pane = new _converse.ControlBoxPane();
|
|
|
|
this.el.querySelector('.controlbox-panes').insertAdjacentElement(
|
|
|
|
'afterBegin',
|
|
|
|
this.controlbox_pane.el
|
|
|
|
)
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
close (ev) {
|
2016-02-28 20:24:06 +01:00
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
2017-06-15 15:01:29 +02:00
|
|
|
if (_converse.sticky_controlbox) {
|
|
|
|
return;
|
|
|
|
}
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.connection.connected && !_converse.connection.disconnecting) {
|
2016-02-28 20:24:06 +01:00
|
|
|
this.model.save({'closed': true});
|
|
|
|
} else {
|
|
|
|
this.model.trigger('hide');
|
|
|
|
}
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.emit('controlBoxClosed', this);
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
ensureClosedState () {
|
2016-02-28 20:24:06 +01:00
|
|
|
if (this.model.get('closed')) {
|
|
|
|
this.hide();
|
|
|
|
} else {
|
|
|
|
this.show();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
hide (callback) {
|
2017-06-15 15:01:29 +02:00
|
|
|
if (_converse.sticky_controlbox) {
|
|
|
|
return;
|
|
|
|
}
|
2018-01-03 17:49:08 +01:00
|
|
|
u.addClass('hidden', this.el);
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.emit('chatBoxClosed', this);
|
|
|
|
if (!_converse.connection.connected) {
|
|
|
|
_converse.controlboxtoggle.render();
|
2016-11-22 17:42:58 +01:00
|
|
|
}
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.controlboxtoggle.show(callback);
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
onControlBoxToggleHidden () {
|
2017-09-17 01:30:52 +02:00
|
|
|
this.model.set('closed', false);
|
|
|
|
this.el.classList.remove('hidden');
|
|
|
|
_converse.emit('controlBoxOpened', this);
|
2016-03-14 17:04:27 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
show () {
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.controlboxtoggle.hide(
|
2016-03-14 17:04:27 +01:00
|
|
|
this.onControlBoxToggleHidden.bind(this)
|
|
|
|
);
|
2016-02-28 20:24:06 +01:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
showHelpMessages () {
|
2017-01-26 15:49:02 +01:00
|
|
|
/* Override showHelpMessages in ChatBoxView, for now do nothing.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* (Array) msgs: Array of messages
|
|
|
|
*/
|
2016-02-28 20:24:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-09-22 18:55:02 +02:00
|
|
|
_converse.LoginPanelModel = Backbone.Model.extend({
|
|
|
|
defaults: {
|
2018-02-08 17:05:22 +01:00
|
|
|
// Passed-by-reference. Fine in this case because there's
|
|
|
|
// only one such model.
|
2017-09-22 18:55:02 +02:00
|
|
|
'errors': [],
|
|
|
|
}
|
|
|
|
});
|
2016-02-28 20:24:06 +01:00
|
|
|
|
2017-11-10 21:20:13 +01:00
|
|
|
_converse.LoginPanel = Backbone.VDOMView.extend({
|
2016-02-28 20:24:06 +01:00
|
|
|
tagName: 'div',
|
2017-09-16 18:11:31 +02:00
|
|
|
id: "converse-login-panel",
|
2017-09-17 01:30:52 +02:00
|
|
|
className: 'controlbox-pane fade-in',
|
2016-02-28 20:24:06 +01:00
|
|
|
events: {
|
2017-09-22 18:55:02 +02:00
|
|
|
'submit form#converse-login': 'authenticate',
|
2017-09-24 10:21:14 +02:00
|
|
|
'change input': 'validate'
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize (cfg) {
|
2017-09-22 18:55:02 +02:00
|
|
|
this.model.on('change', this.render, this);
|
|
|
|
this.listenTo(_converse.connfeedback, 'change', this.render);
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-12-13 22:39:41 +01:00
|
|
|
toHTML () {
|
2017-09-22 18:55:02 +02:00
|
|
|
const connection_status = _converse.connfeedback.get('connection_status');
|
|
|
|
let feedback_class, pretty_status;
|
|
|
|
if (_.includes(REPORTABLE_STATUSES, connection_status)) {
|
|
|
|
pretty_status = PRETTY_CONNECTION_STATUS[connection_status];
|
|
|
|
feedback_class = CONNECTION_STATUS_CSS_CLASS[pretty_status];
|
|
|
|
}
|
2017-11-10 21:20:13 +01:00
|
|
|
return tpl_login_panel(
|
2017-09-22 18:55:02 +02:00
|
|
|
_.extend(this.model.toJSON(), {
|
|
|
|
'__': __,
|
|
|
|
'_converse': _converse,
|
|
|
|
'ANONYMOUS': _converse.ANONYMOUS,
|
|
|
|
'EXTERNAL': _converse.EXTERNAL,
|
|
|
|
'LOGIN': _converse.LOGIN,
|
|
|
|
'PREBIND': _converse.PREBIND,
|
|
|
|
'auto_login': _converse.auto_login,
|
|
|
|
'authentication': _converse.authentication,
|
|
|
|
'connection_status': connection_status,
|
|
|
|
'conn_feedback_class': feedback_class,
|
|
|
|
'conn_feedback_subject': pretty_status,
|
|
|
|
'conn_feedback_message': _converse.connfeedback.get('message'),
|
|
|
|
'placeholder_username': (_converse.locked_domain || _converse.default_domain) &&
|
|
|
|
__('Username') || __('user@domain'),
|
|
|
|
})
|
|
|
|
);
|
2017-09-16 18:11:31 +02:00
|
|
|
},
|
|
|
|
|
2017-09-22 18:55:02 +02:00
|
|
|
validate () {
|
2017-09-22 10:45:03 +02:00
|
|
|
const form = this.el.querySelector('form');
|
2017-09-25 12:50:13 +02:00
|
|
|
const jid_element = form.querySelector('input[name=jid]');
|
|
|
|
if (jid_element.value &&
|
2017-09-22 18:55:02 +02:00
|
|
|
!_converse.locked_domain &&
|
|
|
|
!_converse.default_domain &&
|
2018-01-03 17:49:08 +01:00
|
|
|
!u.isValidJID(jid_element.value)) {
|
2017-09-25 12:50:13 +02:00
|
|
|
jid_element.setCustomValidity(__('Please enter a valid XMPP address'));
|
|
|
|
return false;
|
2017-09-22 14:09:31 +02:00
|
|
|
}
|
2017-09-25 12:50:13 +02:00
|
|
|
jid_element.setCustomValidity('');
|
|
|
|
return true;
|
2017-09-08 14:24:38 +02:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
authenticate (ev) {
|
2017-08-29 10:32:44 +02:00
|
|
|
/* Authenticate the user based on a form submission event.
|
|
|
|
*/
|
2016-02-28 20:24:06 +01:00
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.authentication === _converse.ANONYMOUS) {
|
2017-09-22 18:55:02 +02:00
|
|
|
this.connect(_converse.jid, null);
|
2016-02-28 20:24:06 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-09-22 18:55:02 +02:00
|
|
|
if (!this.validate()) {
|
|
|
|
return;
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2017-09-22 18:55:02 +02:00
|
|
|
let jid = ev.target.querySelector('input[name=jid]').value;
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.locked_domain) {
|
|
|
|
jid = Strophe.escapeNode(jid) + '@' + _converse.locked_domain;
|
|
|
|
} else if (_converse.default_domain && !_.includes(jid, '@')) {
|
|
|
|
jid = jid + '@' + _converse.default_domain;
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2017-09-25 12:50:13 +02:00
|
|
|
this.connect(
|
|
|
|
jid, _.get(ev.target.querySelector('input[name=password]'), 'value')
|
|
|
|
);
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-09-22 10:45:03 +02:00
|
|
|
connect (jid, password) {
|
2016-02-28 20:24:06 +01:00
|
|
|
if (jid) {
|
2017-09-22 10:45:03 +02:00
|
|
|
const resource = Strophe.getResourceFromJid(jid);
|
2016-02-28 20:24:06 +01:00
|
|
|
if (!resource) {
|
2016-12-20 10:30:20 +01:00
|
|
|
jid = jid.toLowerCase() + _converse.generateResource();
|
2016-02-28 20:24:06 +01:00
|
|
|
} else {
|
|
|
|
jid = Strophe.getBareJidFromJid(jid).toLowerCase()+'/'+resource;
|
|
|
|
}
|
|
|
|
}
|
2017-10-31 21:47:27 +01:00
|
|
|
if (_.includes(["converse/login", "converse/register"],
|
|
|
|
Backbone.history.getFragment())) {
|
|
|
|
_converse.router.navigate('', {'replace': true});
|
|
|
|
}
|
2017-03-31 03:54:42 +02:00
|
|
|
_converse.connection.reset();
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.connection.connect(jid, password, _converse.onConnectStatusChanged);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2018-02-15 15:50:55 +01:00
|
|
|
_converse.ControlBoxPane = Backbone.NativeView.extend({
|
2016-02-28 20:24:06 +01:00
|
|
|
tagName: 'div',
|
|
|
|
className: 'controlbox-pane',
|
|
|
|
events: {
|
|
|
|
'click a.toggle-xmpp-contact-form': 'toggleContactForm',
|
|
|
|
'submit form.add-xmpp-contact': 'addContactFromForm',
|
|
|
|
'submit form.search-xmpp-contact': 'searchContacts',
|
|
|
|
'click a.subscribe-to-user': 'addContactFromList'
|
|
|
|
},
|
|
|
|
|
2018-02-15 15:50:55 +01:00
|
|
|
initialize () {
|
|
|
|
_converse.xmppstatusview = new _converse.XMPPStatusView({
|
|
|
|
'model': _converse.xmppstatus
|
2017-06-09 23:43:58 +02:00
|
|
|
});
|
2018-02-15 15:50:55 +01:00
|
|
|
this.el.insertAdjacentElement(
|
|
|
|
'afterBegin',
|
|
|
|
_converse.xmppstatusview.render().el
|
|
|
|
);
|
2017-06-05 21:42:25 +02:00
|
|
|
},
|
|
|
|
|
2017-07-17 22:01:23 +02:00
|
|
|
generateAddContactHTML (settings={}) {
|
2017-06-05 21:42:25 +02:00
|
|
|
if (_converse.xhr_user_search) {
|
|
|
|
return tpl_search_contact({
|
|
|
|
label_contact_name: __('Contact name'),
|
|
|
|
label_search: __('Search')
|
|
|
|
});
|
|
|
|
} else {
|
2017-07-17 22:01:23 +02:00
|
|
|
return tpl_add_contact_form(_.assign({
|
|
|
|
error_message: null,
|
2017-06-05 21:42:25 +02:00
|
|
|
label_contact_username: __('e.g. user@example.org'),
|
2017-07-17 22:01:23 +02:00
|
|
|
label_add: __('Add'),
|
|
|
|
value: ''
|
|
|
|
}, settings));
|
2017-06-05 21:42:25 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
toggleContactForm (ev) {
|
2016-02-28 20:24:06 +01:00
|
|
|
ev.preventDefault();
|
2017-07-17 22:01:23 +02:00
|
|
|
this.el.querySelector('.search-xmpp div').innerHTML = this.generateAddContactHTML();
|
|
|
|
var dropdown = this.el.querySelector('.contact-form-container');
|
2018-01-03 17:49:08 +01:00
|
|
|
u.slideToggleElement(dropdown).then(() => {
|
|
|
|
if (u.isVisible(dropdown)) {
|
2017-11-17 14:42:09 +01:00
|
|
|
dropdown.querySelector('input.username').focus();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
searchContacts (ev) {
|
2016-02-28 20:24:06 +01:00
|
|
|
ev.preventDefault();
|
2018-01-03 17:49:08 +01:00
|
|
|
const search_query= ev.target.querySelector('input.username').value,
|
|
|
|
url = _converse.xhr_user_search_url+ "?q=" + search_query,
|
|
|
|
xhr = new XMLHttpRequest();
|
|
|
|
|
|
|
|
xhr.open('GET', url, true);
|
|
|
|
xhr.setRequestHeader('Accept', "application/json, text/javascript");
|
|
|
|
|
|
|
|
xhr.onload = function () {
|
|
|
|
if (xhr.status >= 200 && xhr.status < 400) {
|
|
|
|
const data = JSON.parse(xhr.responseText),
|
2018-02-09 16:02:56 +01:00
|
|
|
ul = _converse.root.querySelector('.search-xmpp ul');
|
2018-01-03 17:49:08 +01:00
|
|
|
u.removeElement(ul.querySelector('li.found-user'));
|
|
|
|
u.removeElement(ul.querySelector('li.chat-info'));
|
|
|
|
if (!data.length) {
|
|
|
|
const no_users_text = __('No users found');
|
|
|
|
ul.insertAdjacentHTML('beforeEnd', `<li class="chat-info">${no_users_text}</li>`);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const title_subscribe = __('Click to add as a chat contact');
|
|
|
|
_.each(data, function (obj) {
|
|
|
|
const li = u.stringToElement('<li class="found-user"></li>'),
|
|
|
|
a = u.stringToElement(`<a class="subscribe-to-user" href="#" title="${title_subscribe}"></a>`),
|
|
|
|
jid = Strophe.getNodeFromJid(obj.id)+"@"+Strophe.getDomainFromJid(obj.id);
|
|
|
|
|
|
|
|
a.setAttribute('data-recipient', jid);
|
|
|
|
a.textContent = obj.fullname;
|
|
|
|
li.appendChild(a);
|
|
|
|
u.appendChild(li)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xhr.onerror();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2018-01-03 17:49:08 +01:00
|
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
|
|
_converse.log('Could not fetch contacts via XHR', Strophe.LogLevel.ERROR);
|
|
|
|
};
|
|
|
|
xhr.send();
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
addContactFromForm (ev) {
|
2016-02-28 20:24:06 +01:00
|
|
|
ev.preventDefault();
|
2017-11-17 14:42:09 +01:00
|
|
|
const input = ev.target.querySelector('input');
|
|
|
|
const jid = input.value;
|
2018-02-07 13:29:54 +01:00
|
|
|
if (!jid || _.compact(jid.split('@')).length < 2) {
|
2017-07-17 22:01:23 +02:00
|
|
|
this.el.querySelector('.search-xmpp div').innerHTML =
|
|
|
|
this.generateAddContactHTML({
|
2017-09-08 19:50:34 +02:00
|
|
|
error_message: __('Please enter a valid XMPP address'),
|
2017-07-17 22:01:23 +02:00
|
|
|
label_contact_username: __('e.g. user@example.org'),
|
|
|
|
label_add: __('Add'),
|
|
|
|
value: jid
|
|
|
|
});
|
2016-02-28 20:24:06 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.roster.addAndSubscribe(jid);
|
2018-01-03 17:49:08 +01:00
|
|
|
u.slideIn(this.el.querySelector('.contact-form-container'));
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
addContactFromList (ev) {
|
2016-02-28 20:24:06 +01:00
|
|
|
ev.preventDefault();
|
2017-11-17 14:42:09 +01:00
|
|
|
const jid = ev.target.getAttribute('data-recipient'),
|
|
|
|
name = ev.target.textContent;
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.roster.addAndSubscribe(jid, name);
|
2017-11-17 14:42:09 +01:00
|
|
|
const parent = ev.target.parentNode;
|
|
|
|
parent.parentNode.removeChild(parent);
|
2018-01-03 17:49:08 +01:00
|
|
|
u.slideIn(this.el.querySelector('.contact-form-container'));
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2018-01-03 20:02:05 +01:00
|
|
|
_converse.ControlBoxToggle = Backbone.NativeView.extend({
|
2016-02-28 20:24:06 +01:00
|
|
|
tagName: 'a',
|
2016-11-22 17:42:58 +01:00
|
|
|
className: 'toggle-controlbox hidden',
|
2016-02-28 20:24:06 +01:00
|
|
|
id: 'toggle-controlbox',
|
|
|
|
events: {
|
|
|
|
'click': 'onClick'
|
|
|
|
},
|
|
|
|
attributes: {
|
|
|
|
'href': "#"
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize () {
|
2018-02-15 15:50:55 +01:00
|
|
|
_converse.chatboxviews.insertRowColumn(this.render().el);
|
|
|
|
_converse.api.waitUntil('initialized')
|
|
|
|
.then(this.render.bind(this))
|
|
|
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
render () {
|
2016-02-28 20:24:06 +01:00
|
|
|
// We let the render method of ControlBoxView decide whether
|
|
|
|
// the ControlBox or the Toggle must be shown. This prevents
|
|
|
|
// artifacts (i.e. on page load the toggle is shown only to then
|
|
|
|
// seconds later be hidden in favor of the control box).
|
2017-08-16 12:31:17 +02:00
|
|
|
this.el.innerHTML = tpl_controlbox_toggle({
|
2017-09-08 14:24:38 +02:00
|
|
|
'label_toggle': _converse.connection.connected ? __('Contacts') : __('Toggle chat')
|
2017-08-16 12:31:17 +02:00
|
|
|
})
|
|
|
|
return this;
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
hide (callback) {
|
2018-01-03 17:49:08 +01:00
|
|
|
u.hideElement(this.el);
|
2016-11-22 17:42:58 +01:00
|
|
|
callback();
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
show (callback) {
|
2018-01-03 17:49:08 +01:00
|
|
|
u.fadeIn(this.el, callback);
|
2016-02-28 20:24:06 +01:00
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
showControlBox () {
|
|
|
|
let controlbox = _converse.chatboxes.get('controlbox');
|
2016-02-28 20:24:06 +01:00
|
|
|
if (!controlbox) {
|
2016-12-20 10:30:20 +01:00
|
|
|
controlbox = _converse.addControlBox();
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.connection.connected) {
|
2016-02-28 20:24:06 +01:00
|
|
|
controlbox.save({closed: false});
|
|
|
|
} else {
|
|
|
|
controlbox.trigger('show');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
onClick (e) {
|
2016-02-28 20:24:06 +01:00
|
|
|
e.preventDefault();
|
2018-02-09 16:02:56 +01:00
|
|
|
if (u.isVisible(_converse.root.querySelector("#controlbox"))) {
|
2017-07-10 17:46:22 +02:00
|
|
|
const controlbox = _converse.chatboxes.get('controlbox');
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.connection.connected) {
|
2016-02-28 20:24:06 +01:00
|
|
|
controlbox.save({closed: true});
|
|
|
|
} else {
|
|
|
|
controlbox.trigger('hide');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.showControlBox();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2016-12-04 16:03:06 +01:00
|
|
|
|
2017-08-16 12:31:17 +02:00
|
|
|
Promise.all([
|
|
|
|
_converse.api.waitUntil('connectionInitialized'),
|
|
|
|
_converse.api.waitUntil('chatBoxesInitialized')
|
|
|
|
]).then(_converse.addControlBox)
|
|
|
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
const disconnect = function () {
|
2016-12-04 16:03:06 +01:00
|
|
|
/* Upon disconnection, set connected to `false`, so that if
|
|
|
|
* we reconnect,
|
|
|
|
* "onConnected" will be called, to fetch the roster again and
|
|
|
|
* to send out a presence stanza.
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
const view = _converse.chatboxviews.get('controlbox');
|
2016-12-04 16:03:06 +01:00
|
|
|
view.model.set({connected:false});
|
2017-09-08 19:50:34 +02:00
|
|
|
view.renderLoginPanel();
|
2016-12-04 16:03:06 +01:00
|
|
|
};
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.on('disconnected', disconnect);
|
2016-12-04 16:03:06 +01:00
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
const afterReconnected = function () {
|
2017-09-23 23:29:50 +02:00
|
|
|
/* After reconnection makes sure the controlbox is aware.
|
2016-12-04 16:03:06 +01:00
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
const view = _converse.chatboxviews.get('controlbox');
|
2016-12-04 16:03:06 +01:00
|
|
|
if (view.model.get('connected')) {
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.chatboxviews.get("controlbox").onConnected();
|
2016-12-04 16:03:06 +01:00
|
|
|
} else {
|
|
|
|
view.model.set({connected:true});
|
|
|
|
}
|
|
|
|
};
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.on('reconnected', afterReconnected);
|
2016-02-28 20:24:06 +01:00
|
|
|
}
|
|
|
|
});
|
2016-02-20 16:06:12 +01:00
|
|
|
}));
|