Commit 8e0f8f0a authored by JC Brand's avatar JC Brand

Add the ability to filter contacts by chat state.

The roster filter is now also remembered across page loads.
parent 885c553e
......@@ -1848,6 +1848,15 @@
background-position: right 3px center; }
#conversejs #converse-roster .roster-filter-group .roster-filter.onX {
cursor: pointer; }
#conversejs #converse-roster .roster-filter-group .state-type {
float: left;
border: 1px solid #999;
font-size: calc(14px - 2px);
height: 25px;
margin: 0;
padding: 0;
padding-left: 0.4em;
width: 53%; }
#conversejs #converse-roster .roster-filter-group .filter-type {
display: table-cell;
float: right;
......
......@@ -2,8 +2,10 @@
## 1.0.0 (Unreleased)
- Better Sass/CSS for responsive/mobile views. [jcbrand]
- Split converse.js up into different plugin modules. [jcbrand]
- Better Sass/CSS for responsive/mobile views. New mobile-only build. [jcbrand]
- Roster contacts can now be filtered by chat state and roster filters are
remembered across page loads. [jcbrand]
- Add support for messages with type `headline`, often used for notifications
from the server. [jcbrand]
- Add stanza-specific event listener `converse.listen.stanza`.
......
......@@ -44,6 +44,16 @@
.roster-filter.onX {
cursor: pointer;
}
.state-type {
float: left;
border: 1px solid #999;
font-size: calc(#{$font-size} - 2px);
height: $controlbox-dropdown-height;
margin: 0;
padding: 0;
padding-left: 0.4em;
width: 53%;
}
.filter-type {
display: table-cell;
float: right;
......
......@@ -138,28 +138,38 @@
test_utils.openControlBox();
});
it("will only appear when roster contacts flow over the visible area", $.proxy(function () {
_clearContacts();
it("will only appear when roster contacts flow over the visible area", function () {
var $filter = converse.rosterview.$('.roster-filter');
var names = mock.cur_names;
expect($filter.length).toBe(1);
expect($filter.is(':visible')).toBeFalsy();
for (var i=0; i<names.length; i++) {
converse.roster.create({
ask: null,
fullname: names[i],
jid: names[i].replace(/ /g,'.').toLowerCase() + '@localhost',
requesting: 'false',
subscription: 'both'
});
runs(function () {
_clearContacts();
converse.rosterview.update(); // XXX: Will normally called as event handler
});
waits(5); // Needed, due to debounce
runs(function () {
expect($filter.length).toBe(1);
expect($filter.is(':visible')).toBeFalsy();
for (var i=0; i<names.length; i++) {
converse.roster.create({
ask: null,
fullname: names[i],
jid: names[i].replace(/ /g,'.').toLowerCase() + '@localhost',
requesting: 'false',
subscription: 'both'
});
converse.rosterview.update(); // XXX: Will normally called as event handler
}
});
waits(5); // Needed, due to debounce
runs(function () {
$filter = converse.rosterview.$('.roster-filter');
if (converse.rosterview.$roster.hasScrollBar()) {
expect($filter.is(':visible')).toBeTruthy();
} else {
expect($filter.is(':visible')).toBeFalsy();
}
}
}, converse));
});
});
it("can be used to filter the contacts shown", function () {
var $filter;
......@@ -171,8 +181,9 @@
$filter = converse.rosterview.$('.roster-filter');
$roster = converse.rosterview.$roster;
});
waits(350); // Needed, due to debounce
waits(5); // Needed, due to debounce in "update" method
runs(function () {
converse.rosterview.filter_view.delegateEvents();
expect($roster.find('dd:visible').length).toBe(15);
expect($roster.find('dt:visible').length).toBe(5);
$filter.val("candice");
......@@ -180,30 +191,33 @@
expect($roster.find('dt:visible').length).toBe(5); // ditto
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
expect($roster.find('dd:visible').length).toBe(1);
expect($roster.find('dd:visible').eq(0).text().trim()).toBe('Candice van der Knijff');
expect($roster.find('dt:visible').length).toBe(1);
expect($roster.find('dt:visible').eq(0).text()).toBe('colleagues');
$filter = converse.rosterview.$('.roster-filter');
$filter.val("an");
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
expect($roster.find('dd:visible').length).toBe(5);
expect($roster.find('dt:visible').length).toBe(4);
$filter = converse.rosterview.$('.roster-filter');
$filter.val("xxx");
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
expect($roster.find('dd:visible').length).toBe(0);
expect($roster.find('dt:visible').length).toBe(0);
$filter = converse.rosterview.$('.roster-filter');
$filter.val(""); // Check that contacts are shown again, when the filter string is cleared.
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs(function () {
expect($roster.find('dd:visible').length).toBe(15);
expect($roster.find('dt:visible').length).toBe(5);
......@@ -219,12 +233,13 @@
converse.roster_groups = true;
_clearContacts();
utils.createGroupedContacts();
converse.rosterview.filter_view.delegateEvents();
$filter = converse.rosterview.$('.roster-filter');
$roster = converse.rosterview.$roster;
$type = converse.rosterview.$('.filter-type');
$type.val('groups');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs(function () {
expect($roster.find('dd:visible').length).toBe(15);
expect($roster.find('dt:visible').length).toBe(5);
......@@ -233,22 +248,24 @@
expect($roster.find('dt:visible').length).toBe(5); // ditto
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
expect($roster.find('dt:visible').length).toBe(1);
expect($roster.find('dt:visible').eq(0).text()).toBe('colleagues');
// Check that all contacts under the group are shown
expect($roster.find('dt:visible').nextUntil('dt', 'dd:hidden').length).toBe(0);
$filter = converse.rosterview.$('.roster-filter');
$filter.val("xxx");
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
expect($roster.find('dt:visible').length).toBe(0);
$filter = converse.rosterview.$('.roster-filter');
$filter.val(""); // Check that groups are shown again, when the filter string is cleared.
$filter.trigger('keydown');
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs(function () {
expect($roster.find('dd:visible').length).toBe(15);
expect($roster.find('dt:visible').length).toBe(5);
......@@ -262,12 +279,14 @@
utils.createGroupedContacts();
var $filter = converse.rosterview.$('.roster-filter');
runs (function () {
converse.rosterview.filter_view.delegateEvents();
$filter.val("xxx");
$filter.trigger('keydown');
expect($filter.hasClass("x")).toBeFalsy();
});
waits(350); // Needed, due to debounce
waits(550); // Needed, due to debounce
runs (function () {
$filter = converse.rosterview.$('.roster-filter');
expect($filter.hasClass("x")).toBeTruthy();
$filter.addClass("onX").click();
expect($filter.val()).toBe("");
......
......@@ -324,7 +324,7 @@
onControlBoxToggleHidden: function () {
this.$el.show('fast', function () {
if (converse.rosterview) {
converse.rosterview.update();
converse.rosterview.updateOnlineCount();
}
utils.refreshWebkit();
converse.emit('controlBoxOpened', this);
......
......@@ -779,20 +779,6 @@
.c('item', {jid: this.get('jid'), subscription: "remove"});
converse.connection.sendIQ(iq, callback, callback);
return this;
},
showInRoster: function () {
var chatStatus = this.get('chat_status');
if ((converse.show_only_online_users && chatStatus !== 'online') || (converse.hide_offline_users && chatStatus === 'offline')) {
// If pending or requesting, show
if ((this.get('ask') === 'subscribe') ||
(this.get('subscription') === 'from') ||
(this.get('requesting') === true)) {
return true;
}
return false;
}
return true;
}
});
......
This diff is collapsed.
<form class="pure-form roster-filter-group input-button-group">
<input style="display: none;" class="roster-filter" placeholder="{{placeholder}}">
<select style="display: none;" class="filter-type">
<option value="contacts">{{label_contacts}}</option>
<option value="groups">{{label_groups}}</option>
<input value="{{filter_text}}" class="roster-filter"
placeholder="{{placeholder}}"
{[ if (filter_type === 'state') { ]} style="display: none" {[ } ]} >
<select class="state-type" {[ if (filter_type !== 'state') { ]} style="display: none" {[ } ]} >
<option value="">{{label_any}}</option>
<option {[ if (chat_state === 'online') { ]} selected="selected" {[ } ]}
value="online">{{label_online}}</option>
<option {[ if (chat_state === 'chatty') { ]} selected="selected" {[ } ]}
value="chatty">{{label_chatty}}</option>
<option {[ if (chat_state === 'dnd') { ]} selected="selected" {[ } ]}
value="dnd">{{label_busy}}</option>
<option {[ if (chat_state === 'away') { ]} selected="selected" {[ } ]}
value="away">{{label_away}}</option>
<option {[ if (chat_state === 'xa') { ]} selected="selected" {[ } ]}
value="xa">{{label_xa}}</option>
<option {[ if (chat_state === 'offline') { ]} selected="selected" {[ } ]}
value="offline">{{label_offline}}</option>
</select>
<select class="filter-type">
<option {[ if (filter_type === 'contacts') { ]} selected="selected" {[ } ]}
value="contacts">{{label_contacts}}</option>
<option {[ if (filter_type === 'groups') { ]} selected="selected" {[ } ]}
value="groups">{{label_groups}}</option>
<option {[ if (filter_type === 'state') { ]} selected="selected" {[ } ]}
value="state">{{label_state}}</option>
</select>
</form>
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