\n ';
+'"/>\n ';
+ } ;
+__p += '\n
\n';
return __p
};});
@@ -12757,8 +12808,8 @@ return __p
Strophe = _converse$env.Strophe,
_ = _converse$env._,
b64_sha1 = _converse$env.b64_sha1,
- moment = _converse$env.moment,
- utils = _converse$env.utils;
+ moment = _converse$env.moment;
+ var u = converse.env.utils;
var KEY = {
ENTER: 13,
FORWARD_SLASH: 47
@@ -12779,7 +12830,7 @@ return __p
return;
}
- utils.slideInAllElements(document.querySelectorAll('.toolbar-menu'));
+ u.slideInAllElements(document.querySelectorAll('.toolbar-menu'));
});
},
ChatBoxViews: {
@@ -12859,8 +12910,8 @@ return __p
var emojis_html = tpl_emojis(_.extend(this.model.toJSON(), {
'transform': _converse.use_emojione ? emojione.shortnameToImage : emojione.shortnameToUnicode,
- 'emojis_by_category': utils.getEmojisByCategory(_converse, emojione),
- 'toned_emojis': utils.getTonedEmojis(_converse),
+ 'emojis_by_category': u.getEmojisByCategory(_converse, emojione),
+ 'toned_emojis': u.getTonedEmojis(_converse),
'skintones': ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'],
'shouldBeHidden': this.shouldBeHidden
}));
@@ -12977,7 +13028,8 @@ return __p
this.model.on('showHelpMessages', this.showHelpMessages, this);
this.model.on('sendMessage', this.sendMessage, this);
this.render().renderToolbar().insertHeading().fetchMessages();
- utils.refreshWebkit();
+ this.createEmojiPicker();
+ u.refreshWebkit();
_converse.emit('chatBoxOpened', this);
@@ -13243,20 +13295,24 @@ return __p
'extra_classes': this.getExtraMessageClasses(attrs)
})));
var msg_content = $msg[0].querySelector('.chat-msg-content');
- msg_content.innerHTML = utils.addEmoji(_converse, emojione, utils.addHyperlinks(xss.filterXSS(text, {
+ msg_content.innerHTML = u.addEmoji(_converse, emojione, u.addHyperlinks(xss.filterXSS(text, {
'whiteList': {}
})));
- utils.renderImageURLs(msg_content);
+ u.renderImageURLs(msg_content);
return $msg;
},
showHelpMessages: function showHelpMessages(msgs, type, spinner) {
var _this3 = this;
_.each(msgs, function (msg) {
- _this3.$content.append($(tpl_help_message({
+ _this3.content.insertAdjacentHTML('beforeend', tpl_help_message({
'type': type || 'info',
- 'message': msgs
- })));
+ 'message': xss.filterXSS(msg, {
+ 'whiteList': {
+ 'strong': []
+ }
+ })
+ }));
});
if (spinner === true) {
@@ -13294,14 +13350,14 @@ return __p
handleTextMessage: function handleTextMessage(message) {
this.showMessage(_.clone(message.attributes));
- if (utils.isNewMessage(message) && message.get('sender') === 'me') {
+ if (u.isNewMessage(message) && message.get('sender') === 'me') {
// We remove the "scrolled" flag so that the chat area
// gets scrolled down. We always want to scroll down
// when the user writes a message as opposed to when a
// message is received.
this.model.set('scrolled', false);
} else {
- if (utils.isNewMessage(message) && this.model.get('scrolled', true)) {
+ if (u.isNewMessage(message) && this.model.get('scrolled', true)) {
this.$el.find('.new-msgs-indicator').removeClass('hidden');
}
}
@@ -13527,7 +13583,7 @@ return __p
var elements = _.difference(document.querySelectorAll('.toolbar-menu'), [this.emoji_picker_view.el]);
- utils.slideInAllElements(elements).then(_.partial(utils.slideToggleElement, this.emoji_picker_view.el)).then(this.focus.bind(this));
+ u.slideInAllElements(elements).then(_.partial(u.slideToggleElement, this.emoji_picker_view.el)).then(this.focus.bind(this));
},
toggleCall: function toggleCall(ev) {
ev.stopPropagation();
@@ -13566,7 +13622,7 @@ return __p
if (_converse.connection.connected) {
// Immediately sending the chat state, because the
// model is going to be destroyed afterwards.
- this.model.set('chat_state', _converse.INACTIVE);
+ this.setChatState(_converse.INACTIVE);
this.sendChatState();
}
@@ -13600,29 +13656,36 @@ return __p
toolbar = toolbar || tpl_toolbar;
options = _.assign(this.model.toJSON(), this.getToolbarOptions(options || {}));
this.el.querySelector('.chat-toolbar').innerHTML = toolbar(options);
+ return this;
+ },
+ renderEmojiPicker: function renderEmojiPicker() {
var toggle = this.el.querySelector('.toggle-smiley');
toggle.innerHTML = '';
toggle.appendChild(this.emoji_picker_view.render().el);
- return this;
},
focus: function focus() {
- this.el.querySelector('.chat-textarea').focus();
+ var textarea_el = this.el.querySelector('.chat-textarea');
- _converse.emit('chatBoxFocused', this);
+ if (!_.isNull(textarea_el)) {
+ textarea_el.focus();
+
+ _converse.emit('chatBoxFocused', this);
+ }
return this;
},
hide: function hide() {
this.el.classList.add('hidden');
- utils.refreshWebkit();
+ u.refreshWebkit();
return this;
},
afterShown: function afterShown(focus) {
- if (utils.isPersistableModel(this.model)) {
+ if (u.isPersistableModel(this.model)) {
this.model.save();
}
this.setChatState(_converse.ACTIVE);
+ this.renderEmojiPicker();
this.scrollDown();
if (focus) {
@@ -13631,7 +13694,7 @@ return __p
},
_show: function _show(focus) {
/* Inner show method that gets debounced */
- if (this.$el.is(':visible') && this.$el.css('opacity') === "1") {
+ if (u.isVisible(this.el)) {
if (focus) {
this.focus();
}
@@ -13639,7 +13702,14 @@ return __p
return;
}
- utils.fadeIn(this.el, _.bind(this.afterShown, this, focus));
+ var that = this;
+ u.fadeIn(this.el, function () {
+ that.afterShown();
+
+ if (focus) {
+ that.focus();
+ }
+ });
},
show: function show(focus) {
if (_.isUndefined(this.debouncedShow)) {
@@ -13689,7 +13759,7 @@ return __p
this.onScrolledDown();
}
- utils.safeSave(this.model, {
+ u.safeSave(this.model, {
'scrolled': scrolled
});
},
@@ -13699,8 +13769,12 @@ return __p
},
_scrollDown: function _scrollDown() {
/* Inner method that gets debounced */
- if (this.$content.is(':visible') && !this.model.get('scrolled')) {
- this.$content.scrollTop(this.$content[0].scrollHeight);
+ if (_.isUndefined(this.content)) {
+ return;
+ }
+
+ if (u.isVisible(this.content) && !this.model.get('scrolled')) {
+ this.content.scrollTop = this.content.scrollHeight;
this.onScrolledDown();
this.model.save({
'auto_scrolled': true
@@ -13931,14 +14005,19 @@ return __p
define('tpl!group_header', ['lodash'], function(_) {return function(o) {
-var __t, __p = '', __e = _.escape;
+var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
+function print() { __p += __j.call(arguments, '') }
__p += '
' +
__e(o.label_group) +
-'\n';
+'\n
\n';
return __p
};});
@@ -13999,7 +14078,7 @@ return __p
define('tpl!roster', ['lodash'], function(_) {return function(o) {
var __t, __p = '';
-__p += '
\n';
+__p += '
\n';
return __p
};});
@@ -14138,18 +14217,18 @@ return __p
/*global define */
(function (root, factory) {
- define('converse-rosterview',["jquery.noconflict", "converse-core", "tpl!group_header", "tpl!pending_contact", "tpl!requesting_contact", "tpl!roster", "tpl!roster_filter", "tpl!roster_item", "converse-chatboxes"], factory);
-})(this, function ($, converse, tpl_group_header, tpl_pending_contact, tpl_requesting_contact, tpl_roster, tpl_roster_filter, tpl_roster_item) {
+ define('converse-rosterview',["converse-core", "tpl!group_header", "tpl!pending_contact", "tpl!requesting_contact", "tpl!roster", "tpl!roster_filter", "tpl!roster_item", "converse-chatboxes"], factory);
+})(this, function (converse, tpl_group_header, tpl_pending_contact, tpl_requesting_contact, tpl_roster, tpl_roster_filter, tpl_roster_item) {
"use strict";
var _converse$env = converse.env,
Backbone = _converse$env.Backbone,
- utils = _converse$env.utils,
Strophe = _converse$env.Strophe,
$iq = _converse$env.$iq,
b64_sha1 = _converse$env.b64_sha1,
sizzle = _converse$env.sizzle,
_ = _converse$env._;
+ var u = converse.env.utils;
converse.plugins.add('converse-rosterview', {
overrides: {
// Overrides mentioned here will be picked up by converse.js's
@@ -14269,7 +14348,7 @@ return __p
this.model.on('change:filter_type', this.render, this);
this.model.on('change:filter_text', this.renderClearButton, this);
},
- renderHTML: function renderHTML() {
+ toHTML: function toHTML() {
return tpl_roster_filter(_.extend(this.model.toJSON(), {
visible: this.shouldBeVisible(),
placeholder: __('Filter'),
@@ -14372,7 +14451,7 @@ return __p
}
},
show: function show() {
- if (utils.isVisible(this.el)) {
+ if (u.isVisible(this.el)) {
return this;
}
@@ -14381,7 +14460,7 @@ return __p
return this;
},
hide: function hide() {
- if (!utils.isVisible(this.el)) {
+ if (!u.isVisible(this.el)) {
return this;
}
@@ -14409,7 +14488,9 @@ return __p
tagName: 'div',
id: 'converse-roster',
initialize: function initialize() {
- _converse.roster.on("add", this.onContactAdd, this);
+ var _this = this;
+
+ _converse.roster.on("add", this.onContactAdded, this);
_converse.roster.on('change', this.onContactChange, this);
@@ -14417,19 +14498,23 @@ return __p
_converse.roster.on("remove", this.update, this);
- this.model.on("add", this.onGroupAdd, this);
+ this.model.on("add", this.onGroupAdded, this);
this.model.on("reset", this.reset, this);
_converse.on('rosterGroupsFetched', this.positionFetchedGroups, this);
- _converse.on('rosterContactsFetched', this.update, this);
+ _converse.on('rosterContactsFetched', function () {
+ _converse.roster.each(_this.onContactAdded.bind(_this));
+
+ _this.update();
+ });
this.createRosterFilter();
},
render: function render() {
- this.renderRoster();
this.el.innerHTML = "";
this.el.appendChild(this.filter_view.render().el);
+ this.renderRoster();
if (!_converse.allow_contact_requests) {
// XXX: if we ever support live editing of config then
@@ -14440,8 +14525,10 @@ return __p
return this;
},
renderRoster: function renderRoster() {
- this.$roster = $(tpl_roster());
- this.roster = this.$roster[0];
+ var div = document.createElement('div');
+ div.insertAdjacentHTML('beforeend', tpl_roster());
+ this.roster_el = div.firstChild;
+ this.el.insertAdjacentElement('beforeend', this.roster_el);
},
createRosterFilter: function createRosterFilter() {
// Create a model on which we can store filter properties
@@ -14471,14 +14558,14 @@ return __p
}
}, 100),
update: _.debounce(function () {
- if (_.isNull(this.roster.parentElement)) {
- this.$el.append(this.$roster.show());
+ if (!u.isVisible(this.roster_el)) {
+ u.showElement(this.roster_el);
}
return this.showHideFilter();
}, _converse.animate ? 100 : 0),
showHideFilter: function showHideFilter() {
- if (!utils.isVisible(this.el)) {
+ if (!u.isVisible(this.el)) {
return;
}
@@ -14500,9 +14587,9 @@ return __p
if (type === 'groups') {
_.each(this.getAll(), function (view, idx) {
if (!_.includes(view.model.get('name').toLowerCase(), query.toLowerCase())) {
- view.hide();
+ u.slideIn(view.el);
} else if (view.model.contacts.length > 0) {
- view.show();
+ u.slideOut(view.el);
}
});
} else {
@@ -14515,18 +14602,17 @@ return __p
_converse.roster.reset();
this.removeAll();
- this.renderRoster();
this.render().update();
return this;
},
- onGroupAdd: function onGroupAdd(group) {
+ onGroupAdded: function onGroupAdded(group) {
var view = new _converse.RosterGroupView({
model: group
});
- this.add(group.get('name'), view.render());
- this.positionGroup(view);
+ this.add(group.get('name'), view);
+ this.positionGroup(group);
},
- onContactAdd: function onContactAdd(contact) {
+ onContactAdded: function onContactAdded(contact) {
this.addRosterContact(contact).update();
this.updateFilter();
},
@@ -14579,52 +14665,28 @@ return __p
* positioned aren't already in inserted into the
* roster DOM element.
*/
- var that = this;
this.model.sort();
- this.model.each(function (group, idx) {
- var view = that.get(group.get('name'));
-
- if (!view) {
- view = new _converse.RosterGroupView({
- model: group
- });
- that.add(group.get('name'), view.render());
- }
-
- if (idx === 0) {
- that.$roster.append(view.$el);
- } else {
- that.appendGroup(view);
- }
- });
+ this.model.each(this.onGroupAdded.bind(this));
},
- positionGroup: function positionGroup(view) {
+ positionGroup: function positionGroup(group) {
/* Place the group's DOM element in the correct alphabetical
* position amongst the other groups in the roster.
+ *
+ * NOTE: relies on the assumption that it will be called in
+ * the right order of appearance of groups.
*/
- var $groups = this.$roster.find('.roster-group'),
- index = $groups.length ? this.model.indexOf(view.model) : 0;
+ var view = this.get(group.get('name'));
+ view.render();
+ var list = this.roster_el,
+ index = this.model.indexOf(view.model);
if (index === 0) {
- this.$roster.prepend(view.$el);
+ list.insertAdjacentElement('afterbegin', view.el);
} else if (index === this.model.length - 1) {
- this.appendGroup(view);
+ list.insertAdjacentElement('beforeend', view.el);
} else {
- $($groups.eq(index)).before(view.$el);
- }
-
- return this;
- },
- appendGroup: function appendGroup(view) {
- /* Add the group at the bottom of the roster
- */
- var $last = this.$roster.find('.roster-group').last();
- var $siblings = $last.siblings('dd');
-
- if ($siblings.length > 0) {
- $siblings.last().after(view.$el);
- } else {
- $last.after(view.$el);
+ var neighbour_el = list.querySelector('div:nth-child(' + index + ')');
+ neighbour_el.insertAdjacentElement('afterend', view.el);
}
return this;
@@ -14677,7 +14739,8 @@ return __p
}
});
_converse.RosterContactView = Backbone.View.extend({
- tagName: 'dd',
+ tagName: 'li',
+ className: 'hidden',
events: {
"click .accept-xmpp-request": "acceptRequest",
"click .decline-xmpp-request": "declineRequest",
@@ -14694,7 +14757,7 @@ return __p
var that = this;
if (!this.mayBeShown()) {
- this.$el.hide();
+ u.hideElement(this.el);
return this;
}
@@ -14711,7 +14774,8 @@ return __p
}
});
- this.$el.addClass(chat_status).data('status', chat_status);
+ this.el.classList.add(chat_status);
+ this.el.setAttribute('data-status', chat_status);
if (ask === 'subscribe' || subscription === 'from') {
/* ask === 'subscribe'
@@ -14726,17 +14790,17 @@ return __p
* So in both cases the user is a "pending" contact.
*/
this.el.classList.add('pending-xmpp-contact');
- this.$el.html(tpl_pending_contact(_.extend(item.toJSON(), {
+ this.el.innerHTML = tpl_pending_contact(_.extend(item.toJSON(), {
'desc_remove': __('Click to remove %1$s as a contact', item.get('fullname')),
'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts
- })));
+ }));
} else if (requesting === true) {
this.el.classList.add('requesting-xmpp-contact');
- this.$el.html(tpl_requesting_contact(_.extend(item.toJSON(), {
+ this.el.innerHTML = tpl_requesting_contact(_.extend(item.toJSON(), {
'desc_accept': __("Click to accept the contact request from %1$s", item.get('fullname')),
'desc_decline': __("Click to decline the contact request from %1$s", item.get('fullname')),
'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts
- })));
+ }));
} else if (subscription === 'both' || subscription === 'to') {
this.el.classList.add('current-xmpp-contact');
this.el.classList.remove(_.without(['both', 'to'], subscription)[0]);
@@ -14747,45 +14811,22 @@ return __p
return this;
},
renderRosterItem: function renderRosterItem(item) {
- var chat_status = item.get('chat_status');
- this.$el.html(tpl_roster_item(_.extend(item.toJSON(), {
- 'desc_status': STATUSES[chat_status || 'offline'],
+ this.el.innerHTML = tpl_roster_item(_.extend(item.toJSON(), {
+ 'desc_status': STATUSES[item.get('chat_status') || 'offline'],
'desc_chat': __('Click to chat with this contact'),
'desc_remove': __('Click to remove %1$s as a contact', item.get('fullname')),
'title_fullname': __('Name'),
'allow_contact_removal': _converse.allow_contact_removal,
'num_unread': item.get('num_unread') || 0
- })));
- return this;
- },
- isGroupCollapsed: function isGroupCollapsed() {
- /* Check whether the group in which this contact appears is
- * collapsed.
- */
- // XXX: this sucks and is fragile.
- // It's because I tried to do the "right thing"
- // and use definition lists to represent roster groups.
- // If roster group items were inside the group elements, we
- // would simplify things by not having to check whether the
- // group is collapsed or not.
- var name = this.$el.prevAll('dt:first').data('group');
-
- var group = _.head(_converse.rosterview.model.where({
- 'name': name.toString()
}));
-
- if (group.get('state') === _converse.CLOSED) {
- return true;
- }
-
- return false;
+ return this;
},
mayBeShown: function mayBeShown() {
/* Return a boolean indicating whether this contact should
* generally be visible in the roster.
*
* It doesn't check for the more specific case of whether
- * the group it's in is collapsed (see isGroupCollapsed).
+ * the group it's in is collapsed.
*/
var chatStatus = this.model.get('chat_status');
@@ -14808,7 +14849,7 @@ return __p
return _converse.chatboxviews.showChat(this.model.attributes, true);
},
removeContact: function removeContact(ev) {
- var _this = this;
+ var _this2 = this;
if (ev && ev.preventDefault) {
ev.preventDefault();
@@ -14831,9 +14872,9 @@ return __p
});
_converse.connection.sendIQ(iq, function (iq) {
- _this.model.destroy();
+ _this2.model.destroy();
- _this.remove();
+ _this2.remove();
}, function (err) {
alert(__('Sorry, there was an error while trying to remove %1$s as a contact.', name));
@@ -14842,14 +14883,14 @@ return __p
}
},
acceptRequest: function acceptRequest(ev) {
- var _this2 = this;
+ var _this3 = this;
if (ev && ev.preventDefault) {
ev.preventDefault();
}
_converse.roster.sendContactAddIQ(this.model.get('jid'), this.model.get('fullname'), [], function () {
- _this2.model.authorize().subscribe();
+ _this3.model.authorize().subscribe();
});
},
declineRequest: function declineRequest(ev) {
@@ -14867,21 +14908,17 @@ return __p
}
});
_converse.RosterGroupView = Backbone.Overview.extend({
- tagName: 'dt',
+ tagName: 'div',
className: 'roster-group',
events: {
"click a.group-toggle": "toggle"
},
initialize: function initialize() {
- this.model.contacts.on("add", this.addContact, this);
+ this.sortEventually = _.debounce(this.sortAndPositionAll, 500);
+ this.model.contacts.on("add", this.onContactAdded, this);
this.model.contacts.on("change:subscription", this.onContactSubscriptionChange, this);
this.model.contacts.on("change:requesting", this.onContactRequestChange, this);
- this.model.contacts.on("change:chat_status", function (contact) {
- // This might be optimized by instead of first sorting,
- // finding the correct position in positionContact
- this.model.contacts.sort();
- this.positionContact(contact).render();
- }, this);
+ this.model.contacts.on("change:chat_status", this.sortEventually, this);
this.model.contacts.on("destroy", this.onRemove, this);
this.model.contacts.on("remove", this.onRemove, this);
@@ -14889,34 +14926,33 @@ return __p
},
render: function render() {
this.el.setAttribute('data-group', this.model.get('name'));
- var html = tpl_group_header({
- label_group: this.model.get('name'),
- desc_group_toggle: this.model.get('description'),
- toggle_state: this.model.get('state')
+ this.el.innerHTML = tpl_group_header({
+ 'label_group': this.model.get('name'),
+ 'desc_group_toggle': this.model.get('description'),
+ 'toggle_state': this.model.get('state'),
+ '_converse': _converse
});
- this.el.innerHTML = html;
+ this.contacts_el = this.el.querySelector('.roster-group-contacts');
return this;
},
- addContact: function addContact(contact) {
- var view = new _converse.RosterContactView({
+ createContactView: function createContactView(contact) {
+ var contact_view = new _converse.RosterContactView({
model: contact
});
- this.add(contact.get('id'), view);
- view = this.positionContact(contact).render();
+ this.add(contact.get('id'), contact_view);
+ contact_view.render();
+ return contact_view;
+ },
+ onContactAdded: function onContactAdded(contact) {
+ var contact_view = this.positionContact(contact);
- if (view.mayBeShown()) {
+ if (contact_view.mayBeShown()) {
if (this.model.get('state') === _converse.CLOSED) {
- if (view.$el[0].style.display !== "none") {
- view.$el.hide();
- }
-
- if (!this.$el.is(':visible')) {
- this.$el.show();
- }
+ u.hideElement(contact_view.el);
+ u.showElement(this.el);
} else {
- if (this.$el[0].style.display !== "block") {
- this.show();
- }
+ u.showElement(contact_view.el);
+ u.showElement(this.el);
}
}
},
@@ -14924,120 +14960,134 @@ return __p
/* Place the contact's DOM element in the correct alphabetical
* position amongst the other contacts in this group.
*/
- var view = this.get(contact.get('id'));
+ var view = this.get(contact.get('id')) || this.createContactView(contact);
+ var list = this.contacts_el;
var index = this.model.contacts.indexOf(contact);
- view.$el.detach();
if (index === 0) {
- this.$el.after(view.$el);
+ list.insertAdjacentElement('afterbegin', view.el);
} else if (index === this.model.contacts.length - 1) {
- this.$el.nextUntil('dt').last().after(view.$el);
+ list.insertAdjacentElement('beforeend', view.el);
} else {
- this.$el.nextUntil('dt').eq(index).before(view.$el);
+ var neighbour_el = list.querySelector('li:nth-child(' + index + ')');
+ neighbour_el.insertAdjacentElement('afterend', view.el);
}
return view;
},
+ sortAndPositionAll: function sortAndPositionAll() {
+ this.model.contacts.sort();
+ this.model.contacts.each(this.positionContact.bind(this));
+ },
show: function show() {
- this.$el.show();
+ var _this4 = this;
- _.each(this.getAll(), function (view) {
- if (view.mayBeShown() && !view.isGroupCollapsed()) {
- view.$el.show();
+ u.showElement(this.el);
+
+ _.each(this.getAll(), function (contact_view) {
+ if (contact_view.mayBeShown() && _this4.model.get('state') === _converse.OPENED) {
+ u.showElement(contact_view.el);
}
});
return this;
},
- hide: function hide() {
- this.$el.nextUntil('dt').addBack().hide();
+ collapse: function collapse() {
+ return u.slideIn(this.contacts_el);
+ },
+ filterOutContacts: function filterOutContacts() {
+ var _this5 = this;
+
+ var contacts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
+
+ /* Given a list of contacts, make sure they're filtered out
+ * (aka hidden) and that all other contacts are visible.
+ *
+ * If all contacts are hidden, then also hide the group
+ * title.
+ */
+ var shown = 0;
+ var all_contact_views = this.getAll();
+
+ _.each(this.model.contacts.models, function (contact) {
+ var contact_view = _this5.get(contact.get('id'));
+
+ if (_.includes(contacts, contact)) {
+ u.hideElement(contact_view.el);
+ } else if (contact_view.mayBeShown()) {
+ u.showElement(contact_view.el);
+ shown += 1;
+ }
+ });
+
+ if (shown) {
+ u.showElement(this.el);
+ } else {
+ u.hideElement(this.el);
+ }
+ },
+ getFilterMatches: function getFilterMatches(q, type) {
+ /* Given the filter query "q" and the filter type "type",
+ * return a list of contacts that need to be filtered out.
+ */
+ if (q.length === 0) {
+ return [];
+ }
+
+ var matches;
+ q = q.toLowerCase();
+
+ if (type === 'state') {
+ if (this.model.get('name') === HEADER_REQUESTING_CONTACTS) {
+ // When filtering by chat state, we still want to
+ // 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');
+ });
+ } 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));
+ }
+ } else {
+ matches = this.model.contacts.filter(u.contains.not('fullname', q));
+ }
+
+ return matches;
},
filter: function filter(q, type) {
- var _this3 = this;
-
/* Filter the group's contacts based on the query "q".
* The query is matched against the contact's full name.
* If all contacts are filtered out (i.e. hidden), then the
* group must be filtered out as well.
*/
- var matches;
-
- if (q.length === 0) {
- if (this.model.get('state') === _converse.OPENED) {
- this.model.contacts.each(function (item) {
- var view = _this3.get(item.get('id'));
-
- if (view.mayBeShown() && !view.isGroupCollapsed()) {
- view.$el.show();
- }
- });
- }
-
- this.showIfNecessary();
- } else {
- q = q.toLowerCase();
-
- if (type === 'state') {
- if (this.model.get('name') === HEADER_REQUESTING_CONTACTS) {
- // When filtering by chat state, we still want to
- // show requesting contacts, even though they don't
- // have the state in question.
- matches = this.model.contacts.filter(function (contact) {
- return utils.contains.not('chat_status', q)(contact) && !contact.get('requesting');
- });
- } else if (q === 'unread_messages') {
- matches = this.model.contacts.filter({
- 'num_unread': 0
- });
- } else {
- matches = this.model.contacts.filter(utils.contains.not('chat_status', q));
- }
- } else {
- matches = this.model.contacts.filter(utils.contains.not('fullname', q));
- }
-
- if (matches.length === this.model.contacts.length) {
- // hide the whole group
- this.hide();
- } else {
- _.each(matches, function (item) {
- _this3.get(item.get('id')).$el.hide();
- });
-
- if (this.model.get('state') === _converse.OPENED) {
- _.each(this.model.contacts.reject(utils.contains.not('fullname', q)), function (item) {
- _this3.get(item.get('id')).$el.show();
- });
- }
-
- this.showIfNecessary();
- }
- }
- },
- showIfNecessary: function showIfNecessary() {
- if (!this.$el.is(':visible') && this.model.contacts.length > 0) {
- this.$el.show();
- }
+ this.filterOutContacts(this.getFilterMatches(q, type));
},
toggle: function toggle(ev) {
if (ev && ev.preventDefault) {
ev.preventDefault();
}
- var $el = $(ev.target);
-
- if ($el.hasClass("icon-opened")) {
- this.$el.nextUntil('dt').slideUp();
+ if (_.includes(ev.target.classList, "icon-opened")) {
this.model.save({
state: _converse.CLOSED
});
- $el.removeClass("icon-opened").addClass("icon-closed");
+ this.collapse().then(function () {
+ ev.target.classList.remove("icon-opened");
+ ev.target.classList.add("icon-closed");
+ });
} else {
- $el.removeClass("icon-closed").addClass("icon-opened");
+ ev.target.classList.remove("icon-closed");
+ ev.target.classList.add("icon-opened");
this.model.save({
state: _converse.OPENED
});
- this.filter(_converse.rosterview.$('.roster-filter').val() || '', _converse.rosterview.$('.filter-type').val());
+ this.filter(_converse.rosterview.el.querySelector('.roster-filter').value, _converse.rosterview.el.querySelector('.filter-type').value);
+ u.showElement(this.el);
+ u.slideOut(this.contacts_el);
}
},
onContactGroupChange: function onContactGroupChange(contact) {
@@ -15049,7 +15099,7 @@ return __p
if (in_this_group && !in_this_overview) {
this.model.contacts.remove(cid);
} else if (!in_this_group && in_this_overview) {
- this.addContact(contact);
+ this.onContactAdded(contact);
}
},
onContactSubscriptionChange: function onContactSubscriptionChange(contact) {
@@ -15076,7 +15126,7 @@ return __p
this.remove(contact.get('id'));
if (this.model.contacts.length === 0) {
- this.$el.hide();
+ u.hideElement(this.el);
}
}
});
@@ -15115,7 +15165,7 @@ return __p
return; // The message has no text
}
- if (chatbox.get('type') !== 'chatroom' && utils.isNewMessage(data.stanza) && chatbox.newMessageWillBeHidden()) {
+ if (chatbox.get('type') !== 'chatroom' && u.isNewMessage(data.stanza) && chatbox.newMessageWillBeHidden()) {
var contact = _.head(_converse.roster.where({
'jid': chatbox.get('jid')
}));
@@ -15609,8 +15659,8 @@ return __p
/*global define */
(function (root, factory) {
- define('converse-controlbox',["jquery.noconflict", "converse-core", "lodash.fp", "tpl!add_contact_dropdown", "tpl!add_contact_form", "tpl!converse_brand_heading", "tpl!contacts_panel", "tpl!contacts_tab", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "tpl!search_contact", "tpl!spinner", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
-})(this, function ($, converse, fp, tpl_add_contact_dropdown, tpl_add_contact_form, tpl_brand_heading, tpl_contacts_panel, tpl_contacts_tab, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel, tpl_search_contact, tpl_spinner) {
+ define('converse-controlbox',["jquery.noconflict", "converse-core", "lodash.fp", "tpl!add_contact_dropdown", "tpl!add_contact_form", "tpl!converse_brand_heading", "tpl!contacts_panel", "tpl!contacts_tab", "tpl!controlbox", "tpl!controlbox_toggle", "tpl!login_panel", "tpl!search_contact", "converse-chatview", "converse-rosterview", "converse-profile"], factory);
+})(this, function ($, converse, fp, tpl_add_contact_dropdown, tpl_add_contact_form, tpl_brand_heading, tpl_contacts_panel, tpl_contacts_tab, tpl_controlbox, tpl_controlbox_toggle, tpl_login_panel, tpl_search_contact) {
"use strict";
var USERS_PANEL_ID = 'users';
@@ -16043,7 +16093,7 @@ return __p
this.model.on('change', this.render, this);
this.listenTo(_converse.connfeedback, 'change', this.render);
},
- renderHTML: function renderHTML() {
+ toHTML: function toHTML() {
var connection_status = _converse.connfeedback.get('connection_status');
var feedback_class, pretty_status;
@@ -16747,9 +16797,9 @@ __p += '\n
\n ';
+'">\n ';
if (o.show_send_button) { ;
__p += '\n