Commit da06a62b authored by JC Brand's avatar JC Brand

Regenerated dist files

parent f0b12955
......@@ -26,7 +26,7 @@
// 'prosody@conference.prosody.im',
// 'jdev@conference.jabber.org'
// ],
websocket_url: 'ws://chat.example.org:5280/xmpp-websocket',
// websocket_url: 'ws://chat.example.org:5280/xmpp-websocket',
view_mode: 'fullscreen',
archived_messages_page_size: '500',
allow_public_bookmarks: true,
......@@ -34,7 +34,7 @@
'discuss@conference.conversejs.org'
],
// bosh_service_url: 'http://chat.example.org:5280/http-bind/',
// bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
message_archiving: 'always',
debug: true
});
......
......@@ -10268,6 +10268,15 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
};
};
u.rootContains = function (root, el) {
// The document element does not have the contains method in IE.
if (root === document && !root.contains) {
return document.head.contains(el) || document.body.contains(el);
}
return root.contains ? root.contains(el) : window.HTMLElement.prototype.contains.call(root, el);
};
u.createFragmentFromText = function (markup) {
/* Returns a DocumentFragment containing DOM nodes based on the
* passed-in markup text.
......@@ -10968,6 +10977,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
_converse.chatboxviews.closeAllChatBoxes();
if (_converse.bookmarks) {
_converse.bookmarks.reset();
}
delete _converse.controlboxtoggle;
delete _converse.chatboxviews;
......@@ -11044,7 +11057,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
locales_url: 'locale/{{{locale}}}/LC_MESSAGES/converse.json',
locales: ['af', 'ar', 'bg', 'ca', 'de', 'es', 'eu', 'en', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'nb', 'nl', 'pl', 'pt_BR', 'ru', 'tr', 'uk', 'zh_CN', 'zh_TW'],
message_carbons: true,
message_storage: 'session',
nickname: undefined,
password: undefined,
prebind_url: null,
......@@ -11058,6 +11070,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
storage: 'session',
strict_plugin_dependencies: false,
synchronize_availability: true,
trusted: true,
view_mode: 'overlayed',
// Choices are 'overlayed', 'fullscreen', 'mobile'
websocket_url: undefined,
......@@ -11417,9 +11430,14 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
};
this.clearSession = function () {
if (!_.isUndefined(this.session) && this.session.browserStorage) {
if (!_converse.trusted) {
window.localStorage.clear();
window.sessionStorage.clear();
} else if (!_.isUndefined(this.session) && this.session.browserStorage) {
this.session.browserStorage._clear();
}
_converse.emit('clearSession');
};
this.logOut = function () {
......@@ -11531,14 +11549,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
this.connection.send(carbons_iq);
};
this.unregisterPresenceHandler = function () {
if (!_.isUndefined(_converse.presence_ref)) {
_converse.connection.deleteHandler(_converse.presence_ref);
delete _converse.presence_ref;
}
};
this.sendInitialPresence = function () {
if (_converse.send_initial_presence) {
_converse.xmppstatus.sendPresence();
......@@ -11798,7 +11808,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
} else if (!this.jid) {
throw new Error("attemptNonPreboundSession: If you use auto_login, " + "you also need to give either a jid value (and if " + "applicable a password) or you need to pass in a URL " + "from where the username and password can be fetched " + "(via credentials_url).");
} else {
this.autoLogin(); // Probably ANONYMOUS login
this.autoLogin(); // Could be ANONYMOUS or EXTERNAL
}
} else if (reconnecting) {
this.autoLogin();
......@@ -11812,7 +11822,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
this.jid = credentials.jid;
}
if (this.authentication === _converse.ANONYMOUS) {
if (this.authentication === _converse.ANONYMOUS || this.authentication === _converse.EXTERNAL) {
if (!this.jid) {
throw new Error("Config Error: when using anonymous login " + "you need to provide the server's domain via the 'jid' option. " + "Either when calling converse.initialize, or when calling " + "_converse.api.user.login.");
}
......@@ -11891,8 +11901,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
*/
_converse.emit('beforeTearDown');
_converse.unregisterPresenceHandler();
if (!_.isUndefined(_converse.session)) {
_converse.session.destroy();
}
......@@ -13549,8 +13557,8 @@ define("emojione", (function (global) {
throw new TypeError('disco.supports: You need to provide an entity JID');
}
return _converse.api.waitUntil('discoInitialized').then(function () {
return new Promise(function (resolve, reject) {
return new Promise(function (resolve, reject) {
return _converse.api.waitUntil('discoInitialized').then(function () {
_converse.api.disco.entities.get(entity_jid, true).then(function (entity) {
entity.waitUntilFeaturesDiscovered.then(function () {
var promises = _.concat(entity.items.map(function (item) {
......@@ -13561,8 +13569,8 @@ define("emojione", (function (global) {
resolve(f.filter(f.isObject, result));
}).catch(reject);
}).catch(reject);
});
});
}).catch(reject);
}).catch(reject);
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
},
'getIdentity': function getIdentity(category, type, entity_jid) {
......@@ -16257,7 +16265,7 @@ return __p
define('tpl!bookmark', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="list-item room-item available-chatroom d-flex flex-row ';
__p += '<div class="list-item controlbox-padded room-item available-chatroom d-flex flex-row ';
if (o.hidden) { ;
__p += ' hidden ';
} ;
......@@ -16291,7 +16299,7 @@ return __p
define('tpl!bookmarks_list', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="rooms-toggle bookmarks-toggle" title="' +
__p += '<a href="#" class="rooms-toggle bookmarks-toggle controlbox-padded" title="' +
__e(o.desc_bookmarks) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -16351,17 +16359,6 @@ return __p
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
clearSession: function clearSession() {
this.__super__.clearSession.apply(this, arguments);
if (!_.isUndefined(this.bookmarks)) {
this.bookmarks.reset();
this.bookmarks.browserStorage._clear();
window.sessionStorage.removeItem(this.bookmarks.fetched_flag);
}
},
ChatRoomView: {
events: {
'click .toggle-bookmark': 'toggleBookmark'
......@@ -16788,7 +16785,7 @@ return __p
insertIntoControlBox: function insertIntoControlBox() {
var controlboxview = _converse.chatboxviews.get('controlbox');
if (!_.isUndefined(controlboxview) && !_converse.root.contains(this.el)) {
if (!_.isUndefined(controlboxview) && !u.rootContains(_converse.root, this.el)) {
var el = controlboxview.el.querySelector('.bookmarks-list');
if (!_.isNull(el)) {
......@@ -16898,6 +16895,14 @@ return __p
'event': 'roomsPanelRendered'
}], initBookmarks);
_converse.on('clearSession', function () {
if (!_.isUndefined(_converse.bookmarks)) {
_converse.bookmarks.browserStorage._clear();
window.sessionStorage.removeItem(_converse.bookmarks.fetched_flag);
}
});
_converse.on('reconnected', initBookmarks);
_converse.on('connected', function () {
......@@ -21276,7 +21281,7 @@ return __p
model: _converse.Message,
comparator: 'time'
});
_converse.ChatBox = Backbone.Model.extend({
_converse.ChatBox = _converse.ModelWithVCardAndPresence.extend({
defaults: {
'bookmarked': false,
'chat_state': undefined,
......@@ -21288,15 +21293,7 @@ return __p
initialize: function initialize() {
var _this4 = this;
this.vcard = _converse.vcards.findWhere({
'jid': this.get('jid')
});
if (_.isNil(this.vcard)) {
this.vcard = _converse.vcards.create({
'jid': this.get('jid')
});
}
_converse.ModelWithVCardAndPresence.prototype.initialize.apply(this, arguments);
_converse.api.waitUntil('rosterContactsFetched').then(function () {
_this4.addRelatedContact(_converse.roster.findWhere({
......@@ -21305,7 +21302,7 @@ return __p
});
this.messages = new _converse.Messages();
this.messages.browserStorage = new Backbone.BrowserStorage[_converse.message_storage](b64_sha1("converse.messages".concat(this.get('jid')).concat(_converse.bare_jid)));
this.messages.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.messages".concat(this.get('jid')).concat(_converse.bare_jid)));
this.messages.chatbox = this;
this.messages.on('change:upload', function (message) {
if (message.get('upload') === _converse.SUCCESS) {
......@@ -22604,9 +22601,8 @@ return __p
this.model.messages.on('add', this.onMessageAdded, this);
this.model.messages.on('rendered', this.scrollDown, this);
this.model.on('show', this.show, this);
this.model.on('destroy', this.remove, this); // TODO check for changed fullname as well
this.model.on('change:chat_status', this.onChatStatusChanged, this);
this.model.on('destroy', this.remove, this);
this.model.presence.on('change:show', this.onPresenceChanged, this);
this.model.on('showHelpMessages', this.showHelpMessages, this);
this.render();
this.fetchMessages();
......@@ -22706,7 +22702,7 @@ return __p
}
var contact_jid = this.model.get('jid');
var resources = this.model.get('resources');
var resources = this.model.presence.get('resources');
if (_.isEmpty(resources)) {
return;
......@@ -22715,7 +22711,7 @@ return __p
Promise.all(_.map(_.keys(resources), function (resource) {
return _converse.api.disco.supports(Strophe.NS.SPOILER, "".concat(contact_jid, "/").concat(resource));
})).then(function (results) {
if (results.length) {
if (_.filter(results, 'length').length) {
var html = tpl_spoiler_button(_this4.model.toJSON());
if (_converse.visible_toolbar_buttons.emoji) {
......@@ -23130,7 +23126,11 @@ return __p
}
textarea.value = '';
textarea.focus();
textarea.focus(); // Trigger input event, so that the textarea resizes
var event = document.createEvent('Event');
event.initEvent('input', true, true);
textarea.dispatchEvent(event);
if (message !== '') {
this.onMessageSubmitted(message, spoiler_hint);
......@@ -23243,20 +23243,19 @@ return __p
toggle_el.setAttribute("data-toggle-state", "closed");
}
},
onChatStatusChanged: function onChatStatusChanged(item) {
var chat_status = item.get('chat_status');
var fullname = item.get('fullname');
onPresenceChanged: function onPresenceChanged(item) {
var show = item.get('show'),
fullname = this.model.getDisplayName();
var text;
fullname = _.isEmpty(fullname) ? item.get('jid') : fullname;
if (u.isVisible(this.el)) {
if (chat_status === 'offline') {
if (show === 'offline') {
text = fullname + ' ' + __('has gone offline');
} else if (chat_status === 'away') {
} else if (show === 'away') {
text = fullname + ' ' + __('has gone away');
} else if (chat_status === 'dnd') {
} else if (show === 'dnd') {
text = fullname + ' ' + __('is busy');
} else if (chat_status === 'online') {
} else if (show === 'online') {
text = fullname + ' ' + __('is online');
}
......@@ -23477,7 +23476,7 @@ return __p
define('tpl!login_panel', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div id="converse-login-panel" class="controlbox-pane fade-in row">\n <form id="converse-login" class="converse-form" method="post">\n <div class="conn-feedback fade-in ';
__p += '<div id="converse-login-panel" class="controlbox-pane fade-in row no-gutters">\n <form id="converse-login" class="converse-form" method="post">\n <div class="conn-feedback fade-in ';
if (!o.conn_feedback_subject) { ;
__p += ' hidden ';
} ;
......@@ -23497,20 +23496,28 @@ __p += '\n <span class="spinner fa fa-spinner centered"/>\n ';
} else { ;
__p += '\n ';
if (o.authentication == o.LOGIN || o.authentication == o.EXTERNAL) { ;
__p += '\n <div class="form-group">\n <label for="jid">' +
__p += '\n <div class="form-group">\n <label for="converse-login-jid">' +
__e(o.__("XMPP Username:")) +
'</label>\n <input class="form-control" autofocus required="required" type="text" name="jid" placeholder="' +
'</label>\n <input id="converse-login-jid" class="form-control" autofocus required="required" type="text" name="jid" placeholder="' +
__e(o.placeholder_username) +
'">\n </div>\n ';
if (o.authentication !== o.EXTERNAL) { ;
__p += '\n <div class="form-group">\n <label for="password">' +
__p += '\n <div class="form-group">\n <label for="converse-login-password">' +
__e(o.__("Password:")) +
'</label>\n <input class="form-control" required="required" type="password" name="password" placeholder="' +
'</label>\n <input id="converse-login-password" class="form-control" required="required" type="password" name="password" placeholder="' +
__e(o.__('password')) +
'">\n </div>\n ';
} ;
__p += '\n <fieldset class="buttons">\n <input class="btn btn-primary" type="submit" value="' +
__e(o.__('Submit')) +
__p += '\n <div class="form-group form-check">\n <input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ';
if (o._converse.trusted) { ;
__p += ' checked="checked" ';
} ;
__p += '>\n <label for="converse-login-trusted" class="form-check-label">' +
__e(o.__('This is a trusted device')) +
'</label>\n <i class="fa fa-info-circle" data-toggle="popover"\n data-title="Trusted device?"\n data-content="' +
__e(o.__('To improve performance, we cache your data in this browser. Uncheck this box if this is a public computer or if you want your data to be deleted when you log out. It\'s important that you explicitly log out, otherwise not all cached data might be deleted.')) +
'"></i>\n </div>\n\n <fieldset class="buttons">\n <input class="btn btn-primary" type="submit" value="' +
__e(o.__('Log in')) +
'">\n </fieldset>\n ';
} ;
__p += '\n ';
......@@ -23575,7 +23582,7 @@ return __p
define('tpl!group_header', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="group-toggle" title="' +
__p += '<a href="#" class="group-toggle controlbox-padded" title="' +
__e(o.desc_group_toggle) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -23646,7 +23653,7 @@ return __p
define('tpl!roster', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape;
__p += '<div class="d-flex">\n <span class="w-100 controlbox-heading">' +
__p += '<div class="d-flex controlbox-padded">\n <span class="w-100 controlbox-heading">' +
__e(o.heading_contacts) +
'</span>\n <a class="chatbox-btn add-contact fa fa-user-plus" title="' +
__e(o.title_add_contact) +
......@@ -23658,7 +23665,7 @@ return __p
define('tpl!roster_filter', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<form class="roster-filter-form input-button-group ';
__p += '<form class="controlbox-padded roster-filter-form input-button-group ';
if (!o.visible) { ;
__p += ' hidden ';
} ;
......@@ -23980,7 +23987,7 @@ return __p
};
name_input.addEventListener('input', _.debounce(function () {
xhr.open("GET", "".concat(_converse.xhr_user_search_url, "?q=").concat(name_input.value), true);
xhr.open("GET", "".concat(_converse.xhr_user_search_url, "q=").concat(name_input.value), true);
xhr.send();
}, 300));
this.el.addEventListener('awesomplete-selectcomplete', function (ev) {
......@@ -24148,7 +24155,7 @@ return __p
});
_converse.RosterContactView = Backbone.NativeView.extend({
tagName: 'li',
className: 'd-flex hidden',
className: 'd-flex hidden controlbox-padded',
events: {
"click .accept-xmpp-request": "acceptRequest",
"click .decline-xmpp-request": "declineRequest",
......@@ -24160,6 +24167,7 @@ return __p
this.model.on("destroy", this.remove, this);
this.model.on("open", this.openChat, this);
this.model.on("remove", this.remove, this);
this.model.presence.on("change:show", this.render, this);
this.model.vcard.on('change:fullname', this.render, this);
},
render: function render() {
......@@ -24172,7 +24180,7 @@ return __p
var item = this.model,
ask = item.get('ask'),
chat_status = item.get('chat_status'),
show = item.presence.get('show'),
requesting = item.get('requesting'),
subscription = item.get('subscription');
var classes_to_remove = ['current-xmpp-contact', 'pending-xmpp-contact', 'requesting-xmpp-contact'].concat(_.keys(STATUSES));
......@@ -24183,8 +24191,8 @@ return __p
}
});
this.el.classList.add(chat_status);
this.el.setAttribute('data-status', chat_status);
this.el.classList.add(show);
this.el.setAttribute('data-status', show);
if (ask === 'subscribe' || subscription === 'from') {
/* ask === 'subscribe'
......@@ -24226,22 +24234,22 @@ return __p
},
renderRosterItem: function renderRosterItem(item) {
var status_icon = 'fa-times-circle';
var chat_status = item.get('chat_status') || 'offline';
var show = item.presence.get('show') || 'offline';
if (chat_status === 'online') {
if (show === 'online') {
status_icon = 'fa-circle';
} else if (chat_status === 'away') {
} else if (show === 'away') {
status_icon = 'fa-dot-circle-o';
} else if (chat_status === 'xa') {
} else if (show === 'xa') {
status_icon = 'fa-circle-o';
} else if (chat_status === 'dnd') {
} else if (show === 'dnd') {
status_icon = 'fa-minus-circle';
}
var display_name = item.getDisplayName();
this.el.innerHTML = tpl_roster_item(_.extend(item.toJSON(), {
'display_name': display_name,
'desc_status': STATUSES[chat_status],
'desc_status': STATUSES[show],
'status_icon': status_icon,
'desc_chat': __('Click to chat with %1$s (JID: %2$s)', display_name, item.get('jid')),
'desc_remove': __('Click to remove %1$s as a contact', display_name),
......@@ -24257,7 +24265,7 @@ return __p
* It doesn't check for the more specific case of whether
* the group it's in is collapsed.
*/
var chatStatus = this.model.get('chat_status');
var chatStatus = this.model.presence.get('show');
if (_converse.show_only_online_users && chatStatus !== 'online' || _converse.hide_offline_users && chatStatus === 'offline') {
// If pending or requesting, show
......@@ -24338,7 +24346,7 @@ return __p
ItemView: _converse.RosterContactView,
listItems: 'model.contacts',
listSelector: '.roster-group-contacts',
sortEvent: 'change:chat_status',
sortEvent: 'presenceChanged',
initialize: function initialize() {
Backbone.OrderedListView.prototype.initialize.apply(this, arguments);
this.model.contacts.on("change:subscription", this.onContactSubscriptionChange, this);
......@@ -24428,14 +24436,16 @@ return __p
// show requesting contacts, even though they don't
// have the state in question.
matches = this.model.contacts.filter(function (contact) {
return u.contains.not('chat_status', q)(contact) && !contact.get('requesting');
return !_.includes(contact.presence.get('show'), q) && !contact.get('requesting');
});
} else if (q === 'unread_messages') {
matches = this.model.contacts.filter({
'num_unread': 0
});
} else {
matches = this.model.contacts.filter(u.contains.not('chat_status', q));
matches = this.model.contacts.filter(function (contact) {
return !_.includes(contact.presence.get('show'), q);
});
}
} else {
matches = this.model.contacts.filter(function (contact) {
......@@ -24556,6 +24566,12 @@ return __p
_converse.roster.on("remove", this.update, this);
_converse.presences.on('change:show', function () {
_this5.update();
_this5.updateFilter();
});
this.model.on("reset", this.reset, this); // This event gets triggered once *all* contacts (i.e. not
// just this group's) have been fetched from browser
// storage or the XMPP server and once they've been
......@@ -24667,11 +24683,13 @@ return __p
return this;
},
onContactAdded: function onContactAdded(contact) {
this.addRosterContact(contact).update();
this.addRosterContact(contact);
this.update();
this.updateFilter();
},
onContactChange: function onContactChange(contact) {
this.updateChatBox(contact).update();
this.updateChatBox(contact);
this.update();
if (_.has(contact.changed, 'subscription')) {
if (contact.changed.subscription === 'from') {
......@@ -24699,10 +24717,6 @@ return __p
return this;
}
if (_.has(contact.changed, 'chat_status')) {
changes.chat_status = contact.get('chat_status');
}
if (_.has(contact.changed, 'status')) {
changes.status = contact.get('status');
}
......@@ -24967,7 +24981,7 @@ return __p
define('tpl!profile_view', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="userinfo">\n<div class="profile d-flex">\n <a class="show-profile" href="#">\n <img alt="User Avatar" class="avatar align-self-center" height="40px" width="40px" src="data:' +
__p += '<div class="userinfo controlbox-padded">\n<div class="profile d-flex">\n <a class="show-profile" href="#">\n <img alt="User Avatar" class="avatar align-self-center" height="40px" width="40px" src="data:' +
__e(o.image_type) +
';base64,' +
__e(o.image) +
......@@ -25135,7 +25149,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
if (result.image) {
var word_array_from_b64 = CryptoJS.enc.Base64.parse(result['image']);
result['image_type'] = CryptoJS.SHA1(word_array_from_b64).toString();
result['image_hash'] = CryptoJS.SHA1(word_array_from_b64).toString();
}
if (callback) {
......@@ -25196,7 +25210,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
_converse.initVCardCollection = function () {
_converse.vcards = new _converse.VCards();
_converse.vcards.browserStorage = new Backbone.BrowserStorage.local(b64_sha1("converse.vcards"));
_converse.vcards.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.vcards"));
_converse.vcards.fetch();
};
......@@ -25488,8 +25502,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
/*global define */
(function (root, factory) {
define('converse-controlbox',["converse-core", "lodash.fp", "tpl!converse_brand_heading", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
})(this, function (converse, fp, tpl_brand_heading, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel) {
define('converse-controlbox',["converse-core", "bootstrap", "lodash.fp", "tpl!converse_brand_heading", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
})(this, function (converse, bootstrap, fp, tpl_brand_heading, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel) {
"use strict";
var CHATBOX_TYPE = 'chatbox';
......@@ -25565,21 +25579,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
this.rosterview.removeAll().remove();
}
},
clearSession: function clearSession() {
this.__super__.clearSession.apply(this, arguments);
var chatboxes = _.get(this, 'chatboxes', null);
if (!_.isNil(chatboxes)) {
var controlbox = chatboxes.get('controlbox');
if (controlbox && controlbox.collection && controlbox.collection.browserStorage) {
controlbox.save({
'connected': false
});
}
}
},
ChatBoxes: {
chatBoxMayBeShown: function chatBoxMayBeShown(chatbox) {
return this.__super__.chatBoxMayBeShown.apply(this, arguments) && chatbox.get('id') !== 'controlbox';
......@@ -25882,6 +25881,15 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
initialize: function initialize(cfg) {
this.model.on('change', this.render, this);
this.listenTo(_converse.connfeedback, 'change', this.render);
this.render();
_.forEach(this.el.querySelectorAll('[data-title]'), function (el) {
var popover = new bootstrap.Popover(el, {
'trigger': _converse.view_mode === 'mobile' && 'click' || 'hover',
'dismissible': _converse.view_mode === 'mobile' && true || false,
'container': _converse.chatboxviews.el
});
});
},
toHTML: function toHTML() {
var connection_status = _converse.connfeedback.get('connection_status');
......@@ -25937,7 +25945,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
return;
}
var jid = ev.target.querySelector('input[name=jid]').value;
var form_data = new FormData(ev.target);
_converse.trusted = form_data.get('trusted');
_converse.storage = form_data.get('trusted') ? 'local' : 'session';
var jid = form_data.get('jid');
if (_converse.locked_domain) {
jid = Strophe.escapeNode(jid) + '@' + _converse.locked_domain;
......@@ -25945,7 +25956,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
jid = jid + '@' + _converse.default_domain;
}
this.connect(jid, _.get(ev.target.querySelector('input[name=password]'), 'value'));
this.connect(jid, form_data.get('password'));
},
connect: function connect(jid, password) {
if (jid) {
......@@ -26044,6 +26055,23 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
}
}
});
_converse.on('clearSession', function () {
if (_converse.trusted) {
var chatboxes = _.get(_converse, 'chatboxes', null);
if (!_.isNil(chatboxes)) {
var controlbox = chatboxes.get('controlbox');
if (controlbox && controlbox.collection && controlbox.collection.browserStorage) {
controlbox.save({
'connected': false
});
}
}
}
});
Promise.all([_converse.api.waitUntil('connectionInitialized'), _converse.api.waitUntil('chatBoxesInitialized')]).then(_converse.addControlBox).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
_converse.on('chatBoxesFetched', function () {
......@@ -28114,7 +28142,7 @@ return __p
define('tpl!chatroom_head', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="col col-9">\n <div class="chat-title" title="' +
__p += '<div class="col col-8">\n <div class="chat-title" title="' +
__e(o.jid) +
'">\n ';
if (o.name && o.name !== o.Strophe.getNodeFromJid(o.jid)) { ;
......@@ -28432,7 +28460,7 @@ return __p
define('tpl!room_panel', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape;
__p += '<!-- <div id="chatrooms"> -->\n<div class="d-flex">\n <span class="w-100 controlbox-heading">' +
__p += '<!-- <div id="chatrooms"> -->\n<div class="d-flex controlbox-padded">\n <span class="w-100 controlbox-heading">' +
__e(o.heading_chatrooms) +
'</span>\n <a class="chatbox-btn trigger-list-chatrooms-modal fa fa-list-ul" title="' +
__e(o.title_list_rooms) +
......@@ -30558,7 +30586,7 @@ return __p
};
_converse.handleChatStateNotification = function (contact) {
/* Event handler for on('contactStatusChanged').
/* Event handler for on('contactPresenceChanged').
* Will show an HTML5 notification to indicate that the chat
* status has changed.
*/
......@@ -30609,7 +30637,7 @@ return __p
// handlers.
_converse.on('contactRequest', _converse.handleContactRequestNotification);
_converse.on('contactStatusChanged', _converse.handleChatStateNotification);
_converse.on('contactPresenceChanged', _converse.handleChatStateNotification);
_converse.on('message', _converse.handleMessageNotification);
......@@ -31338,18 +31366,8 @@ return __p
dependencies: ["converse-vcard"],
overrides: {
clearSession () {
this.__super__.clearSession.apply(this, arguments);
if (!_.isUndefined(this.roster)) {
this.roster.browserStorage._clear();
}
},
_tearDown () {
this.__super__._tearDown.apply(this, arguments);
if (this.roster) {
this.roster.off().reset(); // Removes roster contacts
}
}
},
......@@ -31384,10 +31402,10 @@ return __p
* roster and the roster groups.
*/
_converse.roster = new _converse.RosterContacts();
_converse.roster.browserStorage = new Backbone.BrowserStorage.session(
_converse.roster.browserStorage = new Backbone.BrowserStorage[_converse.storage](
b64_sha1(`converse.contacts-${_converse.bare_jid}`));
_converse.rostergroups = new _converse.RosterGroups();
_converse.rostergroups.browserStorage = new Backbone.BrowserStorage.session(
_converse.rostergroups.browserStorage = new Backbone.BrowserStorage[_converse.storage](
b64_sha1(`converse.roster.groups${_converse.bare_jid}`));
_converse.emit('rosterInitialized');
};
......@@ -31427,11 +31445,115 @@ return __p
};
_converse.RosterContact = Backbone.Model.extend({
_converse.Presence = Backbone.Model.extend({
defaults: {
'show': 'offline',
'resources': {}
},
getHighestPriorityResource () {
/* Return the resource with the highest priority.
*
* If multiple resources have the same priority, take the
* latest one.
*/
const resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
const val = _.flow(
_.values,
_.partial(_.sortBy, _, ['priority', 'timestamp']),
_.reverse
)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
},
addResource (presence) {
/* Adds a new resource and it's associated attributes as taken
* from the passed in presence stanza.
*
* Also updates the presence if the resource has higher priority (and is newer).
*/
const jid = presence.getAttribute('from'),
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
delay = presence.querySelector(
`delay[xmlns="${Strophe.NS.DELAY}"]`
),
timestamp = _.isNull(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'show': show,
'timestamp': timestamp
};
const changed = {'resources': resources};
const hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the "global" presence if this is the newest resource
// with the highest priority
changed.show = show;
}
this.save(changed);
return resources;
},
removeResource (resource) {
/* Remove the passed in resource from the resources map.
*
* Also redetermines the presence given that there's one less
* resource.
*/
let resources = this.get('resources');
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
}
this.save({
'resources': resources,
'show': _.propertyOf(
this.getHighestPriorityResource())('show') || 'offline'
});
},
});
_converse.Presences = Backbone.Collection.extend({
model: _converse.Presence,
});
_converse.ModelWithVCardAndPresence = Backbone.Model.extend({
initialize () {
this.setVCard();
this.setPresence();
},
setVCard () {
const jid = this.get('jid');
this.vcard = _converse.vcards.findWhere({'jid': jid}) || _converse.vcards.create({'jid': jid});
},
setPresence () {
const jid = this.get('jid');
this.presence = _converse.presences.findWhere({'jid': jid}) || _converse.presences.create({'jid': jid});
}
});
_converse.RosterContact = _converse.ModelWithVCardAndPresence.extend({
defaults: {
'chat_state': undefined,
'chat_status': 'offline',
'image': _converse.DEFAULT_IMAGE,
'image_type': _converse.DEFAULT_IMAGE_TYPE,
'num_unread': 0,
......@@ -31439,6 +31561,8 @@ return __p
},
initialize (attributes) {
_converse.ModelWithVCardAndPresence.prototype.initialize.apply(this, arguments);
const { jid } = attributes,
bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase(),
resource = Strophe.getResourceFromJid(jid);
......@@ -31448,18 +31572,11 @@ return __p
'groups': [],
'id': bare_jid,
'jid': bare_jid,
'resources': {},
'user_id': Strophe.getNodeFromJid(jid)
}, attributes));
this.vcard = _converse.vcards.findWhere({'jid': bare_jid});
if (_.isNil(this.vcard)) {
this.vcard = _converse.vcards.create({'jid': bare_jid});
}
this.on('change:chat_status', function (item) {
_converse.emit('contactStatusChanged', item.attributes);
});
this.presence.on('change:show', () => _converse.emit('contactPresenceChanged', this));
this.presence.on('change:show', () => this.trigger('presenceChanged'));
},
getDisplayName () {
......@@ -31538,80 +31655,6 @@ return __p
return this;
},
addResource (presence) {
/* Adds a new resource and it's associated attributes as taken
* from the passed in presence stanza.
*
* Also updates the contact's chat_status if the presence has
* higher priority (and is newer).
*/
const jid = presence.getAttribute('from'),
chat_status = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
delay = presence.querySelector(
`delay[xmlns="${Strophe.NS.DELAY}"]`
),
timestamp = _.isNull(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
let priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'status': chat_status,
'timestamp': timestamp
};
const changed = {'resources': resources};
const hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the chat status if this is the newest resource
// with the highest priority
changed.chat_status = chat_status;
}
this.save(changed);
return resources;
},
removeResource (resource) {
/* Remove the passed in resource from the contact's resources map.
*
* Also recomputes the chat_status given that there's one less
* resource.
*/
let resources = this.get('resources');
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
}
this.save({
'resources': resources,
'chat_status': _.propertyOf(
this.getHighestPriorityResource())('status') || 'offline'
});
},
getHighestPriorityResource () {
/* Return the resource with the highest priority.
*
* If multiple resources have the same priority, take the
* newest one.
*/
const resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
const val = _.flow(
_.values,
_.partial(_.sortBy, _, ['priority', 'timestamp']),
_.reverse
)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
},
removeFromRoster (callback, errback) {
/* Instruct the XMPP server to remove this contact from our roster
* Parameters:
......@@ -31630,8 +31673,8 @@ return __p
model: _converse.RosterContact,
comparator (contact1, contact2) {
const status1 = contact1.get('chat_status') || 'offline';
const status2 = contact2.get('chat_status') || 'offline';
const status1 = contact1.presence.get('show') || 'offline';
const status2 = contact2.presence.get('show') || 'offline';
if (_converse.STATUS_WEIGHTS[status1] === _converse.STATUS_WEIGHTS[status2]) {
const name1 = (contact1.getDisplayName()).toLowerCase();
const name2 = (contact2.getDisplayName()).toLowerCase();
......@@ -31682,12 +31725,12 @@ return __p
fetchRosterContacts () {
/* Fetches the roster contacts, first by trying the
* sessionStorage cache, and if that's empty, then by querying
* the XMPP server.
*
* Returns a promise which resolves once the contacts have been
* fetched.
*/
* sessionStorage cache, and if that's empty, then by querying
* the XMPP server.
*
* Returns a promise which resolves once the contacts have been
* fetched.
*/
return new Promise((resolve, reject) => {
this.fetch({
'add': true,
......@@ -31814,7 +31857,7 @@ return __p
if (_converse.show_only_online_users) {
ignored = _.union(ignored, ['dnd', 'xa', 'away']);
}
return _.sum(this.models.filter((model) => !_.includes(ignored, model.get('chat_status'))));
return _.sum(this.models.filter((model) => !_.includes(ignored, model.presence.get('show'))));
},
onRosterPush (iq) {
......@@ -31962,7 +32005,6 @@ return __p
const jid = presence.getAttribute('from'),
bare_jid = Strophe.getBareJidFromJid(jid),
resource = Strophe.getResourceFromJid(jid),
chat_status = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
status_message = _.propertyOf(presence.querySelector('status'))('textContent'),
contact = this.get(bare_jid);
......@@ -31974,7 +32016,8 @@ return __p
// Another resource has changed its status and
// synchronize_availability option set to update,
// we'll update ours as well.
_converse.xmppstatus.save({'status': chat_status});
const show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online';
_converse.xmppstatus.save({'status': show});
if (status_message) {
_converse.xmppstatus.save({'status_message': status_message});
}
......@@ -32012,10 +32055,10 @@ return __p
} else if (presence_type === 'subscribe') {
this.handleIncomingSubscription(presence);
} else if (presence_type === 'unavailable' && contact) {
contact.removeResource(resource);
contact.presence.removeResource(resource);
} else if (contact) {
// presence_type is undefined
contact.addResource(presence);
contact.presence.addResource(presence);
}
}
});
......@@ -32054,9 +32097,37 @@ return __p
}
});
_converse.unregisterPresenceHandler = function () {
if (!_.isUndefined(_converse.presence_ref)) {
_converse.connection.deleteHandler(_converse.presence_ref);
delete _converse.presence_ref;
}
};
/********** Event Handlers *************/
_converse.api.listen.on('beforeTearDown', _converse.unregisterPresenceHandler());
_converse.api.listen.on('afterTearDown', () => {
if (_converse.presence) {
_converse.presences.off().reset(); // Remove presences
}
});
_converse.api.listen.on('clearSession', () => {
if (!_.isUndefined(this.roster)) {
this.roster.browserStorage._clear();
}
});
_converse.api.listen.on('connectionInitialized', () => {
_converse.presences = new _converse.Presences();
_converse.presences.browserStorage =
new Backbone.BrowserStorage.session(b64_sha1(`converse.presences-${_converse.bare_jid}`));
_converse.presences.fetch();
});
_converse.api.listen.on('statusInitialized', (reconnecting) => {
if (reconnecting) {
// No need to recreate the roster, otherwise we lose our
......@@ -32908,7 +32979,7 @@ return __p
define('tpl!rooms_list', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="rooms-toggle open-rooms-toggle" title="' +
__p += '<a href="#" class="rooms-toggle open-rooms-toggle controlbox-padded" title="' +
__e(o.desc_rooms) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -32926,7 +32997,7 @@ return __p
define('tpl!rooms_list_item', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="list-item available-chatroom d-flex flex-row ';
__p += '<div class="list-item controlbox-padded available-chatroom d-flex flex-row ';
if (o.num_unread_general) { ;
__p += ' unread-msgs ';
} ;
......@@ -33162,7 +33233,7 @@ return __p
insertIntoControlBox: function insertIntoControlBox() {
var controlboxview = _converse.chatboxviews.get('controlbox');
if (!_.isUndefined(controlboxview) && !_converse.root.contains(this.el)) {
if (!_.isUndefined(controlboxview) && !u.rootContains(_converse.root, this.el)) {
var el = controlboxview.el.querySelector('.open-rooms-list');
if (!_.isNull(el)) {
......@@ -42396,6 +42396,15 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
};
};
u.rootContains = function (root, el) {
// The document element does not have the contains method in IE.
if (root === document && !root.contains) {
return document.head.contains(el) || document.body.contains(el);
}
return root.contains ? root.contains(el) : window.HTMLElement.prototype.contains.call(root, el);
};
u.createFragmentFromText = function (markup) {
/* Returns a DocumentFragment containing DOM nodes based on the
* passed-in markup text.
......@@ -43543,6 +43552,10 @@ return Backbone.BrowserStorage;
_converse.chatboxviews.closeAllChatBoxes();
if (_converse.bookmarks) {
_converse.bookmarks.reset();
}
delete _converse.controlboxtoggle;
delete _converse.chatboxviews;
......@@ -43619,7 +43632,6 @@ return Backbone.BrowserStorage;
locales_url: 'locale/{{{locale}}}/LC_MESSAGES/converse.json',
locales: ['af', 'ar', 'bg', 'ca', 'de', 'es', 'eu', 'en', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'nb', 'nl', 'pl', 'pt_BR', 'ru', 'tr', 'uk', 'zh_CN', 'zh_TW'],
message_carbons: true,
message_storage: 'session',
nickname: undefined,
password: undefined,
prebind_url: null,
......@@ -43633,6 +43645,7 @@ return Backbone.BrowserStorage;
storage: 'session',
strict_plugin_dependencies: false,
synchronize_availability: true,
trusted: true,
view_mode: 'overlayed',
// Choices are 'overlayed', 'fullscreen', 'mobile'
websocket_url: undefined,
......@@ -43992,9 +44005,14 @@ return Backbone.BrowserStorage;
};
this.clearSession = function () {
if (!_.isUndefined(this.session) && this.session.browserStorage) {
if (!_converse.trusted) {
window.localStorage.clear();
window.sessionStorage.clear();
} else if (!_.isUndefined(this.session) && this.session.browserStorage) {
this.session.browserStorage._clear();
}
_converse.emit('clearSession');
};
this.logOut = function () {
......@@ -44106,14 +44124,6 @@ return Backbone.BrowserStorage;
this.connection.send(carbons_iq);
};
this.unregisterPresenceHandler = function () {
if (!_.isUndefined(_converse.presence_ref)) {
_converse.connection.deleteHandler(_converse.presence_ref);
delete _converse.presence_ref;
}
};
this.sendInitialPresence = function () {
if (_converse.send_initial_presence) {
_converse.xmppstatus.sendPresence();
......@@ -44373,7 +44383,7 @@ return Backbone.BrowserStorage;
} else if (!this.jid) {
throw new Error("attemptNonPreboundSession: If you use auto_login, " + "you also need to give either a jid value (and if " + "applicable a password) or you need to pass in a URL " + "from where the username and password can be fetched " + "(via credentials_url).");
} else {
this.autoLogin(); // Probably ANONYMOUS login
this.autoLogin(); // Could be ANONYMOUS or EXTERNAL
}
} else if (reconnecting) {
this.autoLogin();
......@@ -44387,7 +44397,7 @@ return Backbone.BrowserStorage;
this.jid = credentials.jid;
}
if (this.authentication === _converse.ANONYMOUS) {
if (this.authentication === _converse.ANONYMOUS || this.authentication === _converse.EXTERNAL) {
if (!this.jid) {
throw new Error("Config Error: when using anonymous login " + "you need to provide the server's domain via the 'jid' option. " + "Either when calling converse.initialize, or when calling " + "_converse.api.user.login.");
}
......@@ -44466,8 +44476,6 @@ return Backbone.BrowserStorage;
*/
_converse.emit('beforeTearDown');
_converse.unregisterPresenceHandler();
if (!_.isUndefined(_converse.session)) {
_converse.session.destroy();
}
......@@ -46124,8 +46132,8 @@ define("emojione", (function (global) {
throw new TypeError('disco.supports: You need to provide an entity JID');
}
return _converse.api.waitUntil('discoInitialized').then(function () {
return new Promise(function (resolve, reject) {
return new Promise(function (resolve, reject) {
return _converse.api.waitUntil('discoInitialized').then(function () {
_converse.api.disco.entities.get(entity_jid, true).then(function (entity) {
entity.waitUntilFeaturesDiscovered.then(function () {
var promises = _.concat(entity.items.map(function (item) {
......@@ -46136,8 +46144,8 @@ define("emojione", (function (global) {
resolve(f.filter(f.isObject, result));
}).catch(reject);
}).catch(reject);
});
});
}).catch(reject);
}).catch(reject);
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
},
'getIdentity': function getIdentity(category, type, entity_jid) {
......@@ -48994,7 +49002,7 @@ return __p
define('tpl!bookmark', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="list-item room-item available-chatroom d-flex flex-row ';
__p += '<div class="list-item controlbox-padded room-item available-chatroom d-flex flex-row ';
if (o.hidden) { ;
__p += ' hidden ';
} ;
......@@ -49028,7 +49036,7 @@ return __p
define('tpl!bookmarks_list', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="rooms-toggle bookmarks-toggle" title="' +
__p += '<a href="#" class="rooms-toggle bookmarks-toggle controlbox-padded" title="' +
__e(o.desc_bookmarks) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -49088,17 +49096,6 @@ return __p
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
clearSession: function clearSession() {
this.__super__.clearSession.apply(this, arguments);
if (!_.isUndefined(this.bookmarks)) {
this.bookmarks.reset();
this.bookmarks.browserStorage._clear();
window.sessionStorage.removeItem(this.bookmarks.fetched_flag);
}
},
ChatRoomView: {
events: {
'click .toggle-bookmark': 'toggleBookmark'
......@@ -49525,7 +49522,7 @@ return __p
insertIntoControlBox: function insertIntoControlBox() {
var controlboxview = _converse.chatboxviews.get('controlbox');
if (!_.isUndefined(controlboxview) && !_converse.root.contains(this.el)) {
if (!_.isUndefined(controlboxview) && !u.rootContains(_converse.root, this.el)) {
var el = controlboxview.el.querySelector('.bookmarks-list');
if (!_.isNull(el)) {
......@@ -49635,6 +49632,14 @@ return __p
'event': 'roomsPanelRendered'
}], initBookmarks);
_converse.on('clearSession', function () {
if (!_.isUndefined(_converse.bookmarks)) {
_converse.bookmarks.browserStorage._clear();
window.sessionStorage.removeItem(_converse.bookmarks.fetched_flag);
}
});
_converse.on('reconnected', initBookmarks);
_converse.on('connected', function () {
......@@ -54013,7 +54018,7 @@ return __p
model: _converse.Message,
comparator: 'time'
});
_converse.ChatBox = Backbone.Model.extend({
_converse.ChatBox = _converse.ModelWithVCardAndPresence.extend({
defaults: {
'bookmarked': false,
'chat_state': undefined,
......@@ -54025,15 +54030,7 @@ return __p
initialize: function initialize() {
var _this4 = this;
this.vcard = _converse.vcards.findWhere({
'jid': this.get('jid')
});
if (_.isNil(this.vcard)) {
this.vcard = _converse.vcards.create({
'jid': this.get('jid')
});
}
_converse.ModelWithVCardAndPresence.prototype.initialize.apply(this, arguments);
_converse.api.waitUntil('rosterContactsFetched').then(function () {
_this4.addRelatedContact(_converse.roster.findWhere({
......@@ -54042,7 +54039,7 @@ return __p
});
this.messages = new _converse.Messages();
this.messages.browserStorage = new Backbone.BrowserStorage[_converse.message_storage](b64_sha1("converse.messages".concat(this.get('jid')).concat(_converse.bare_jid)));
this.messages.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.messages".concat(this.get('jid')).concat(_converse.bare_jid)));
this.messages.chatbox = this;
this.messages.on('change:upload', function (message) {
if (message.get('upload') === _converse.SUCCESS) {
......@@ -55312,9 +55309,8 @@ return __p
this.model.messages.on('add', this.onMessageAdded, this);
this.model.messages.on('rendered', this.scrollDown, this);
this.model.on('show', this.show, this);
this.model.on('destroy', this.remove, this); // TODO check for changed fullname as well
this.model.on('change:chat_status', this.onChatStatusChanged, this);
this.model.on('destroy', this.remove, this);
this.model.presence.on('change:show', this.onPresenceChanged, this);
this.model.on('showHelpMessages', this.showHelpMessages, this);
this.render();
this.fetchMessages();
......@@ -55414,7 +55410,7 @@ return __p
}
var contact_jid = this.model.get('jid');
var resources = this.model.get('resources');
var resources = this.model.presence.get('resources');
if (_.isEmpty(resources)) {
return;
......@@ -55423,7 +55419,7 @@ return __p
Promise.all(_.map(_.keys(resources), function (resource) {
return _converse.api.disco.supports(Strophe.NS.SPOILER, "".concat(contact_jid, "/").concat(resource));
})).then(function (results) {
if (results.length) {
if (_.filter(results, 'length').length) {
var html = tpl_spoiler_button(_this4.model.toJSON());
if (_converse.visible_toolbar_buttons.emoji) {
......@@ -55838,7 +55834,11 @@ return __p
}
textarea.value = '';
textarea.focus();
textarea.focus(); // Trigger input event, so that the textarea resizes
var event = document.createEvent('Event');
event.initEvent('input', true, true);
textarea.dispatchEvent(event);
if (message !== '') {
this.onMessageSubmitted(message, spoiler_hint);
......@@ -55951,20 +55951,19 @@ return __p
toggle_el.setAttribute("data-toggle-state", "closed");
}
},
onChatStatusChanged: function onChatStatusChanged(item) {
var chat_status = item.get('chat_status');
var fullname = item.get('fullname');
onPresenceChanged: function onPresenceChanged(item) {
var show = item.get('show'),
fullname = this.model.getDisplayName();
var text;
fullname = _.isEmpty(fullname) ? item.get('jid') : fullname;
if (u.isVisible(this.el)) {
if (chat_status === 'offline') {
if (show === 'offline') {
text = fullname + ' ' + __('has gone offline');
} else if (chat_status === 'away') {
} else if (show === 'away') {
text = fullname + ' ' + __('has gone away');
} else if (chat_status === 'dnd') {
} else if (show === 'dnd') {
text = fullname + ' ' + __('is busy');
} else if (chat_status === 'online') {
} else if (show === 'online') {
text = fullname + ' ' + __('is online');
}
......@@ -56185,7 +56184,7 @@ return __p
define('tpl!login_panel', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div id="converse-login-panel" class="controlbox-pane fade-in row">\n <form id="converse-login" class="converse-form" method="post">\n <div class="conn-feedback fade-in ';
__p += '<div id="converse-login-panel" class="controlbox-pane fade-in row no-gutters">\n <form id="converse-login" class="converse-form" method="post">\n <div class="conn-feedback fade-in ';
if (!o.conn_feedback_subject) { ;
__p += ' hidden ';
} ;
......@@ -56205,20 +56204,28 @@ __p += '\n <span class="spinner fa fa-spinner centered"/>\n ';
} else { ;
__p += '\n ';
if (o.authentication == o.LOGIN || o.authentication == o.EXTERNAL) { ;
__p += '\n <div class="form-group">\n <label for="jid">' +
__p += '\n <div class="form-group">\n <label for="converse-login-jid">' +
__e(o.__("XMPP Username:")) +
'</label>\n <input class="form-control" autofocus required="required" type="text" name="jid" placeholder="' +
'</label>\n <input id="converse-login-jid" class="form-control" autofocus required="required" type="text" name="jid" placeholder="' +
__e(o.placeholder_username) +
'">\n </div>\n ';
if (o.authentication !== o.EXTERNAL) { ;
__p += '\n <div class="form-group">\n <label for="password">' +
__p += '\n <div class="form-group">\n <label for="converse-login-password">' +
__e(o.__("Password:")) +
'</label>\n <input class="form-control" required="required" type="password" name="password" placeholder="' +
'</label>\n <input id="converse-login-password" class="form-control" required="required" type="password" name="password" placeholder="' +
__e(o.__('password')) +
'">\n </div>\n ';
} ;
__p += '\n <fieldset class="buttons">\n <input class="btn btn-primary" type="submit" value="' +
__e(o.__('Submit')) +
__p += '\n <div class="form-group form-check">\n <input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ';
if (o._converse.trusted) { ;
__p += ' checked="checked" ';
} ;
__p += '>\n <label for="converse-login-trusted" class="form-check-label">' +
__e(o.__('This is a trusted device')) +
'</label>\n <i class="fa fa-info-circle" data-toggle="popover"\n data-title="Trusted device?"\n data-content="' +
__e(o.__('To improve performance, we cache your data in this browser. Uncheck this box if this is a public computer or if you want your data to be deleted when you log out. It\'s important that you explicitly log out, otherwise not all cached data might be deleted.')) +
'"></i>\n </div>\n\n <fieldset class="buttons">\n <input class="btn btn-primary" type="submit" value="' +
__e(o.__('Log in')) +
'">\n </fieldset>\n ';
} ;
__p += '\n ';
......@@ -56283,7 +56290,7 @@ return __p
define('tpl!group_header', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="group-toggle" title="' +
__p += '<a href="#" class="group-toggle controlbox-padded" title="' +
__e(o.desc_group_toggle) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -56354,7 +56361,7 @@ return __p
define('tpl!roster', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape;
__p += '<div class="d-flex">\n <span class="w-100 controlbox-heading">' +
__p += '<div class="d-flex controlbox-padded">\n <span class="w-100 controlbox-heading">' +
__e(o.heading_contacts) +
'</span>\n <a class="chatbox-btn add-contact fa fa-user-plus" title="' +
__e(o.title_add_contact) +
......@@ -56366,7 +56373,7 @@ return __p
define('tpl!roster_filter', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<form class="roster-filter-form input-button-group ';
__p += '<form class="controlbox-padded roster-filter-form input-button-group ';
if (!o.visible) { ;
__p += ' hidden ';
} ;
......@@ -57204,7 +57211,7 @@ define("awesomplete", (function (global) {
};
name_input.addEventListener('input', _.debounce(function () {
xhr.open("GET", "".concat(_converse.xhr_user_search_url, "?q=").concat(name_input.value), true);
xhr.open("GET", "".concat(_converse.xhr_user_search_url, "q=").concat(name_input.value), true);
xhr.send();
}, 300));
this.el.addEventListener('awesomplete-selectcomplete', function (ev) {
......@@ -57372,7 +57379,7 @@ define("awesomplete", (function (global) {
});
_converse.RosterContactView = Backbone.NativeView.extend({
tagName: 'li',
className: 'd-flex hidden',
className: 'd-flex hidden controlbox-padded',
events: {
"click .accept-xmpp-request": "acceptRequest",
"click .decline-xmpp-request": "declineRequest",
......@@ -57384,6 +57391,7 @@ define("awesomplete", (function (global) {
this.model.on("destroy", this.remove, this);
this.model.on("open", this.openChat, this);
this.model.on("remove", this.remove, this);
this.model.presence.on("change:show", this.render, this);
this.model.vcard.on('change:fullname', this.render, this);
},
render: function render() {
......@@ -57396,7 +57404,7 @@ define("awesomplete", (function (global) {
var item = this.model,
ask = item.get('ask'),
chat_status = item.get('chat_status'),
show = item.presence.get('show'),
requesting = item.get('requesting'),
subscription = item.get('subscription');
var classes_to_remove = ['current-xmpp-contact', 'pending-xmpp-contact', 'requesting-xmpp-contact'].concat(_.keys(STATUSES));
......@@ -57407,8 +57415,8 @@ define("awesomplete", (function (global) {
}
});
this.el.classList.add(chat_status);
this.el.setAttribute('data-status', chat_status);
this.el.classList.add(show);
this.el.setAttribute('data-status', show);
if (ask === 'subscribe' || subscription === 'from') {
/* ask === 'subscribe'
......@@ -57450,22 +57458,22 @@ define("awesomplete", (function (global) {
},
renderRosterItem: function renderRosterItem(item) {
var status_icon = 'fa-times-circle';
var chat_status = item.get('chat_status') || 'offline';
var show = item.presence.get('show') || 'offline';
if (chat_status === 'online') {
if (show === 'online') {
status_icon = 'fa-circle';
} else if (chat_status === 'away') {
} else if (show === 'away') {
status_icon = 'fa-dot-circle-o';
} else if (chat_status === 'xa') {
} else if (show === 'xa') {
status_icon = 'fa-circle-o';
} else if (chat_status === 'dnd') {
} else if (show === 'dnd') {
status_icon = 'fa-minus-circle';
}
var display_name = item.getDisplayName();
this.el.innerHTML = tpl_roster_item(_.extend(item.toJSON(), {
'display_name': display_name,
'desc_status': STATUSES[chat_status],
'desc_status': STATUSES[show],
'status_icon': status_icon,
'desc_chat': __('Click to chat with %1$s (JID: %2$s)', display_name, item.get('jid')),
'desc_remove': __('Click to remove %1$s as a contact', display_name),
......@@ -57481,7 +57489,7 @@ define("awesomplete", (function (global) {
* It doesn't check for the more specific case of whether
* the group it's in is collapsed.
*/
var chatStatus = this.model.get('chat_status');
var chatStatus = this.model.presence.get('show');
if (_converse.show_only_online_users && chatStatus !== 'online' || _converse.hide_offline_users && chatStatus === 'offline') {
// If pending or requesting, show
......@@ -57562,7 +57570,7 @@ define("awesomplete", (function (global) {
ItemView: _converse.RosterContactView,
listItems: 'model.contacts',
listSelector: '.roster-group-contacts',
sortEvent: 'change:chat_status',
sortEvent: 'presenceChanged',
initialize: function initialize() {
Backbone.OrderedListView.prototype.initialize.apply(this, arguments);
this.model.contacts.on("change:subscription", this.onContactSubscriptionChange, this);
......@@ -57652,14 +57660,16 @@ define("awesomplete", (function (global) {
// show requesting contacts, even though they don't
// have the state in question.
matches = this.model.contacts.filter(function (contact) {
return u.contains.not('chat_status', q)(contact) && !contact.get('requesting');
return !_.includes(contact.presence.get('show'), q) && !contact.get('requesting');
});
} else if (q === 'unread_messages') {
matches = this.model.contacts.filter({
'num_unread': 0
});
} else {
matches = this.model.contacts.filter(u.contains.not('chat_status', q));
matches = this.model.contacts.filter(function (contact) {
return !_.includes(contact.presence.get('show'), q);
});
}
} else {
matches = this.model.contacts.filter(function (contact) {
......@@ -57780,6 +57790,12 @@ define("awesomplete", (function (global) {
_converse.roster.on("remove", this.update, this);
_converse.presences.on('change:show', function () {
_this5.update();
_this5.updateFilter();
});
this.model.on("reset", this.reset, this); // This event gets triggered once *all* contacts (i.e. not
// just this group's) have been fetched from browser
// storage or the XMPP server and once they've been
......@@ -57891,11 +57907,13 @@ define("awesomplete", (function (global) {
return this;
},
onContactAdded: function onContactAdded(contact) {
this.addRosterContact(contact).update();
this.addRosterContact(contact);
this.update();
this.updateFilter();
},
onContactChange: function onContactChange(contact) {
this.updateChatBox(contact).update();
this.updateChatBox(contact);
this.update();
if (_.has(contact.changed, 'subscription')) {
if (contact.changed.subscription === 'from') {
......@@ -57923,10 +57941,6 @@ define("awesomplete", (function (global) {
return this;
}
if (_.has(contact.changed, 'chat_status')) {
changes.chat_status = contact.get('chat_status');
}
if (_.has(contact.changed, 'status')) {
changes.status = contact.get('status');
}
......@@ -58191,7 +58205,7 @@ return __p
define('tpl!profile_view', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="userinfo">\n<div class="profile d-flex">\n <a class="show-profile" href="#">\n <img alt="User Avatar" class="avatar align-self-center" height="40px" width="40px" src="data:' +
__p += '<div class="userinfo controlbox-padded">\n<div class="profile d-flex">\n <a class="show-profile" href="#">\n <img alt="User Avatar" class="avatar align-self-center" height="40px" width="40px" src="data:' +
__e(o.image_type) +
';base64,' +
__e(o.image) +
......@@ -60793,7 +60807,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
if (result.image) {
var word_array_from_b64 = CryptoJS.enc.Base64.parse(result['image']);
result['image_type'] = CryptoJS.SHA1(word_array_from_b64).toString();
result['image_hash'] = CryptoJS.SHA1(word_array_from_b64).toString();
}
if (callback) {
......@@ -60854,7 +60868,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
_converse.initVCardCollection = function () {
_converse.vcards = new _converse.VCards();
_converse.vcards.browserStorage = new Backbone.BrowserStorage.local(b64_sha1("converse.vcards"));
_converse.vcards.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.vcards"));
_converse.vcards.fetch();
};
......@@ -61146,8 +61160,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
/*global define */
(function (root, factory) {
define('converse-controlbox',["converse-core", "lodash.fp", "tpl!converse_brand_heading", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
})(this, function (converse, fp, tpl_brand_heading, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel) {
define('converse-controlbox',["converse-core", "bootstrap", "lodash.fp", "tpl!converse_brand_heading", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
})(this, function (converse, bootstrap, fp, tpl_brand_heading, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel) {
"use strict";
var CHATBOX_TYPE = 'chatbox';
......@@ -61223,21 +61237,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
this.rosterview.removeAll().remove();
}
},
clearSession: function clearSession() {
this.__super__.clearSession.apply(this, arguments);
var chatboxes = _.get(this, 'chatboxes', null);
if (!_.isNil(chatboxes)) {
var controlbox = chatboxes.get('controlbox');
if (controlbox && controlbox.collection && controlbox.collection.browserStorage) {
controlbox.save({
'connected': false
});
}
}
},
ChatBoxes: {
chatBoxMayBeShown: function chatBoxMayBeShown(chatbox) {
return this.__super__.chatBoxMayBeShown.apply(this, arguments) && chatbox.get('id') !== 'controlbox';
......@@ -61540,6 +61539,15 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
initialize: function initialize(cfg) {
this.model.on('change', this.render, this);
this.listenTo(_converse.connfeedback, 'change', this.render);
this.render();
_.forEach(this.el.querySelectorAll('[data-title]'), function (el) {
var popover = new bootstrap.Popover(el, {
'trigger': _converse.view_mode === 'mobile' && 'click' || 'hover',
'dismissible': _converse.view_mode === 'mobile' && true || false,
'container': _converse.chatboxviews.el
});
});
},
toHTML: function toHTML() {
var connection_status = _converse.connfeedback.get('connection_status');
......@@ -61595,7 +61603,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
return;
}
var jid = ev.target.querySelector('input[name=jid]').value;
var form_data = new FormData(ev.target);
_converse.trusted = form_data.get('trusted');
_converse.storage = form_data.get('trusted') ? 'local' : 'session';
var jid = form_data.get('jid');
if (_converse.locked_domain) {
jid = Strophe.escapeNode(jid) + '@' + _converse.locked_domain;
......@@ -61603,7 +61614,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
jid = jid + '@' + _converse.default_domain;
}
this.connect(jid, _.get(ev.target.querySelector('input[name=password]'), 'value'));
this.connect(jid, form_data.get('password'));
},
connect: function connect(jid, password) {
if (jid) {
......@@ -61702,6 +61713,23 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
}
}
});
_converse.on('clearSession', function () {
if (_converse.trusted) {
var chatboxes = _.get(_converse, 'chatboxes', null);
if (!_.isNil(chatboxes)) {
var controlbox = chatboxes.get('controlbox');
if (controlbox && controlbox.collection && controlbox.collection.browserStorage) {
controlbox.save({
'connected': false
});
}
}
}
});
Promise.all([_converse.api.waitUntil('connectionInitialized'), _converse.api.waitUntil('chatBoxesInitialized')]).then(_converse.addControlBox).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
_converse.on('chatBoxesFetched', function () {
......@@ -62164,7 +62192,7 @@ return __p
define('tpl!inverse_brand_heading', ['lodash'], function(_) {return function(o) {
var __t, __p = '';
__p += '<div class="row">\n <div class="container brand-heading-container">\n <h1 class="brand-heading"><i class="icon-conversejs"></i>Converse</h1>\n <p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://conversejs.org">Open Source</a> XMPP chat client</p>\n <p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages">Translate</a> into your own language</p>\n <div>\n</div>\n';
__p += '<div class="row">\n <div class="container brand-heading-container">\n <h1 class="brand-heading"><i class="icon-conversejs"></i>Converse</h1>\n <p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://conversejs.org">Open Source</a> XMPP chat client brought to you by <a target="_blank" rel="nofollow" href="https://opkode.com">Opkode</a> </p>\n <p class="brand-subtitle"><a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages">Translate</a> it into your own language</p>\n <div>\n</div>\n';
return __p
};});
......@@ -63853,7 +63881,7 @@ return __p
define('tpl!chatroom_head', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="col col-9">\n <div class="chat-title" title="' +
__p += '<div class="col col-8">\n <div class="chat-title" title="' +
__e(o.jid) +
'">\n ';
if (o.name && o.name !== o.Strophe.getNodeFromJid(o.jid)) { ;
......@@ -64171,7 +64199,7 @@ return __p
define('tpl!room_panel', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape;
__p += '<!-- <div id="chatrooms"> -->\n<div class="d-flex">\n <span class="w-100 controlbox-heading">' +
__p += '<!-- <div id="chatrooms"> -->\n<div class="d-flex controlbox-padded">\n <span class="w-100 controlbox-heading">' +
__e(o.heading_chatrooms) +
'</span>\n <a class="chatbox-btn trigger-list-chatrooms-modal fa fa-list-ul" title="' +
__e(o.title_list_rooms) +
......@@ -66269,7 +66297,7 @@ return __p
};
_converse.handleChatStateNotification = function (contact) {
/* Event handler for on('contactStatusChanged').
/* Event handler for on('contactPresenceChanged').
* Will show an HTML5 notification to indicate that the chat
* status has changed.
*/
......@@ -66320,7 +66348,7 @@ return __p
// handlers.
_converse.on('contactRequest', _converse.handleContactRequestNotification);
_converse.on('contactStatusChanged', _converse.handleChatStateNotification);
_converse.on('contactPresenceChanged', _converse.handleChatStateNotification);
_converse.on('message', _converse.handleMessageNotification);
......@@ -71952,22 +71980,13 @@ return __p
converse.plugins.add('converse-roster', {
dependencies: ["converse-vcard"],
overrides: {
clearSession: function clearSession() {
this.__super__.clearSession.apply(this, arguments);
if (!_.isUndefined(this.roster)) {
this.roster.browserStorage._clear();
}
},
_tearDown: function _tearDown() {
this.__super__._tearDown.apply(this, arguments);
if (this.roster) {
this.roster.off().reset(); // Removes roster contacts
}
}
},
initialize: function initialize() {
var _this6 = this;
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
......@@ -71991,9 +72010,9 @@ return __p
* roster and the roster groups.
*/
_converse.roster = new _converse.RosterContacts();
_converse.roster.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.contacts-".concat(_converse.bare_jid)));
_converse.roster.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.contacts-".concat(_converse.bare_jid)));
_converse.rostergroups = new _converse.RosterGroups();
_converse.rostergroups.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.roster.groups".concat(_converse.bare_jid)));
_converse.rostergroups.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.roster.groups".concat(_converse.bare_jid)));
_converse.emit('rosterInitialized');
};
......@@ -72038,16 +72057,119 @@ return __p
}
};
_converse.RosterContact = Backbone.Model.extend({
_converse.Presence = Backbone.Model.extend({
defaults: {
'show': 'offline',
'resources': {}
},
getHighestPriorityResource: function getHighestPriorityResource() {
/* Return the resource with the highest priority.
*
* If multiple resources have the same priority, take the
* latest one.
*/
var resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
var val = _.flow(_.values, _.partial(_.sortBy, _, ['priority', 'timestamp']), _.reverse)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
},
addResource: function addResource(presence) {
/* Adds a new resource and it's associated attributes as taken
* from the passed in presence stanza.
*
* Also updates the presence if the resource has higher priority (and is newer).
*/
var jid = presence.getAttribute('from'),
show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
delay = presence.querySelector("delay[xmlns=\"".concat(Strophe.NS.DELAY, "\"]")),
timestamp = _.isNull(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
var priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
var resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'show': show,
'timestamp': timestamp
};
var changed = {
'resources': resources
};
var hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the "global" presence if this is the newest resource
// with the highest priority
changed.show = show;
}
this.save(changed);
return resources;
},
removeResource: function removeResource(resource) {
/* Remove the passed in resource from the resources map.
*
* Also redetermines the presence given that there's one less
* resource.
*/
var resources = this.get('resources');
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
}
this.save({
'resources': resources,
'show': _.propertyOf(this.getHighestPriorityResource())('show') || 'offline'
});
}
});
_converse.Presences = Backbone.Collection.extend({
model: _converse.Presence
});
_converse.ModelWithVCardAndPresence = Backbone.Model.extend({
initialize: function initialize() {
this.setVCard();
this.setPresence();
},
setVCard: function setVCard() {
var jid = this.get('jid');
this.vcard = _converse.vcards.findWhere({
'jid': jid
}) || _converse.vcards.create({
'jid': jid
});
},
setPresence: function setPresence() {
var jid = this.get('jid');
this.presence = _converse.presences.findWhere({
'jid': jid
}) || _converse.presences.create({
'jid': jid
});
}
});
_converse.RosterContact = _converse.ModelWithVCardAndPresence.extend({
defaults: {
'chat_state': undefined,
'chat_status': 'offline',
'image': _converse.DEFAULT_IMAGE,
'image_type': _converse.DEFAULT_IMAGE_TYPE,
'num_unread': 0,
'status': ''
},
initialize: function initialize(attributes) {
var _this = this;
_converse.ModelWithVCardAndPresence.prototype.initialize.apply(this, arguments);
var jid = attributes.jid,
bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase(),
resource = Strophe.getResourceFromJid(jid);
......@@ -72056,21 +72178,13 @@ return __p
'groups': [],
'id': bare_jid,
'jid': bare_jid,
'resources': {},
'user_id': Strophe.getNodeFromJid(jid)
}, attributes));
this.vcard = _converse.vcards.findWhere({
'jid': bare_jid
this.presence.on('change:show', function () {
return _converse.emit('contactPresenceChanged', _this);
});
if (_.isNil(this.vcard)) {
this.vcard = _converse.vcards.create({
'jid': bare_jid
});
}
this.on('change:chat_status', function (item) {
_converse.emit('contactStatusChanged', item.attributes);
this.presence.on('change:show', function () {
return _this.trigger('presenceChanged');
});
},
getDisplayName: function getDisplayName() {
......@@ -72164,76 +72278,6 @@ return __p
return this;
},
addResource: function addResource(presence) {
/* Adds a new resource and it's associated attributes as taken
* from the passed in presence stanza.
*
* Also updates the contact's chat_status if the presence has
* higher priority (and is newer).
*/
var jid = presence.getAttribute('from'),
chat_status = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
resource = Strophe.getResourceFromJid(jid),
delay = presence.querySelector("delay[xmlns=\"".concat(Strophe.NS.DELAY, "\"]")),
timestamp = _.isNull(delay) ? moment().format() : moment(delay.getAttribute('stamp')).format();
var priority = _.propertyOf(presence.querySelector('priority'))('textContent') || 0;
priority = _.isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10);
var resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
'name': resource,
'priority': priority,
'status': chat_status,
'timestamp': timestamp
};
var changed = {
'resources': resources
};
var hpr = this.getHighestPriorityResource();
if (priority == hpr.priority && timestamp == hpr.timestamp) {
// Only set the chat status if this is the newest resource
// with the highest priority
changed.chat_status = chat_status;
}
this.save(changed);
return resources;
},
removeResource: function removeResource(resource) {
/* Remove the passed in resource from the contact's resources map.
*
* Also recomputes the chat_status given that there's one less
* resource.
*/
var resources = this.get('resources');
if (!_.isObject(resources)) {
resources = {};
} else {
delete resources[resource];
}
this.save({
'resources': resources,
'chat_status': _.propertyOf(this.getHighestPriorityResource())('status') || 'offline'
});
},
getHighestPriorityResource: function getHighestPriorityResource() {
/* Return the resource with the highest priority.
*
* If multiple resources have the same priority, take the
* newest one.
*/
var resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) {
var val = _.flow(_.values, _.partial(_.sortBy, _, ['priority', 'timestamp']), _.reverse)(resources)[0];
if (!_.isUndefined(val)) {
return val;
}
}
},
removeFromRoster: function removeFromRoster(callback, errback) {
/* Instruct the XMPP server to remove this contact from our roster
* Parameters:
......@@ -72256,8 +72300,8 @@ return __p
_converse.RosterContacts = Backbone.Collection.extend({
model: _converse.RosterContact,
comparator: function comparator(contact1, contact2) {
var status1 = contact1.get('chat_status') || 'offline';
var status2 = contact2.get('chat_status') || 'offline';
var status1 = contact1.presence.get('show') || 'offline';
var status2 = contact2.presence.get('show') || 'offline';
if (_converse.STATUS_WEIGHTS[status1] === _converse.STATUS_WEIGHTS[status2]) {
var name1 = contact1.getDisplayName().toLowerCase();
......@@ -72299,17 +72343,17 @@ return __p
}, Strophe.NS.ROSTERX, 'message', null);
},
fetchRosterContacts: function fetchRosterContacts() {
var _this = this;
var _this2 = this;
/* Fetches the roster contacts, first by trying the
* sessionStorage cache, and if that's empty, then by querying
* the XMPP server.
*
* Returns a promise which resolves once the contacts have been
* fetched.
*/
* sessionStorage cache, and if that's empty, then by querying
* the XMPP server.
*
* Returns a promise which resolves once the contacts have been
* fetched.
*/
return new Promise(function (resolve, reject) {
_this.fetch({
_this2.fetch({
'add': true,
'silent': true,
success: function success(collection) {
......@@ -72384,7 +72428,7 @@ return __p
_converse.connection.sendIQ(iq, callback, errback);
},
addContactToRoster: function addContactToRoster(jid, name, groups, attributes) {
var _this2 = this;
var _this3 = this;
/* Adds a RosterContact instance to _converse.roster and
* registers the contact on the XMPP server.
......@@ -72400,8 +72444,8 @@ return __p
return new Promise(function (resolve, reject) {
groups = groups || [];
_this2.sendContactAddIQ(jid, name, groups, function () {
var contact = _this2.create(_.assignIn({
_this3.sendContactAddIQ(jid, name, groups, function () {
var contact = _this3.create(_.assignIn({
'ask': undefined,
'nickname': name,
groups: groups,
......@@ -72450,7 +72494,7 @@ return __p
}
return _.sum(this.models.filter(function (model) {
return !_.includes(ignored, model.get('chat_status'));
return !_.includes(ignored, model.presence.get('show'));
}));
},
onRosterPush: function onRosterPush(iq) {
......@@ -72496,7 +72540,7 @@ return __p
return true;
},
fetchFromServer: function fetchFromServer() {
var _this3 = this;
var _this4 = this;
/* Fetch the roster from the XMPP server */
return new Promise(function (resolve, reject) {
......@@ -72507,7 +72551,7 @@ return __p
xmlns: Strophe.NS.ROSTER
});
var callback = _.flow(_this3.onReceivedFromServer.bind(_this3), resolve);
var callback = _.flow(_this4.onReceivedFromServer.bind(_this4), resolve);
var errback = function errback(iq) {
var errmsg = "Error while trying to fetch roster from the server";
......@@ -72627,7 +72671,6 @@ return __p
var jid = presence.getAttribute('from'),
bare_jid = Strophe.getBareJidFromJid(jid),
resource = Strophe.getResourceFromJid(jid),
chat_status = _.propertyOf(presence.querySelector('show'))('textContent') || 'online',
status_message = _.propertyOf(presence.querySelector('status'))('textContent'),
contact = this.get(bare_jid);
......@@ -72636,8 +72679,10 @@ return __p
// Another resource has changed its status and
// synchronize_availability option set to update,
// we'll update ours as well.
var show = _.propertyOf(presence.querySelector('show'))('textContent') || 'online';
_converse.xmppstatus.save({
'status': chat_status
'status': show
});
if (status_message) {
......@@ -72685,10 +72730,10 @@ return __p
} else if (presence_type === 'subscribe') {
this.handleIncomingSubscription(presence);
} else if (presence_type === 'unavailable' && contact) {
contact.removeResource(resource);
contact.presence.removeResource(resource);
} else if (contact) {
// presence_type is undefined
contact.addResource(presence);
contact.presence.addResource(presence);
}
}
});
......@@ -72705,7 +72750,7 @@ return __p
_converse.RosterGroups = Backbone.Collection.extend({
model: _converse.RosterGroup,
fetchRosterGroups: function fetchRosterGroups() {
var _this4 = this;
var _this5 = this;
/* Fetches all the roster groups from sessionStorage.
*
......@@ -72713,7 +72758,7 @@ return __p
* returned.
*/
return new Promise(function (resolve, reject) {
_this4.fetch({
_this5.fetch({
silent: true,
// We need to first have all groups before
// we can start positioning them, so we set
......@@ -72723,8 +72768,39 @@ return __p
});
}
});
_converse.unregisterPresenceHandler = function () {
if (!_.isUndefined(_converse.presence_ref)) {
_converse.connection.deleteHandler(_converse.presence_ref);
delete _converse.presence_ref;
}
};
/********** Event Handlers *************/
_converse.api.listen.on('beforeTearDown', _converse.unregisterPresenceHandler());
_converse.api.listen.on('afterTearDown', function () {
if (_converse.presence) {
_converse.presences.off().reset(); // Remove presences
}
});
_converse.api.listen.on('clearSession', function () {
if (!_.isUndefined(_this6.roster)) {
_this6.roster.browserStorage._clear();
}
});
_converse.api.listen.on('connectionInitialized', function () {
_converse.presences = new _converse.Presences();
_converse.presences.browserStorage = new Backbone.BrowserStorage.session(b64_sha1("converse.presences-".concat(_converse.bare_jid)));
_converse.presences.fetch();
});
_converse.api.listen.on('statusInitialized', function (reconnecting) {
if (reconnecting) {
// No need to recreate the roster, otherwise we lose our
......@@ -73582,7 +73658,7 @@ return __p
define('tpl!rooms_list', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<a href="#" class="rooms-toggle open-rooms-toggle" title="' +
__p += '<a href="#" class="rooms-toggle open-rooms-toggle controlbox-padded" title="' +
__e(o.desc_rooms) +
'">\n <span class="fa ';
if (o.toggle_state === o._converse.OPENED) { ;
......@@ -73600,7 +73676,7 @@ return __p
define('tpl!rooms_list_item', ['lodash'], function(_) {return function(o) {
var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<div class="list-item available-chatroom d-flex flex-row ';
__p += '<div class="list-item controlbox-padded available-chatroom d-flex flex-row ';
if (o.num_unread_general) { ;
__p += ' unread-msgs ';
} ;
......@@ -73836,7 +73912,7 @@ return __p
insertIntoControlBox: function insertIntoControlBox() {
var controlboxview = _converse.chatboxviews.get('controlbox');
if (!_.isUndefined(controlboxview) && !_converse.root.contains(this.el)) {
if (!_.isUndefined(controlboxview) && !u.rootContains(_converse.root, this.el)) {
var el = controlboxview.el.querySelector('.open-rooms-list');
if (!_.isNull(el)) {
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment