瀏覽代碼

Remove controlbox tabs and show rooms and contacts panels together

JC Brand 7 年之前
父節點
當前提交
ede21e7c32

+ 7 - 4
css/converse.css

@@ -5722,17 +5722,17 @@ body.reset {
     display: block;
     font-weight: normal;
     margin: 1em 0; }
-  #conversejs #controlbox #chatrooms, #conversejs #controlbox #contacts {
-    margin-top: 0.75em;
-    padding-bottom: 0.75em; }
   #conversejs #controlbox .controlbox-pane .userinfo {
     padding-bottom: 1em;
     border-bottom: 1px solid #818479; }
     #conversejs #controlbox .controlbox-pane .userinfo .username {
-      margin-left: 0.5em; }
+      margin-left: 0.5em;
+      overflow: hidden;
+      text-overflow: ellipsis; }
     #conversejs #controlbox .controlbox-pane .userinfo .d-flex {
       margin-bottom: 0.2em; }
   #conversejs #controlbox #chatrooms {
+    padding: 0;
     border-bottom: 1px solid #818479; }
     #conversejs #controlbox #chatrooms form.add-chatroom {
       margin: 0;
@@ -5827,6 +5827,9 @@ body.reset {
           padding: 0.3em 0;
           clear: left;
           width: 100%; }
+  #conversejs #controlbox #chatrooms, #conversejs #controlbox #converse-roster {
+    margin-top: 0.75em;
+    padding-bottom: 0.75em; }
   #conversejs #controlbox .dropdown a {
     width: 143px;
     display: inline-block; }

+ 7 - 4
css/inverse.css

@@ -5794,17 +5794,17 @@ body {
     display: block;
     font-weight: normal;
     margin: 1em 0; }
-  #conversejs #controlbox #chatrooms, #conversejs #controlbox #contacts {
-    margin-top: 0.75em;
-    padding-bottom: 0.75em; }
   #conversejs #controlbox .controlbox-pane .userinfo {
     padding-bottom: 1em;
     border-bottom: 1px solid #818479; }
     #conversejs #controlbox .controlbox-pane .userinfo .username {
-      margin-left: 0.5em; }
+      margin-left: 0.5em;
+      overflow: hidden;
+      text-overflow: ellipsis; }
     #conversejs #controlbox .controlbox-pane .userinfo .d-flex {
       margin-bottom: 0.2em; }
   #conversejs #controlbox #chatrooms {
+    padding: 0;
     border-bottom: 1px solid #818479; }
     #conversejs #controlbox #chatrooms form.add-chatroom {
       margin: 0;
@@ -5899,6 +5899,9 @@ body {
           padding: 0.3em 0;
           clear: left;
           width: 100%; }
+  #conversejs #controlbox #chatrooms, #conversejs #controlbox #converse-roster {
+    margin-top: 0.75em;
+    padding-bottom: 0.75em; }
   #conversejs #controlbox .dropdown a {
     width: 143px;
     display: inline-block; }

+ 1 - 1
mockup/converse.html

@@ -24,7 +24,7 @@
                 </div>
             </div>
 
-            <div class="chatbox col col col-lg-2 col-md-3 col-sm-4 col-sx-12 w-100" id="chatbox-37c0c87392010303765fe36b05c0967d62c6b70f">
+            <div class="chatbox col col-lg-2 col-md-3 col-sm-4 col-sx-12 w-100" id="chatbox-37c0c87392010303765fe36b05c0967d62c6b70f">
                 <div class="flyout box-flyout">
 
                     <div class="chat-head chat-head-chatbox row no-gutters">

+ 107 - 109
mockup/user-panel.html

@@ -16,7 +16,7 @@
 <div id="chatrooms">
     <div class="d-flex">
         <span class="w-100">Chatrooms</span>
-        <a class="chatbox-btn fa fa-users" title="Click to change rooms" data-toggle="modal" data-target="#chatroomsModal"></a>
+        <a class="chatbox-btn fa fa-users" title="Click to add a new room" data-toggle="modal" data-target="#chatroomsModal"></a>
     </div>
     <div class="list-container rooms-list-container">
         <div class="rooms-list">
@@ -42,123 +42,121 @@
 </div>
 
 <div id="converse-roster">
-    <div id="contacts">
-        <div class="d-flex">
-            <span class="w-100">Contacts</span>
-            <a class="chatbox-btn fa fa-user-plus" title="Click to add new chat contacts" data-toggle="modal" data-target="#addContactModal"></a>
-        </div>
-        <form class="pure-form roster-filter-form input-button-group">
-            <div class="form-group form-inline">
-                <input value="" class="roster-filter form-control" placeholder="Filter">
-                <div class="filter-by">
-                    <span class="fa fa-user" title="Filter by contacts"></span>
-                    <span class="fa fa-users" title="Filter by groups"></span>
-                    <span class="fa fa-circle" title="Filter by status"></span>
-                </div>
+    <div class="d-flex">
+        <span class="w-100">Contacts</span>
+        <a class="chatbox-btn fa fa-user-plus" title="Click to add new chat contacts" data-toggle="modal" data-target="#addContactModal"></a>
+    </div>
+    <form class="pure-form roster-filter-form input-button-group">
+        <div class="form-group form-inline">
+            <input value="" class="roster-filter form-control" placeholder="Filter">
+            <div class="filter-by">
+                <span class="fa fa-user" title="Filter by contacts"></span>
+                <span class="fa fa-users" title="Filter by groups"></span>
+                <span class="fa fa-circle" title="Filter by status"></span>
             </div>
-        </form>
+        </div>
+    </form>
 
-        <div class="roster-contacts">
-            <div class="roster-group" id="xmpp-contact-requests">
-                <a href="#" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Contact Requests</a>
-                <ul>
-                    <li class="offline requesting-xmpp-contact d-flex">
-                        <span class="req-contact-name w-100">Bob Skinstad</span>
-                        <a class="accept-xmpp-request fa fa-check align-self-center" title="Click here to accept this contact's request" href="#"></a>
-                        <a class="decline-xmpp-request fa fa-times align-self-center" title="Click here to decline this contact's request" href="#"></a>
-                    </li>
-                    <li class="offline requesting-xmpp-contact d-flex">
-                        <span class="req-contact-name w-100">André Vos</span>
-                        <a class="accept-xmpp-request fa fa-check align-self-center" title="Click here to accept this contact's request" href="#"></a>
-                        <a class="decline-xmpp-request fa fa-times align-self-center" title="Click here to decline this contact's request" href="#"></a>
-                    </li>
-                </ul>
-            </div>
+    <div class="roster-contacts">
+        <div class="roster-group" id="xmpp-contact-requests">
+            <a href="#" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Contact Requests</a>
+            <ul>
+                <li class="offline requesting-xmpp-contact d-flex">
+                    <span class="req-contact-name w-100">Bob Skinstad</span>
+                    <a class="accept-xmpp-request fa fa-check align-self-center" title="Click here to accept this contact's request" href="#"></a>
+                    <a class="decline-xmpp-request fa fa-times align-self-center" title="Click here to decline this contact's request" href="#"></a>
+                </li>
+                <li class="offline requesting-xmpp-contact d-flex">
+                    <span class="req-contact-name w-100">André Vos</span>
+                    <a class="accept-xmpp-request fa fa-check align-self-center" title="Click here to accept this contact's request" href="#"></a>
+                    <a class="decline-xmpp-request fa fa-times align-self-center" title="Click here to decline this contact's request" href="#"></a>
+                </li>
+            </ul>
+        </div>
 
-            <div class="roster-group" data-group="Colleagues">
-                <a href="#" data-group="Colleagues" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Colleagues</a>
+        <div class="roster-group" data-group="Colleagues">
+            <a href="#" data-group="Colleagues" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Colleagues</a>
 
-                <ul>
-                    <li class="online current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle" title="This contact is online"></span> Victor Matfield</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                    <li class="away current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle-o" title="this contact is away"></span> William Winterbottom</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                    <li class="dnd current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-minus-circle" title="This contact is busy"></span> Gary Teichmann</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
+            <ul>
+                <li class="online current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle" title="This contact is online"></span> Victor Matfield</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
                 </li>
-            </div>
+                <li class="away current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle-o" title="this contact is away"></span> William Winterbottom</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+                <li class="dnd current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-minus-circle" title="This contact is busy"></span> Gary Teichmann</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+            </li>
+        </div>
 
-            <div class="roster-group" data-group="Family">
-                <a href="#" data-group="Family" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Family</a>
-                <ul>
-                    <li class="away current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle-o" title="this contact is away"></span> Allan Donald</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                    <li class="offline current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-times-circle" title="This contact is offline"></span> Corné Krige</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                </ul>
-            </div>
+        <div class="roster-group" data-group="Family">
+            <a href="#" data-group="Family" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Family</a>
+            <ul>
+                <li class="away current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle-o" title="this contact is away"></span> Allan Donald</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+                <li class="offline current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-times-circle" title="This contact is offline"></span> Corné Krige</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+            </ul>
+        </div>
 
-            <div class="roster-group" data-group="Friends">
-                <a href="#" data-group="Friends" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Friends</a>
-                <ul>
-                    <li class="online current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle" title="This contact is online"></span> John Smit</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                    <li class="online current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle" title="This contact is online"></span> Bakkies Botha</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                </ul>
-            </div>
+        <div class="roster-group" data-group="Friends">
+            <a href="#" data-group="Friends" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Friends</a>
+            <ul>
+                <li class="online current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle" title="This contact is online"></span> John Smit</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+                <li class="online current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle" title="This contact is online"></span> Bakkies Botha</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+            </ul>
+        </div>
 
-            <div class="roster-group" data-group="Ungrouped">
-                <a href="#" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Ungrouped</a>
-                <ul>
-                    <li class="online current-xmpp-contact d-flex">
-                        <a class="open-chat w-100" title="Click to chat with this contact" href="#">
-                            <span class="fa fa-circle" title="This contact is online"></span> James Small</a>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                </ul>
-            </div>
+        <div class="roster-group" data-group="Ungrouped">
+            <a href="#" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Ungrouped</a>
+            <ul>
+                <li class="online current-xmpp-contact d-flex">
+                    <a class="open-chat w-100" title="Click to chat with this contact" href="#">
+                        <span class="fa fa-circle" title="This contact is online"></span> James Small</a>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+            </ul>
+        </div>
 
-            <div class="roster-group" id="pending-xmpp-contacts">
-                <a href="#" class="group-toggle" title="Click to hide these contacts">
-                    <span class="fa fa-caret-down"></span> Pending Contacts</a>
-                <ul>
-                    <li class="offline pending-xmpp-contact d-flex">
-                        <span class="pending-contact-name w-100">Rassie Erasmus</span>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                    <li class="offline pending-xmpp-contact d-flex">
-                        <span class="pending-contact-name w-100">Victor Matfield</span>
-                        <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
-                    </li>
-                </ul>
-            </div>
+        <div class="roster-group" id="pending-xmpp-contacts">
+            <a href="#" class="group-toggle" title="Click to hide these contacts">
+                <span class="fa fa-caret-down"></span> Pending Contacts</a>
+            <ul>
+                <li class="offline pending-xmpp-contact d-flex">
+                    <span class="pending-contact-name w-100">Rassie Erasmus</span>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+                <li class="offline pending-xmpp-contact d-flex">
+                    <span class="pending-contact-name w-100">Victor Matfield</span>
+                    <a class="remove-xmpp-contact fa fa-trash align-self-center" title="Click to remove this contact" href="#"></a>
+                </li>
+            </ul>
         </div>
     </div>
 </div>

+ 8 - 5
sass/_controlbox.scss

@@ -157,11 +157,6 @@
 
         }
 
-        #chatrooms, #contacts {
-            margin-top: 0.75em;
-            padding-bottom: 0.75em;
-        }
-
         .controlbox-pane {
             .userinfo {
                 padding-bottom: 1em;
@@ -169,6 +164,8 @@
 
                 .username {
                     margin-left: 0.5em;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
                 }
                 .d-flex {
                     margin-bottom: 0.2em;
@@ -177,6 +174,7 @@
         }
 
         #chatrooms {
+            padding: 0;
             border-bottom: 1px solid $gray-color;
 
             form.add-chatroom {
@@ -284,6 +282,11 @@
             }
         }
 
+        #chatrooms, #converse-roster {
+            margin-top: 0.75em;
+            padding-bottom: 0.75em;
+        }
+
         .dropdown {
             a {
                 width: 143px;

+ 16 - 4
src/converse-chatview.js

@@ -304,6 +304,7 @@
                 },
 
                 render () {
+                    this.setClasses();
                     this.el.setAttribute('id', this.model.get('box_id'));
                     this.el.innerHTML = tpl_chatbox(
                         _.extend(this.model.toJSON(), {
@@ -316,6 +317,20 @@
                     return this;
                 },
 
+                setClasses () {
+                    if (_converse.view_mode === 'fullscreen') {
+                        this.el.classList.add('col-xl-10');
+                        this.el.classList.add('col-md-9');
+                    } else {
+                        this.el.classList.add('col');
+                        this.el.classList.add('col-lg-2');
+                        this.el.classList.add('col-md-3');
+                        this.el.classList.add('col-sm-4');
+                        this.el.classList.add('col-sx-12');
+                        this.el.classList.add('w-100');
+                    }
+                },
+
                 renderToolbar (toolbar, options) {
                     if (!_converse.show_toolbar) {
                         return this;
@@ -431,10 +446,7 @@
                      * as well as src/converse-muc.js (if those plugins are
                      * enabled).
                      */
-                    const container = _converse.root.querySelector('#conversejs');
-                    if (this.el.parentNode !== container) {
-                        container.insertBefore(this.el, container.firstChild);
-                    }
+                    _converse.chatboxviews.insertRowColumn(this.el);
                     return this;
                 },
 

+ 35 - 106
src/converse-controlbox.js

@@ -12,8 +12,6 @@
             "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",
@@ -28,8 +26,6 @@
             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,
@@ -37,7 +33,6 @@
         ) {
     "use strict";
 
-    const USERS_PANEL_ID = 'users';
     const CHATBOX_TYPE = 'chatbox';
     const { Strophe, Backbone, Promise, _, moment } = converse.env;
     const u = converse.env.utils;
@@ -91,7 +86,7 @@
          *
          * NB: These plugins need to have already been loaded via require.js.
          */
-        dependencies: ["converse-chatboxes"],
+        dependencies: ["converse-chatboxes", "converse-rosterview"],
 
         overrides: {
             // Overrides mentioned here will be picked up by converse.js's
@@ -201,6 +196,7 @@
             },
 
             ChatBoxView: {
+
                 insertIntoDOM () {
                     const view = this.__super__._converse.chatboxviews.get("controlbox");
                     if (view) {
@@ -248,15 +244,15 @@
                 className: 'chatbox',
                 id: 'controlbox',
                 events: {
-                    'click a.close-chatbox-button': 'close',
-                    'click ul#controlbox-tabs li a': 'switchTab',
+                    'click a.close-chatbox-button': 'close'
                 },
 
                 initialize () {
                     if (_.isUndefined(_converse.controlboxtoggle)) {
                         _converse.controlboxtoggle = new _converse.ControlBoxToggle();
-                        _converse.controlboxtoggle.el.insertAdjacentElement('afterend', this.el);
                     }
+                    _converse.controlboxtoggle.el.insertAdjacentElement('afterend', this.el);
+
                     this.model.on('change:connected', this.onConnected, this);
                     this.model.on('destroy', this.hide, this);
                     this.model.on('hide', this.hide, this);
@@ -277,23 +273,23 @@
                             this.model.set('closed', !_converse.show_controlbox_by_default);
                         }
                     }
-                    if (!this.model.get('closed')) {
-                        this.show();
-                    } else {
-                        this.hide();
-                    }
                     this.el.innerHTML = tpl_controlbox(
                         _.extend(this.model.toJSON(), {
                             'sticky_controlbox': _converse.sticky_controlbox
                         }));
 
+                    if (!this.model.get('closed')) {
+                        this.show();
+                    } else {
+                        this.hide();
+                    }
                     if (!_converse.connection.connected ||
                             !_converse.connection.authenticated ||
                             _converse.connection.disconnecting) {
                         this.renderLoginPanel();
                     } else if (this.model.get('connected') &&
-                            (!this.contactspanel || !u.isVisible(this.contactspanel.el))) {
-                        this.renderContactsPanel();
+                            (!this.controlbox_pane || !u.isVisible(this.controlbox_pane.el))) {
+                        this.renderControlBoxPane();
                     }
                     return this;
                 },
@@ -310,7 +306,7 @@
 
                 insertRoster () {
                     /* Place the rosterview inside the "Contacts" panel. */
-                    this.contactspanel.el.insertAdjacentElement(
+                    this.controlbox_pane.el.insertAdjacentElement(
                         'beforeEnd',
                         _converse.rosterview.el
                     );
@@ -333,6 +329,8 @@
 
                 renderLoginPanel () {
                     this.el.classList.add("logged-out");
+                    this.el.classList.remove("col-xl-2");
+                    this.el.classList.remove("col-md-3");
                     if (_.isNil(this.loginpanel)) {
                         this.loginpanel = new _converse.LoginPanel({
                             'model': new _converse.LoginPanelModel()
@@ -347,7 +345,7 @@
                     return this;
                 },
 
-                renderContactsPanel () {
+                renderControlBoxPane () {
                     /* Renders the "Contacts" panel of the controlbox.
                      *
                      * This will only be called after the user has already been
@@ -358,19 +356,14 @@
                         delete this.loginpanel;
                     }
                     this.el.classList.remove("logged-out");
+                    this.el.classList.add("col-xl-2");
+                    this.el.classList.add("col-md-3");
 
-                    if (_.isUndefined(this.model.get('active-panel'))) {
-                        this.model.save({'active-panel': USERS_PANEL_ID});
-                    }
-                    this.contactspanel = new _converse.ContactsPanel({
-                        'parent_el': this.el.querySelector('.controlbox-panes')
-                    });
-                    this.contactspanel.insertIntoDOM();
-
-                    _converse.xmppstatusview = new _converse.XMPPStatusView({
-                        'model': _converse.xmppstatus
-                    });
-                    _converse.xmppstatusview.render();
+                    this.controlbox_pane = new _converse.ControlBoxPane();
+                    this.el.querySelector('.controlbox-panes').insertAdjacentElement(
+                        'afterBegin',
+                        this.controlbox_pane.el
+                    )
                 },
 
                 close (ev) {
@@ -421,24 +414,6 @@
                     return this;
                 },
 
-                switchTab (ev) {
-                    if (ev && ev.preventDefault) { ev.preventDefault(); }
-                    const tab = ev.target,
-                        sibling_li = tab.parentNode.nextElementSibling || tab.parentNode.previousElementSibling,
-                        sibling = sibling_li.firstChild,
-                        sibling_panel = _converse.root.querySelector(sibling.getAttribute('href')),
-                        tab_panel = _converse.root.querySelector(tab.getAttribute('href'));
-
-                    u.hideElement(sibling_panel);
-                    u.removeClass('current', sibling);
-                    u.addClass('current', tab);
-                    u.removeClass('hidden', tab_panel);
-                    if (!_.isUndefined(_converse.chatboxes.browserStorage)) {
-                        this.model.save({'active-panel': tab.getAttribute('data-id')});
-                    }
-                    return this;
-                },
-
                 showHelpMessages () {
                     /* Override showHelpMessages in ChatBoxView, for now do nothing.
                      *
@@ -553,10 +528,9 @@
             });
 
 
-            _converse.ContactsPanel = Backbone.NativeView.extend({
+            _converse.ControlBoxPane = Backbone.NativeView.extend({
                 tagName: 'div',
                 className: 'controlbox-pane',
-                id: 'users',
                 events: {
                     'click a.toggle-xmpp-contact-form': 'toggleContactForm',
                     'submit form.add-xmpp-contact': 'addContactFromForm',
@@ -564,57 +538,14 @@
                     'click a.subscribe-to-user': 'addContactFromList'
                 },
 
-                initialize (cfg) {
-                    this.parent_el = cfg.parent_el;
-                    this.tab_el = document.createElement('li');
-                    _converse.chatboxes.on('change:num_unread', this.renderTab, this);
-                    _converse.chatboxes.on('add', _.debounce(this.renderTab, 100), this);
-                },
-
-                render () {
-                    this.renderTab();
-                    let widgets = tpl_contacts_panel({
-                        label_online: __('Online'),
-                        label_busy: __('Busy'),
-                        label_away: __('Away'),
-                        label_offline: __('Offline'),
-                        label_logout: __('Log out'),
-                        include_offline_state: _converse.include_offline_state,
-                        allow_logout: _converse.allow_logout
-                    });
-                    if (_converse.allow_contact_requests) {
-                        widgets += tpl_add_contact_dropdown({
-                            label_click_to_chat: __('Click to add new chat contacts'),
-                            label_add_contact: __('Add a contact')
-                        });
-                    }
-                    this.el.innerHTML = widgets;
-
-                    const controlbox = _converse.chatboxes.get('controlbox');
-                    if (controlbox.get('active-panel') !== USERS_PANEL_ID) {
-                        this.el.classList.add('hidden');
-                    }
-                    return this;
-                },
-
-                renderTab () {
-                    const controlbox = _converse.chatboxes.get('controlbox');
-                    if (_.isNil(controlbox)) {
-                        return;
-                    }
-                    const chats = fp.filter(_.partial(u.isOfType, CHATBOX_TYPE), _converse.chatboxes.models);
-                    this.tab_el.innerHTML = tpl_contacts_tab({
-                        'label_contacts': LABEL_CONTACTS,
-                        'is_current': controlbox.get('active-panel') === USERS_PANEL_ID,
-                        'num_unread': fp.sum(fp.map(fp.curry(u.getAttribute)('num_unread'), chats))
+                initialize () {
+                    _converse.xmppstatusview = new _converse.XMPPStatusView({
+                        'model': _converse.xmppstatus
                     });
-                },
-
-                insertIntoDOM () {
-                    this.parent_el.appendChild(this.render().el);
-                    this.tabs = this.parent_el.parentNode.querySelector('#controlbox-tabs');
-                    this.tabs.appendChild(this.tab_el);
-                    return this;
+                    this.el.insertAdjacentElement(
+                        'afterBegin',
+                        _converse.xmppstatusview.render().el
+                    );
                 },
 
                 generateAddContactHTML (settings={}) {
@@ -728,11 +659,10 @@
                 },
 
                 initialize () {
-                    _converse.chatboxviews.el.insertAdjacentElement('afterBegin', this.render().el);
-                    const that = this;
-                    _converse.api.waitUntil('initialized').then(() => {
-                        this.render();
-                    }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+                    _converse.chatboxviews.insertRowColumn(this.render().el);
+                    _converse.api.waitUntil('initialized')
+                        .then(this.render.bind(this))
+                        .catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
                 },
 
                 render () {
@@ -796,7 +726,6 @@
                  */
                 const view = _converse.chatboxviews.get('controlbox');
                 view.model.set({connected:false});
-                view.el.querySelector('#controlbox-tabs').innerHTML = '';
                 view.renderLoginPanel();
             };
             _converse.on('disconnected', disconnect);

+ 2 - 2
src/converse-dragresize.js

@@ -312,8 +312,8 @@
                     return result;
                 },
 
-                renderContactsPanel () {
-                    const result = this.__super__.renderContactsPanel.apply(this, arguments);
+                renderControlBoxPane () {
+                    const result = this.__super__.renderControlBoxPane.apply(this, arguments);
                     this.initDragResize().setDimensions();
                     return result;
                 }

+ 28 - 44
src/converse-muc.js

@@ -26,7 +26,6 @@
             "tpl!chatroom_password_form",
             "tpl!chatroom_sidebar",
             "tpl!chatroom_toolbar",
-            "tpl!chatrooms_tab",
             "tpl!info",
             "tpl!occupant",
             "tpl!room_description",
@@ -57,7 +56,6 @@
             tpl_chatroom_password_form,
             tpl_chatroom_sidebar,
             tpl_chatroom_toolbar,
-            tpl_chatrooms_tab,
             tpl_info,
             tpl_occupant,
             tpl_room_description,
@@ -69,7 +67,6 @@
     ) {
 
     "use strict";
-    const ROOMS_PANEL_ID = 'chatrooms';
     const CHATROOMS_TYPE = 'chatroom';
 
     const MUC_ROLE_WEIGHTS = {
@@ -160,17 +157,21 @@
             },
 
             ControlBoxView: {
+
                 renderRoomsPanel () {
                     const { _converse } = this.__super__;
                     this.roomspanel = new _converse.RoomsPanel({
-                        'parent': this.el.querySelector('.controlbox-panes'),
                         'model': new (_converse.RoomsPanelModel.extend({
                             id: b64_sha1(`converse.roomspanel${_converse.bare_jid}`), // Required by sessionStorage
                             browserStorage: new Backbone.BrowserStorage[_converse.storage](
                                 b64_sha1(`converse.roomspanel${_converse.bare_jid}`))
                         }))()
                     });
-                    this.roomspanel.insertIntoDOM().model.fetch();
+                    this.roomspanel.model.fetch();
+
+                    this.el.querySelector('.controlbox-pane').insertAdjacentElement(
+                        'beforeEnd', this.roomspanel.render().el);
+
                     if (!this.roomspanel.model.get('nick')) {
                         this.roomspanel.model.save({
                             nick: Strophe.getNodeFromJid(_converse.bare_jid)
@@ -179,9 +180,9 @@
                     _converse.emit('roomsPanelRendered');
                 },
 
-                renderContactsPanel () {
+                renderControlBoxPane () {
                     const { _converse } = this.__super__;
-                    this.__super__.renderContactsPanel.apply(this, arguments);
+                    this.__super__.renderControlBoxPane.apply(this, arguments);
                     if (_converse.allow_muc) {
                         this.renderRoomsPanel();
                     }
@@ -470,6 +471,7 @@
                 },
 
                 render () {
+                    this.setClasses();
                     this.el.setAttribute('id', this.model.get('box_id'));
                     this.el.innerHTML = tpl_chatroom();
                     this.renderHeading();
@@ -480,6 +482,20 @@
                     return this;
                 },
 
+                setClasses () {
+                    if (_converse.view_mode === 'fullscreen') {
+                        this.el.classList.add('col-xl-10');
+                        this.el.classList.add('col-md-9');
+                    } else {
+                        this.el.classList.add('col');
+                        this.el.classList.add('col-lg-4');
+                        this.el.classList.add('col-md-6');
+                        this.el.classList.add('col-sm-8');
+                        this.el.classList.add('col-sx-12');
+                        this.el.classList.add('w-100');
+                    }
+                },
+
                 renderHeading () {
                     /* Render the heading UI of the chat room. */
                     this.el.querySelector('.chat-head-chatroom').innerHTML = this.generateHeadingHTML();
@@ -2556,11 +2572,9 @@
             });
 
             _converse.RoomsPanel = Backbone.NativeView.extend({
-                /* Backbone.NativeView which renders the "Rooms" tab and accompanying
-                 * panel in the control box.
+                /* Backbone.NativeView which renders MUC section of the control box.
                  *
-                 * In this panel, chat rooms can be listed, joined and new rooms
-                 * can be created.
+                 * Chat rooms can be listed, joined and new rooms can be created.
                  */
                 tagName: 'div',
                 className: 'controlbox-pane',
@@ -2576,46 +2590,16 @@
 
                 initialize (cfg) {
                     this.join_form = new _converse.MUCJoinForm({'model': this.model});
-                    this.parent_el = cfg.parent;
-                    this.tab_el = document.createElement('li');
                     this.model.on('change:muc_domain', this.onDomainChange, this);
                     this.model.on('change:nick', this.onNickChange, this);
-                    _converse.chatboxes.on('change:num_unread', this.renderTab, this);
-                    _converse.chatboxes.on('add', _.debounce(this.renderTab, 100), this);
                 },
 
                 render () {
-                    this.el.innerHTML = tpl_room_panel();
+                    this.el.innerHTML = tpl_room_panel({
+                        'title_new_room': __('Click to add a new room')
+                    });
                     this.join_form.setElement(this.el.querySelector('.add-chatroom'));
                     this.join_form.render();
-
-                    this.renderTab();
-                    const controlbox = _converse.chatboxes.get('controlbox');
-                    if (controlbox.get('active-panel') !== ROOMS_PANEL_ID) {
-                        this.el.classList.add('hidden');
-                    } else {
-                        this.el.classList.remove('hidden');
-                    }
-                    return this;
-                },
-
-                renderTab () {
-                    const controlbox = _converse.chatboxes.get('controlbox');
-                    const chatrooms = fp.filter(
-                        _.partial(u.isOfType, CHATROOMS_TYPE),
-                        _converse.chatboxes.models
-                    );
-                    this.tab_el.innerHTML = tpl_chatrooms_tab({
-                        'label_rooms': __('Rooms'),
-                        'is_current': controlbox.get('active-panel') === ROOMS_PANEL_ID,
-                        'num_unread': fp.sum(fp.map(fp.curry(u.getAttribute)('num_unread'), chatrooms))
-                    });
-                },
-
-                insertIntoDOM () {
-                    this.parent_el.appendChild(this.render().el);
-                    this.tabs = this.parent_el.parentNode.querySelector('#controlbox-tabs');
-                    this.tabs.appendChild(this.tab_el);
                     return this;
                 },
 

+ 16 - 35
src/converse-profile.js

@@ -9,7 +9,7 @@
 (function (root, factory) {
     define(["converse-core",
             "tpl!change_status_message",
-            "tpl!chat_status",
+            "tpl!profile_view",
             "tpl!choose_status",
             "tpl!status_option",
             "converse-vcard"
@@ -17,7 +17,7 @@
 }(this, function (
             converse,
             tpl_change_status_message,
-            tpl_chat_status,
+            tpl_profile_view,
             tpl_choose_status,
             tpl_status_option
         ) {
@@ -35,8 +35,9 @@
             const { _converse } = this,
                 { __ } = _converse;
 
-            _converse.XMPPStatusView = Backbone.NativeView.extend({
-                el: "form#set-xmpp-status",
+
+            _converse.XMPPStatusView = Backbone.VDOMView.extend({
+                tagName: "div",
                 events: {
                     "click a.choose-xmpp-status": "toggleOptions",
                     "click #fancy-xmpp-status-select a.change-xmpp-status-message": "renderStatusChangeForm",
@@ -50,30 +51,17 @@
                     this.model.on("update-status-ui", this.updateStatusUI, this);
                 },
 
-                render () {
-                    // Replace the default dropdown with something nicer
-                    const options = this.el.querySelectorAll('#select-xmpp-status option');
+                toHTML () {
                     const chat_status = this.model.get('status') || 'offline';
-                    this.el.innerHTML = tpl_choose_status();
-
-                    this.el.querySelector('#fancy-xmpp-status-select')
-                        .innerHTML = tpl_chat_status({
-                            'status_message': this.model.get('status_message') ||
-                                              __("I am %1$s", this.getPrettyStatus(chat_status)),
-                            'chat_status': chat_status,
-                            'desc_custom_status': __('Click here to write a custom status message'),
-                            'desc_change_status': __('Click to change your chat status')
-                        });
-
-                    // iterate through all the <option> elements and add option values
-                    const options_list = _.map(
-                        options,
-                        (el) => tpl_status_option({'value': el.value, 'text': el.text })
-                    );
-                    const options_target = this.el.querySelector(".xmpp-status-menu");
-                    options_target.classList.add('collapsed');
-                    options_target.innerHTML = options_list.join('');
-                    return this;
+                    return tpl_profile_view(_.extend(this.model.toJSON(), {
+                        'fullname': this.model.get('fullname') || _converse.bare_jid,
+                        'status_message': this.model.get('status_message') ||
+                                            __("I am %1$s", this.getPrettyStatus(chat_status)),
+                        'chat_status': chat_status,
+                        'title_change_settings': __('Change settings'),
+                        'title_change_status': __('Click to change your chat status'),
+                        'title_your_profile': __('Your profile')
+                    }));
                 },
 
                 toggleOptions (ev) {
@@ -133,14 +121,7 @@
                     // For translators: the %1$s part gets replaced with the status
                     // Example, I am online
                     const status_message = model.get('status_message') || __("I am %1$s", this.getPrettyStatus(stat));
-                    const fancy_select = this.el.querySelector('#fancy-xmpp-status-select');
-                    fancy_select.classList.remove('no-border');
-                    fancy_select.innerHTML = tpl_chat_status({
-                        'chat_status': stat,
-                        'status_message': status_message,
-                        'desc_custom_status': __('Click here to write a custom status message'),
-                        'desc_change_status': __('Click to change your chat status')
-                    });
+                    // TODO
                 }
             });
         }

+ 4 - 4
src/converse-roomslist.js

@@ -131,7 +131,7 @@
 
             _converse.RoomsListView = Backbone.OrderedListView.extend({
                 tagName: 'div',
-                className: 'open-rooms-list rooms-list-container',
+                className: 'open-rooms-list list-container rooms-list-container',
                 events: {
                     'click .add-bookmark': 'addBookmark',
                     'click .close-room': 'closeRoom',
@@ -177,9 +177,9 @@
                     const controlboxview = _converse.chatboxviews.get('controlbox');
                     if (!_.isUndefined(controlboxview) &&
                             !_converse.root.contains(this.el)) {
-                        const container = controlboxview.el.querySelector('#chatrooms');
-                        if (!_.isNull(container)) {
-                            container.insertBefore(this.el, container.firstChild);
+                        const el = controlboxview.el.querySelector('.open-rooms-list');
+                        if (!_.isNull(el)) {
+                            el.parentNode.replaceChild(this.el, el);
                         }
                     }
                 },

+ 14 - 22
src/converse-rosterview.js

@@ -129,7 +129,8 @@
             });
 
             _converse.RosterFilterView = Backbone.VDOMView.extend({
-                tagName: 'span',
+                tagName: 'form',
+                className: 'roster-filter-form',
                 events: {
                     "keydown .roster-filter": "liveFilter",
                     "submit form.roster-filter-form": "submitFilter",
@@ -149,9 +150,9 @@
                         _.extend(this.model.toJSON(), {
                             visible: this.shouldBeVisible(),
                             placeholder: __('Filter'),
-                            label_contacts: LABEL_CONTACTS,
-                            label_groups: LABEL_GROUPS,
-                            label_state: __('State'),
+                            title_contact_filter: __('Filter by contact name'),
+                            title_group_filter: __('Filter by group name'),
+                            title_status_filter: __('Filter by status'),
                             label_any: __('Any'),
                             label_unread_messages: __('Unread'),
                             label_online: __('Online'),
@@ -655,9 +656,14 @@
                 },
 
                 render () {
-                    this.el.innerHTML = "";
-                    this.el.appendChild(this.filter_view.render().el);
-                    this.renderRoster();
+                    this.el.innerHTML = tpl_roster({
+                        'heading_contacts': __('Contacts'),
+                        'title_add_contact': __('Add a contact')
+                    });
+                    const form = this.el.querySelector('.roster-filter-form');
+                    this.el.replaceChild(this.filter_view.render().el, form);
+                    this.roster_el = this.el.querySelector('.roster-contacts');
+
                     if (!_converse.allow_contact_requests) {
                         // XXX: if we ever support live editing of config then
                         // we'll need to be able to remove this class on the fly.
@@ -666,13 +672,6 @@
                     return this;
                 },
 
-                renderRoster () {
-                    const div = document.createElement('div');
-                    div.insertAdjacentHTML('beforeend', tpl_roster());
-                    this.roster_el = div.firstChild;
-                    this.el.insertAdjacentElement('beforeend', this.roster_el);
-                },
-
                 createRosterFilter () {
                     // Create a model on which we can store filter properties
                     const model = new _converse.RosterFilter();
@@ -703,16 +702,9 @@
                     if (!u.isVisible(this.roster_el)) {
                         u.showElement(this.roster_el);
                     }
-                    return this.showHideFilter();
-                }, _converse.animate ? 100 : 0),
-
-                showHideFilter () {
-                    if (!u.isVisible(this.el)) {
-                        return;
-                    }
                     this.filter_view.showOrHide();
                     return this;
-                },
+                }, _converse.animate ? 100 : 0),
 
                 filter (query, type) {
                     // First we make sure the filter is restored to its

+ 0 - 6
src/templates/chat_status.html

@@ -1,6 +0,0 @@
-<div class="xmpp-status">
-    <a class="choose-xmpp-status {{{o.chat_status}}} icon-{{{o.chat_status}}}" data-value="{{{o.status_message}}}" href="#" title="{{{o.desc_change_status}}}">
-        {{{o.status_message}}}
-    </a>
-    <a class="change-xmpp-status-message icon-pencil" href="#" title="{{{o.desc_custom_status}}}"></a>
-</div>

+ 0 - 9
src/templates/chatrooms_tab.html

@@ -1,9 +0,0 @@
-<a class="s rooms-tab
-   {[ if (o.is_current) { ]} current {[ } ]}
-   {[ if (o.num_unread) { ]} unread-msgs {[ } ]}"
-       data-id="chatrooms" href="#chatrooms">
-    {{{o.label_rooms}}}
-    {[ if (o.num_unread) { ]}
-        <span class="msgs-indicator">{{{o. num_unread }}}</span>
-    {[ } ]}
-</a>

+ 0 - 9
src/templates/contacts_tab.html

@@ -1,9 +0,0 @@
-<a class="s contacts-tab
-   {[ if (o.is_current) { ]} current {[ } ]}
-   {[ if (o.num_unread) { ]} unread-msgs {[ } ]}"
-       data-id="users" href="#users">
-    {{{o.label_contacts}}}
-    {[ if (o.num_unread) { ]}
-        <span class="msgs-indicator">{{{ o.num_unread }}}</span>
-    {[ } ]}
-</a>

+ 0 - 1
src/templates/controlbox.html

@@ -1,6 +1,5 @@
 <div class="flyout box-flyout">
     <div class="chat-head controlbox-head">
-        <ul id="controlbox-tabs"></ul>
         {[ if (!o.sticky_controlbox) { ]}
             <a class="chatbox-btn close-chatbox-button icon-close"></a>
         {[ } ]}

+ 0 - 0
src/templates/contacts_panel.html → src/templates/controlbox_pane.html


+ 13 - 0
src/templates/profile_view.html

@@ -0,0 +1,13 @@
+<div class="userinfo">
+<div class="d-flex">
+    <canvas height="20" width="20" class="avatar align-self-center"></canvas>
+    <span class="username w-100 align-self-center">{{{o.fullname}}}</span>
+    <a class="chatbox-btn fa fa-vcard align-self-center" title="{{{o.title_your_profile}}}" data-toggle="modal" data-target="#userProfileModal"></a>
+    <a class="chatbox-btn fa fa-cog align-self-center" title="{{{o.title_change_status}}}" data-toggle="modal" data-target="#settingsModal"></a>
+</div>
+<div class="d-flex xmpp-status">
+    <span class="{{{o.chat_status}}} w-100 align-self-center" data-value="{{{o.chat_status}}}">
+        <span class="fa fa-circle"></span> {{{o.status_message}}}</span>
+    <a class="chatbox-btn fa fa-pencil" title="{{{o.title_change_status}}}" data-toggle="modal" data-target="#changeStatusModal"></a>
+</div>
+</div>

+ 8 - 2
src/templates/room_panel.html

@@ -1,4 +1,10 @@
+<!-- <div id="chatrooms"> -->
 <form class="add-chatroom"></form>
-<div class="list-container rooms-list-container">
-    <dl id="available-chatrooms" class="rooms-list"></dl>
+<div class="d-flex">
+    <span class="w-100">Chatrooms</span>
+    <a class="chatbox-btn fa fa-users" title="{{{o.title_new_room}}}" data-toggle="modal" data-target="#chatroomsModal"></a>
 </div>
+<div class="list-container open-rooms-list rooms-list-container">
+    <div id="available-chatrooms" class="rooms-list"></div>
+</div>
+<!-- </div> -->

+ 8 - 0
src/templates/roster.html

@@ -1 +1,9 @@
+<div class="d-flex">
+    <span class="w-100">{{{o.heading_contacts}}}</span>
+    <a class="chatbox-btn fa fa-user-plus" title="{{{o.title_add_contact}}}"
+       data-toggle="modal" data-target="#addContactModal"></a>
+</div>
+
+<form class="roster-filter-form"></form>
+
 <div class="roster-contacts"></div>

+ 30 - 31
src/templates/roster_filter.html

@@ -1,32 +1,31 @@
-<span {[ if (!o.visible) { ]} class="hidden" {[ } ]}>
-<form class="pure-form roster-filter-form input-button-group">
-    <input value="{{{o.filter_text}}}"
-           class="roster-filter roster-filter-{{{o.filter_type}}}"
-           placeholder="{{{o.placeholder}}}">
-    <select class="state-type state-type-{{{o.filter_type}}}">
-        <option value="">{{{o.label_any}}}</option>
-        <option {[ if (o.chat_state === 'unread_messages') { ]} selected="selected" {[ } ]}
-            value="unread_messages">{{{o.label_unread_messages}}}</option>
-        <option {[ if (o.chat_state === 'online') { ]} selected="selected" {[ } ]}
-            value="online">{{{o.label_online}}}</option>
-        <option {[ if (o.chat_state === 'chat') { ]} selected="selected" {[ } ]}
-            value="chat">{{{o.label_chatty}}}</option>
-        <option {[ if (o.chat_state === 'dnd') { ]} selected="selected" {[ } ]}
-            value="dnd">{{{o.label_busy}}}</option>
-        <option {[ if (o.chat_state === 'away') { ]} selected="selected" {[ } ]}
-            value="away">{{{o.label_away}}}</option>
-        <option {[ if (o.chat_state === 'xa') { ]} selected="selected" {[ } ]}
-            value="xa">{{{o.label_xa}}}</option>
-        <option {[ if (o.chat_state === 'offline') { ]} selected="selected" {[ } ]}
-            value="offline">{{{o.label_offline}}}</option>
-    </select>
-    <select class="filter-type">
-        <option {[ if (o.filter_type === 'contacts') { ]} selected="selected" {[ } ]}
-                value="contacts">{{{o.label_contacts}}}</option>
-        <option {[ if (o.filter_type === 'groups') { ]} selected="selected" {[ } ]}
-                value="groups">{{{o.label_groups}}}</option>
-        <option {[ if (o.filter_type === 'state') { ]} selected="selected" {[ } ]}
-                value="state">{{{o.label_state}}}</option>
-    </select>
+<form class="roster-filter-form input-button-group {[ if (!o.visible) { ]} hidden {[ } ]}">
+    <div class="form-group form-inline">
+        <input value="{{{o.filter_text}}}"
+               class="roster-filter roster-filter-{{{o.filter_type}}}"
+               placeholder="{{{o.placeholder}}}">
+
+        <select class="state-type state-type-{{{o.filter_type}}}">
+            <option value="">{{{o.label_any}}}</option>
+            <option {[ if (o.chat_state === 'unread_messages') { ]} selected="selected" {[ } ]}
+                value="unread_messages">{{{o.label_unread_messages}}}</option>
+            <option {[ if (o.chat_state === 'online') { ]} selected="selected" {[ } ]}
+                value="online">{{{o.label_online}}}</option>
+            <option {[ if (o.chat_state === 'chat') { ]} selected="selected" {[ } ]}
+                value="chat">{{{o.label_chatty}}}</option>
+            <option {[ if (o.chat_state === 'dnd') { ]} selected="selected" {[ } ]}
+                value="dnd">{{{o.label_busy}}}</option>
+            <option {[ if (o.chat_state === 'away') { ]} selected="selected" {[ } ]}
+                value="away">{{{o.label_away}}}</option>
+            <option {[ if (o.chat_state === 'xa') { ]} selected="selected" {[ } ]}
+                value="xa">{{{o.label_xa}}}</option>
+            <option {[ if (o.chat_state === 'offline') { ]} selected="selected" {[ } ]}
+                value="offline">{{{o.label_offline}}}</option>
+        </select>
+
+        <div class="filter-by">
+            <span class="fa fa-user" data-type="contact" title="{{{o.title_contact_filter}}}"></span>
+            <span class="fa fa-users" data-type="group" title="{{{o.title_group_filter}}}"></span>
+            <span class="fa fa-circle" data-type="status" title="{{{o.title_status_filter}}}"></span>
+        </div>
+    </div>
 </form>
-</span>

+ 3 - 0
src/utils.js

@@ -655,6 +655,9 @@
     }
 
     u.isVisible = function (el) {
+        if (u.hasClass('hidden', el)) {
+            return false;
+        }
         // XXX: Taken from jQuery's "visible" implementation
         return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
     };