diff --git a/converse.js b/converse.js
index 0e659c43c..c6b9c2447 100644
--- a/converse.js
+++ b/converse.js
@@ -3240,7 +3240,8 @@
initialize: function () {
this.model.contacts.on("add", this.addContact, 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 might be optimized by instead of first sorting,
+ // finding the correct position in positionContact
this.model.contacts.sort();
this.positionContact(contact).render();
}, this);
@@ -3293,7 +3294,7 @@
addContact: function (contact) {
var view = new converse.RosterContactView({model: contact});
this.add(contact.get('id'), view);
- var view = this.positionContact(contact).render();
+ view = this.positionContact(contact).render();
if (this.model.get('state') === CLOSED) {
view.$el.hide();
}
@@ -3347,7 +3348,7 @@
});
this.RosterView = Backbone.Overview.extend({
- tagName: 'dl',
+ tagName: 'div',
id: 'converse-roster',
initialize: function () {
@@ -3369,7 +3370,10 @@
},
render: function () {
- this.$el.empty();
+ this.$el.html(converse.templates.roster({
+ placeholder: __('Type to filter contacts')
+ }));
+ this.$('.roster-filter').liveFilter('.roster-contacts', {hide: 'dt'});
return this;
},
@@ -3457,13 +3461,13 @@
*/
model.sort();
model.each($.proxy(function (group, idx) {
- var view = this.get(group.get('name'))
+ var view = this.get(group.get('name'));
if (!view) {
view = new converse.RosterGroupView({model: group});
this.add(group.get('name'), view.render());
}
if (idx === 0) {
- this.$el.append(view.$el);
+ this.$('.roster-contacts').append(view.$el);
} else {
this.appendGroup(view);
}
@@ -3476,7 +3480,7 @@
*/
var index = this.model.indexOf(view.model);
if (index === 0) {
- this.$el.prepend(view.$el);
+ this.$('.roster-contacts').prepend(view.$el);
} else if (index == (this.model.length-1)) {
this.appendGroup(view);
} else {
diff --git a/css/converse.css b/css/converse.css
index 433e089e7..76019e9a7 100644
--- a/css/converse.css
+++ b/css/converse.css
@@ -872,11 +872,11 @@ dl.add-converse-contact {
white-space: nowrap;
text-overflow: ellipsis;
}
-#conversejs #converse-roster span.req-contact-name {
+#converse-roster span.req-contact-name {
width: 65%;
}
-#conversejs #converse-roster span.pending-contact-name,
-#conversejs #converse-roster a.open-chat {
+#converse-roster span.pending-contact-name,
+#converse-roster a.open-chat {
width: 80%;
}
#converse-roster dd span {
@@ -952,7 +952,7 @@ dl.add-converse-contact {
font-size: 15px;
}
#conversejs dd.available-chatroom,
-#conversejs #converse-roster dd {
+#converse-roster dd {
font-weight: bold;
border: none;
display: block;
@@ -961,7 +961,7 @@ dl.add-converse-contact {
text-shadow: 0 1px 0 #fafafa;
clear: both;
}
-#conversejs #converse-roster dd {
+#converse-roster dd {
line-height: 16px;
}
#conversejs .group-toggle {
@@ -970,20 +970,20 @@ dl.add-converse-contact {
}
#conversejs .roster-group:hover,
#conversejs dd.available-chatroom:hover,
-#conversejs #converse-roster dd:hover {
+#converse-roster dd:hover {
background-color: #eee;
}
-#conversejs #converse-roster dd a.decline-xmpp-request {
+#converse-roster dd a.decline-xmpp-request {
margin-left: 5px;
}
-#conversejs #converse-roster dd a.remove-xmpp-contact {
+#converse-roster dd a.remove-xmpp-contact {
float: right;
width: 22px;
margin: 0;
display: none;
color: #4f4f4f;
}
-#conversejs #converse-roster dd:hover a.remove-xmpp-contact {
+#converse-roster dd:hover a.remove-xmpp-contact {
display: inline-block;
}
#conversejs .chatbox,
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst
index 19b7ecb18..5e1526c34 100644
--- a/docs/CHANGES.rst
+++ b/docs/CHANGES.rst
@@ -1,8 +1,14 @@
Changelog
=========
-0.8 (2014-08-04)
-----------------
+0.8.1 (Unreleased)
+------------------
+
+* #212 Provide a live filter of the roster contacts. [jcbrand]
+
+
+0.8.0 (2014-08-04)
+------------------
.. note::
1. Converse.js is now relicensed under the `Mozilla Public License `_.
diff --git a/less/converse.less b/less/converse.less
index 1f5c49c25..43c81238b 100644
--- a/less/converse.less
+++ b/less/converse.less
@@ -967,12 +967,12 @@ dl.add-converse-contact {
text-overflow: ellipsis;
}
-#conversejs #converse-roster span.req-contact-name {
+#converse-roster span.req-contact-name {
width: 65%;
}
-#conversejs #converse-roster span.pending-contact-name,
-#conversejs #converse-roster a.open-chat {
+#converse-roster span.pending-contact-name,
+#converse-roster a.open-chat {
width: 80%;
}
@@ -1063,7 +1063,7 @@ dl.add-converse-contact {
}
#conversejs dd.available-chatroom,
-#conversejs #converse-roster dd {
+#converse-roster dd {
font-weight: bold;
border: none;
display: block;
@@ -1073,7 +1073,7 @@ dl.add-converse-contact {
clear: both;
}
-#conversejs #converse-roster dd {
+#converse-roster dd {
line-height: 16px;
}
@@ -1084,15 +1084,15 @@ dl.add-converse-contact {
#conversejs .roster-group:hover,
#conversejs dd.available-chatroom:hover,
-#conversejs #converse-roster dd:hover {
+#converse-roster dd:hover {
background-color: #eee;
}
-#conversejs #converse-roster dd a.decline-xmpp-request {
+#converse-roster dd a.decline-xmpp-request {
margin-left: 5px;
}
-#conversejs #converse-roster dd a.remove-xmpp-contact {
+#converse-roster dd a.remove-xmpp-contact {
float: right;
width: 22px;
margin: 0;
@@ -1100,7 +1100,7 @@ dl.add-converse-contact {
color: rgb(79, 79, 79);
}
-#conversejs #converse-roster dd:hover a.remove-xmpp-contact {
+#converse-roster dd:hover a.remove-xmpp-contact {
display: inline-block;
}
diff --git a/main.js b/main.js
index f38cfb4da..065f3600a 100644
--- a/main.js
+++ b/main.js
@@ -4,6 +4,7 @@ config = {
"jquery": "components/jquery/dist/jquery",
"jquery.browser": "components/jquery.browser/dist/jquery.browser",
"jquery.easing": "components/jquery-easing-original/jquery.easing.1.3", // XXX: Only required for https://conversejs.org website
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"bootstrap": "components/bootstrap/dist/js/bootstrap", // XXX: Only required for https://conversejs.org website
"locales": "locale/locales",
"underscore": "components/underscore/underscore",
@@ -74,6 +75,7 @@ config = {
'bigint': { deps: ['crypto'] },
'jquery.browser': { deps: ['jquery'] },
'jquery.easing': { deps: ['jquery'] },
+ 'jquery.fastLiveFilter':{ deps: ['jquery'] },
'strophe': { deps: ['jquery'] },
'strophe.disco': { deps: ['strophe'] },
'strophe.muc': { deps: ['strophe', 'jquery'] },
diff --git a/mockup/controlbox.html b/mockup/controlbox.html
index abd1df3e0..a5e3a52a3 100644
--- a/mockup/controlbox.html
+++ b/mockup/controlbox.html
@@ -114,139 +114,142 @@
-
- -
- Colleagues
-
- -
-
-
- Victor Matfield
-
-
-
- -
-
-
- William Winterbottom
-
-
-
- -
-
-
- Gary Teichmann
-
-
-
+
-
-
-
- - Rooms on conference.opkode.im
- -
- Special chatroom with a long name (2)
-
-
-
Description:
-
Occupants: 2
-
Features:
-
- - Moderated
- Open room
- - Permanent room
- Public
- - Semi-anonymous
- - Requires authentication
-
-
-
-
-
+
-
+ Pending Contacts
+
+
- Rassie Erasmus
+
+
+
- Victor Matfield
+
+
+
+
+
+
+
+ - Rooms on conference.opkode.im
+ -
+ Special chatroom with a long name (2)
+
+
+
Description:
+
Occupants: 2
+
Features:
+
+ - Moderated
- Open room
+ - Permanent room
- Public
+ - Semi-anonymous
+ - Requires authentication
+
+
+
+
+
+
diff --git a/src/build-no-locales-no-otr.js b/src/build-no-locales-no-otr.js
index 59980d89e..dc70e383a 100644
--- a/src/build-no-locales-no-otr.js
+++ b/src/build-no-locales-no-otr.js
@@ -25,6 +25,7 @@
"strophe.disco": "components/strophe.disco/index",
"converse-dependencies": "src/deps-no-otr",
"jquery.browser": "components/jquery.browser/dist/jquery.browser",
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"moment":"components/momentjs/moment",
"converse-templates":"src/templates",
"tpl": "components/requirejs-tpl-jcbrand/tpl",
diff --git a/src/build-no-otr.js b/src/build-no-otr.js
index 46ac70a4c..cad1e9417 100644
--- a/src/build-no-otr.js
+++ b/src/build-no-otr.js
@@ -29,6 +29,7 @@
"ru": "locale/ru/LC_MESSAGES/ru",
"zh": "locale/zh/LC_MESSAGES/zh",
"jquery.browser": "components/jquery.browser/dist/jquery.browser",
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"underscore": "components/underscore/underscore",
"backbone": "components/backbone/backbone",
"backbone.browserStorage": "components/backbone.browserStorage/backbone.browserStorage",
diff --git a/src/build-website-no-otr.js b/src/build-website-no-otr.js
index 566e2b093..e4a5d4293 100644
--- a/src/build-website-no-otr.js
+++ b/src/build-website-no-otr.js
@@ -29,6 +29,7 @@
"ru": "locale/ru/LC_MESSAGES/ru",
"zh": "locale/zh/LC_MESSAGES/zh",
"jquery.browser": "components/jquery.browser/dist/jquery.browser",
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"underscore": "components/underscore/underscore",
"backbone": "components/backbone/backbone",
"backbone.browserStorage": "components/backbone.browserStorage/backbone.browserStorage",
diff --git a/src/build-website.js b/src/build-website.js
index 12ce240b8..145c5303b 100644
--- a/src/build-website.js
+++ b/src/build-website.js
@@ -35,6 +35,7 @@
"backbone.overview": "components/backbone.overview/backbone.overview",
"bootstrap": "components/bootstrap/dist/js/bootstrap", // XXX: Only required for https://conversejs.org website
"jquery.easing": "components/jquery-easing-original/jquery.easing.1.3", // XXX: Only required for https://conversejs.org website
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"strophe": "components/strophe/strophe",
"strophe.muc": "components/strophe.muc/index",
"strophe.roster": "components/strophe.roster/index",
diff --git a/src/build.js b/src/build.js
index d6fff153a..f7429e605 100644
--- a/src/build.js
+++ b/src/build.js
@@ -29,6 +29,7 @@
"ru": "locale/ru/LC_MESSAGES/ru",
"zh": "locale/zh/LC_MESSAGES/zh",
"jquery.browser": "components/jquery.browser/dist/jquery.browser",
+ "jquery.fastLiveFilter": "src/jquery.fastLiveFilter",
"underscore": "components/underscore/underscore",
"backbone": "components/backbone/backbone",
"backbone.browserStorage": "components/backbone.browserStorage/backbone.browserStorage",
diff --git a/src/deps-full.js b/src/deps-full.js
index feade1432..16e0b5992 100644
--- a/src/deps-full.js
+++ b/src/deps-full.js
@@ -5,6 +5,7 @@ define("converse-dependencies", [
"backbone.browserStorage",
"backbone.overview",
"jquery.browser",
+ "jquery.fastLiveFilter",
"strophe",
"strophe.muc",
"strophe.roster",
diff --git a/src/deps-no-otr.js b/src/deps-no-otr.js
index d987c2815..25eefccd0 100644
--- a/src/deps-no-otr.js
+++ b/src/deps-no-otr.js
@@ -4,6 +4,7 @@ define("converse-dependencies", [
"backbone.browserStorage",
"backbone.overview",
"jquery.browser",
+ "jquery.fastLiveFilter",
"strophe",
"strophe.muc",
"strophe.roster",
diff --git a/src/deps-website-no-otr.js b/src/deps-website-no-otr.js
index 01623ace3..5013417fd 100644
--- a/src/deps-website-no-otr.js
+++ b/src/deps-website-no-otr.js
@@ -6,6 +6,7 @@ define("converse-dependencies", [
"backbone.overview",
"jquery.browser",
"jquery.easing", // XXX: Can be removed, only for https://conversejs.org
+ "jquery.fastLiveFilter",
"strophe",
"strophe.muc",
"strophe.roster",
diff --git a/src/deps-website.js b/src/deps-website.js
index a7f2b77a2..aae33edaf 100644
--- a/src/deps-website.js
+++ b/src/deps-website.js
@@ -2,11 +2,12 @@ define("converse-dependencies", [
"otr",
"moment",
"locales",
- "bootstrap", // XXX: Can be removed, only for https://conversejs.org
+ "bootstrap", // XXX: Only for https://conversejs.org
"backbone.browserStorage",
"backbone.overview",
"jquery.browser",
- "jquery.easing", // XXX: Can be removed, only for https://conversejs.org
+ "jquery.easing", // XXX: Only for https://conversejs.org
+ "jquery.fastLiveFilter",
"strophe",
"strophe.muc",
"strophe.roster",
diff --git a/src/jquery.fastLiveFilter.js b/src/jquery.fastLiveFilter.js
new file mode 100644
index 000000000..935cff239
--- /dev/null
+++ b/src/jquery.fastLiveFilter.js
@@ -0,0 +1,59 @@
+/**
+ * fastLiveFilter jQuery plugin 1.0.3
+ *
+ * Copyright (c) 2011, Anthony Bush
+ * License:
+ * Project Website: http://anthonybush.com/projects/jquery_fast_live_filter/
+ **/
+
+jQuery.fn.liveFilter = function(list, options) {
+ // Options: input, list, timeout, callback
+ options = options || {};
+ var input = this;
+ var lastFilter = '';
+ var timeout = options.timeout || 0;
+ var callback = options.callback || function() {};
+ var keyTimeout;
+ callback(); // do a one-time callback on initialization to make sure everything's in sync
+
+ input.change(function() {
+ var $list = jQuery(list);
+ var lis = $list.children();
+ var len = lis.length;
+ var filter = input.val().toLowerCase();
+ if (filter.length > 0) {
+ $list.find(options.hide).hide();
+ } else {
+ $list.find(options.hide).show();
+ }
+ var li, innerText;
+ var numShown = 0;
+ for (var i = 0; i < len; i++) {
+ li = lis[i];
+ innerText = !options.selector ?
+ (li.textContent || li.innerText || "") :
+ $(li).find(options.selector).text();
+
+ if (innerText.toLowerCase().indexOf(filter) >= 0) {
+ if (li.style.display == "none") {
+ $(li).show();
+ }
+ numShown++;
+ } else {
+ if (li.style.display != "none") {
+ $(li).hide();
+ }
+ }
+ }
+ callback(numShown);
+ return false;
+ }).keydown(function() {
+ clearTimeout(keyTimeout);
+ keyTimeout = setTimeout(function() {
+ if( input.val() === lastFilter ) return;
+ lastFilter = input.val();
+ input.change();
+ }, timeout);
+ });
+ return this; // maintain jQuery chainability
+};
diff --git a/src/templates.js b/src/templates.js
index fa82944ab..9bf5c0b43 100644
--- a/src/templates.js
+++ b/src/templates.js
@@ -32,6 +32,7 @@ define("converse-templates", [
"tpl!src/templates/room_description",
"tpl!src/templates/room_item",
"tpl!src/templates/room_panel",
+ "tpl!src/templates/roster",
"tpl!src/templates/roster_item",
"tpl!src/templates/select_option",
"tpl!src/templates/status_option",
@@ -73,11 +74,12 @@ define("converse-templates", [
room_description: arguments[30],
room_item: arguments[31],
room_panel: arguments[32],
- roster_item: arguments[33],
- select_option: arguments[34],
- status_option: arguments[35],
- toggle_chats: arguments[36],
- toolbar: arguments[37],
- trimmed_chat: arguments[38]
+ roster: arguments[33],
+ roster_item: arguments[34],
+ select_option: arguments[35],
+ status_option: arguments[36],
+ toggle_chats: arguments[37],
+ toolbar: arguments[38],
+ trimmed_chat: arguments[39]
};
});
diff --git a/src/templates/roster.html b/src/templates/roster.html
new file mode 100644
index 000000000..0940b1516
--- /dev/null
+++ b/src/templates/roster.html
@@ -0,0 +1,2 @@
+
+