From 1441f4ab64336c0be0c9b99dee1f80171b54c29e Mon Sep 17 00:00:00 2001 From: JC Brand Date: Thu, 7 Aug 2014 21:27:42 +0200 Subject: [PATCH] Add text input to act as live filter. updates #212 --- converse.js | 18 ++- css/converse.css | 18 +-- docs/CHANGES.rst | 10 +- less/converse.less | 18 +-- main.js | 2 + mockup/controlbox.html | 259 +++++++++++++++++---------------- src/build-no-locales-no-otr.js | 1 + src/build-no-otr.js | 1 + src/build-website-no-otr.js | 1 + src/build-website.js | 1 + src/build.js | 1 + src/deps-full.js | 1 + src/deps-no-otr.js | 1 + src/deps-website-no-otr.js | 1 + src/deps-website.js | 5 +- src/jquery.fastLiveFilter.js | 59 ++++++++ src/templates.js | 14 +- src/templates/roster.html | 2 + 18 files changed, 250 insertions(+), 163 deletions(-) create mode 100644 src/jquery.fastLiveFilter.js create mode 100644 src/templates/roster.html 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 - - -
+
+ +
+
+ Colleagues +
+
+ + + Victor Matfield + + +
+
+ + + William Winterbottom + + +
+
+ + + Gary Teichmann + + +
-
- Family -
-
- - - Allan Donald - - -
-
- - - Corné Krige - - -
+
+ Family +
+
+ + + Allan Donald + + +
+
+ + + Corné Krige + + +
-
- Friends -
-
- - - John Smit - - -
-
- - - Bakkies Botha - - -
+
+ Friends +
+
+ + + John Smit + + +
+
+ + + Bakkies Botha + + +
-
- Ungrouped -
-
- - - James Small - - -
+
+ Ungrouped +
+
+ + + James Small + + +
-
- Contact Requests -
-
- Bob Skinstad - - - - -
-
- André Vos - - - - -
+
+ Contact Requests +
+
+ Bob Skinstad + + + + +
+
+ André Vos + + + + +
-
- Pending Contacts -
-
Rassie Erasmus - -
-
Victor Matfield - -
-
-
-
+ + 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 @@ + +