Browse Source

roomslist: Refactor to use VDOMView instead of OrderedListView

JC Brand 5 years ago
parent
commit
91397125ba

+ 5 - 8
spec/roomslist.js

@@ -15,11 +15,9 @@
 
             test_utils.openControlBox();
             const controlbox = _converse.chatboxviews.get('controlbox');
-            let list = controlbox.el.querySelector('div.rooms-list-container');
+            let list = controlbox.el.querySelector('.list-container--openrooms');
             expect(_.includes(list.classList, 'hidden')).toBeTruthy();
-
             await test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
-            expect(_converse.rooms_list_view === undefined).toBeFalsy();
 
             const lview = _converse.rooms_list_view
             await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
@@ -37,7 +35,7 @@
             room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
             expect(room_els.length).toBe(1);
             expect(room_els[0].innerText).toBe('lounge@montague.lit');
-            list = controlbox.el.querySelector('div.rooms-list-container');
+            list = controlbox.el.querySelector('.list-container--openrooms');
             u.waitUntil(() => _.includes(list.classList, 'hidden'));
 
             view = _converse.chatboxviews.get('lounge@montague.lit');
@@ -45,11 +43,10 @@
             room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
             expect(room_els.length).toBe(0);
 
-            list = controlbox.el.querySelector('div.rooms-list-container');
+            list = controlbox.el.querySelector('.list-container--openrooms');
             expect(_.includes(list.classList, 'hidden')).toBeTruthy();
             done();
-            }
-        ));
+        }));
 
         it("uses bookmarks to determine groupchat names",
             mock.initConverse(
@@ -100,7 +97,7 @@
 
             await _converse.api.waitUntil('roomsListInitialized');
             const controlbox = _converse.chatboxviews.get('controlbox');
-            const list = controlbox.el.querySelector('div.rooms-list-container');
+            const list = controlbox.el.querySelector('.list-container--openrooms');
             expect(_.includes(list.classList, 'hidden')).toBeFalsy();
             const items = list.querySelectorAll('.list-item');
             expect(items.length).toBe(1);

+ 47 - 146
src/converse-roomslist.js

@@ -10,10 +10,8 @@
  * rooms in the "Rooms Panel" of the ControlBox.
  */
 import "@converse/headless/converse-muc";
-import { OrderedListView } from "backbone.overview";
 import converse from "@converse/headless/converse-core";
 import tpl_rooms_list from "templates/rooms_list.html";
-import tpl_rooms_list_item from "templates/rooms_list_item.html"
 
 const { Backbone, Strophe, } = converse.env;
 const u = converse.env.utils;
@@ -39,118 +37,21 @@ converse.plugins.add('converse-roomslist', {
         /* The initialize function gets called as soon as the plugin is
          * loaded by converse.js's plugin machinery.
          */
-        const { _converse } = this,
-              { __ } = _converse;
+        const { _converse } = this;
+        const { __ } = _converse;
 
         // Promises exposed by this plugin
         _converse.api.promises.add('roomsListInitialized');
 
 
-        _converse.OpenRooms = _converse.Collection.extend({
-
-            comparator (room) {
-                if (_converse.bookmarks && room.get('bookmarked')) {
-                    const bookmark = _converse.bookmarks.findWhere({'jid': room.get('jid')});
-                    return bookmark.get('name');
-                } else {
-                    return room.get('name');
-                }
-            },
-
-            initialize () {
-                _converse.chatboxes.on('add', this.onChatBoxAdded, this);
-                _converse.chatboxes.on('change:hidden', this.onChatBoxChanged, this);
-                _converse.chatboxes.on('change:bookmarked', this.onChatBoxChanged, this);
-                _converse.chatboxes.on('change:name', this.onChatBoxChanged, this);
-                _converse.chatboxes.on('change:num_unread', this.onChatBoxChanged, this);
-                _converse.chatboxes.on('change:num_unread_general', this.onChatBoxChanged, this);
-                _converse.chatboxes.on('remove', this.onChatBoxRemoved, this);
-                this.reset(_converse.chatboxes.where({'type': _converse.CHATROOMS_TYPE}).map(cb => cb.attributes));
-            },
-
-            onChatBoxAdded (item) {
-                if (item.get('type') === _converse.CHATROOMS_TYPE) {
-                    this.create(item.attributes);
-                }
-            },
-
-            onChatBoxChanged (item) {
-                if (item.get('type') === _converse.CHATROOMS_TYPE) {
-                    const room =  this.get(item.get('jid'));
-                    room && room.set(item.attributes);
-                }
-            },
-
-            onChatBoxRemoved (item) {
-                if (item.get('type') === _converse.CHATROOMS_TYPE) {
-                    const room = this.get(item.get('jid'))
-                    this.remove(room);
-                }
-            }
-        });
-
-
         _converse.RoomsList = Backbone.Model.extend({
             defaults: {
                 "toggle-state":  _converse.OPENED
             }
         });
 
-        _converse.RoomsListElementView = Backbone.VDOMView.extend({
-            events: {
-                'click .room-info': 'showRoomDetailsModal'
-            },
-
-            initialize () {
-                this.listenTo(this.model, 'destroy', this.remove)
-                this.listenTo(this.model, 'remove', this.remove)
-                this.listenTo(this.model, 'change:bookmarked', this.render)
-                this.listenTo(this.model, 'change:hidden', this.render)
-                this.listenTo(this.model, 'change:name', this.render)
-                this.listenTo(this.model, 'change:num_unread', this.render)
-                this.listenTo(this.model, 'change:num_unread_general', this.render)
-            },
-
-            toHTML () {
-                return tpl_rooms_list_item(
-                    Object.assign(this.model.toJSON(), {
-                        // XXX: By the time this renders, the _converse.bookmarks
-                        // collection should already exist if bookmarks are
-                        // supported by the XMPP server. So we can use it
-                        // as a check for support (other ways of checking are async).
-                        'allow_bookmarks': _converse.allow_bookmarks && _converse.bookmarks,
-                        'currently_open': _converse.isUniView() && !this.model.get('hidden'),
-                        'info_leave_room': __('Leave this groupchat'),
-                        'info_remove_bookmark': __('Unbookmark this groupchat'),
-                        'info_add_bookmark': __('Bookmark this groupchat'),
-                        'info_title': __('Show more information on this groupchat'),
-                        'name': this.getRoomsListElementName(),
-                        'open_title': __('Click to open this groupchat')
-                    }));
-            },
-
-            showRoomDetailsModal (ev) {
-                const room = _converse.chatboxes.get(this.model.get('jid'));
-                ev.preventDefault();
-                if (room.room_details_modal === undefined) {
-                    room.room_details_modal = new _converse.RoomDetailsModal({'model': room});
-                }
-                room.room_details_modal.show(ev);
-            },
 
-            getRoomsListElementName () {
-                if (this.model.get('bookmarked') && _converse.bookmarks) {
-                    const bookmark = _converse.bookmarks.findWhere({'jid': this.model.get('jid')});
-                    if (bookmark) {
-                        return bookmark.get('name');
-                    }
-                }
-                return this.model.get('name');
-            }
-        });
-
-
-        _converse.RoomsListView = OrderedListView.extend({
+        _converse.RoomsListView = Backbone.VDOMView.extend({
             tagName: 'div',
             className: 'open-rooms-list list-container rooms-list-container',
             events: {
@@ -159,41 +60,52 @@ converse.plugins.add('converse-roomslist', {
                 'click .list-toggle': 'toggleRoomsList',
                 'click .remove-bookmark': 'removeBookmark',
                 'click .open-room': 'openRoom',
+                'click .room-info': 'showRoomDetailsModal'
             },
-            listSelector: '.rooms-list',
-            ItemView: _converse.RoomsListElementView,
-            subviewIndex: 'jid',
 
             initialize () {
-                OrderedListView.prototype.initialize.apply(this, arguments);
-
-                this.listenTo(this.model, 'add', this.showOrHide)
-                this.listenTo(this.model, 'remove', this.showOrHide)
-
-                const storage = _converse.config.get('storage'),
-                      id = `converse.roomslist${_converse.bare_jid}`;
-
-                this.list_model = new _converse.RoomsList({'id': id});
-                this.list_model.browserStorage = _converse.createStore(id, storage);
+                this.listenTo(this.model, 'add', this.renderIfChatRoom)
+                this.listenTo(this.model, 'remove', this.renderIfChatRoom)
+                this.listenTo(this.model, 'destroy', this.renderIfChatRoom)
+                this.listenTo(this.model, 'change', this.renderIfRelevantChange)
+
+                const id = `converse.roomslist${_converse.bare_jid}`;
+                this.list_model = new _converse.RoomsList({id});
+                this.list_model.browserStorage = _converse.createStore(id);
                 this.list_model.fetch();
                 this.render();
-                this.sortAndPositionAllItems();
+                this.insertIntoControlBox();
             },
 
-            render () {
-                this.el.innerHTML = tpl_rooms_list({
-                    'toggle_state': this.list_model.get('toggle-state'),
+            renderIfChatRoom (model) {
+                u.isChatRoom(model) && this.render();
+            },
+
+            renderIfRelevantChange (model) {
+                const attrs = ['bookmarked', 'hidden', 'name', 'num_unread', 'num_unread_general'];
+                const changed = model.changed || {};
+                if (u.isChatRoom(model) && Object.keys(changed).filter(m => attrs.includes(m)).length) {
+                    this.render();
+                }
+            },
+
+            toHTML () {
+                return tpl_rooms_list({
+                    'rooms': _converse.api.rooms.get(),
+                    'allow_bookmarks': _converse.allow_bookmarks && _converse.bookmarks,
+                    'collapsed': this.list_model.get('toggle-state') !== _converse.OPENED,
                     'desc_rooms': __('Click to toggle the list of open groupchats'),
+                    'info_add_bookmark': __('Bookmark this groupchat'),
+                    'info_leave_room': __('Leave this groupchat'),
+                    'info_remove_bookmark': __('Unbookmark this groupchat'),
+                    'info_title': __('Show more information on this groupchat'),
+                    'open_title': __('Click to open this groupchat'),
+                    'currently_open': room => _converse.isUniView() && !room.get('hidden'),
+                    'toggle_state': this.list_model.get('toggle-state'),
                     // Note to translators, "Open Groupchats" refers to groupchats that are open, NOT a command.
                     'label_rooms': __('Open Groupchats'),
-                    '_converse': _converse
+                    '_converse': _converse,
                 });
-                if (this.list_model.get('toggle-state') !== _converse.OPENED) {
-                    this.el.querySelector('.open-rooms-list').classList.add('collapsed');
-                }
-                this.showOrHide();
-                this.insertIntoControlBox();
-                return this;
             },
 
             insertIntoControlBox () {
@@ -206,12 +118,14 @@ converse.plugins.add('converse-roomslist', {
                 }
             },
 
-            hide () {
-                u.hideElement(this.el);
-            },
-
-            show () {
-                u.showElement(this.el);
+            showRoomDetailsModal (ev) {
+                const jid = ev.target.getAttribute('data-room-jid');
+                const room = _converse.chatboxes.get(jid);
+                ev.preventDefault();
+                if (room.room_details_modal === undefined) {
+                    room.room_details_modal = new _converse.RoomDetailsModal({'model': room});
+                }
+                room.room_details_modal.show(ev);
             },
 
             async openRoom (ev) {
@@ -235,14 +149,6 @@ converse.plugins.add('converse-roomslist', {
                 }
             },
 
-            showOrHide () {
-                if (!this.model.models.length) {
-                    u.hideElement(this.el);
-                } else {
-                    u.showElement(this.el);
-                }
-            },
-
             removeBookmark: _converse.removeBookmarkViaEvent,
             addBookmark: _converse.addBookmarkViaEvent,
 
@@ -266,12 +172,7 @@ converse.plugins.add('converse-roomslist', {
         });
 
         const initRoomsListView = function () {
-            const storage = _converse.config.get('storage'),
-                  id = `converse.open-rooms-{_converse.bare_jid}`,
-                  model = new _converse.OpenRooms();
-
-            model.browserStorage = _converse.createStore(id, storage);
-            _converse.rooms_list_view = new _converse.RoomsListView({'model': model});
+            _converse.rooms_list_view = new _converse.RoomsListView({'model': _converse.chatboxes});
             /**
              * Triggered once the _converse.RoomsListView has been created and initialized.
              * @event _converse#roomsListInitialized

+ 1 - 1
src/headless/converse-core.js

@@ -355,7 +355,7 @@ _converse.isUniView = function () {
 };
 
 _converse.createStore = function (id, storage) {
-    const s = storage ? storage : _converse.storage[_converse.config.get('storage')];
+    const s = storage ? storage : _converse.config.get('storage');
     return new BrowserStorage[s](id);
 }
 

+ 5 - 1
src/headless/utils/core.js

@@ -169,13 +169,17 @@ u.isOnlyMessageDeliveryReceipt = function (msg) {
     return msg['received'] && u.isEmptyMessage(msg);
 };
 
+u.isChatRoom = function (model) {
+    return model && (model.get('type') === 'chatroom');
+}
+
 u.isHeadlineMessage = function (_converse, message) {
     const from_jid = message.getAttribute('from');
     if (message.getAttribute('type') === 'headline') {
         return true;
     }
     const chatbox = _converse.chatboxes.get(Strophe.getBareJidFromJid(from_jid));
-    if (chatbox && chatbox.get('type') === _converse.CHATROOMS_TYPE) {
+    if (u.isChatRoom(chatbox)) {
         return false;
     }
     if (message.getAttribute('type') !== 'error' && from_jid && !_.includes(from_jid, '@')) {

+ 40 - 3
src/templates/rooms_list.html

@@ -1,4 +1,41 @@
+<div class="list-container list-container--openrooms {{{ !o.rooms.length && 'hidden' || '' }}}">
+
 <a href="#" class="list-toggle open-rooms-toggle controlbox-padded" title="{{{o.desc_rooms}}}">
-    <span class="fa {[ if (o.toggle_state === o._converse.OPENED) { ]} fa-caret-down {[ } else { ]} fa-caret-right {[ } ]}">
-    </span> {{{o.label_rooms}}}</a>
-<div class="items-list rooms-list open-rooms-list"></div>
+<span class="fa {[ if (o.toggle_state === o._converse.OPENED) { ]} fa-caret-down {[ } else { ]} fa-caret-right {[ } ]}">
+</span>  {{{o.label_rooms}}}</a>
+
+<div class="items-list rooms-list open-rooms-list {{{ o.collapsed && 'collapsed' }}}">
+    {[o.rooms.forEach(function (room) { ]}
+        <div class="list-item controlbox-padded available-chatroom d-flex flex-row
+            {[ if (o.currently_open(room)) { ]} open {[ } ]}
+            {[ if (room.get('num_unread_general')) { ]} unread-msgs {[ } ]}"
+            data-room-jid="{{{room.get('jid')}}}">
+
+        {[ if (room.get('num_unread')) { ]}
+            <span class="list-item-badge badge badge-room-color msgs-indicator">{{{ room.get('num_unread') }}}</span>
+        {[ } ]}
+        <a class="list-item-link open-room available-room w-100"
+            data-room-jid="{{{room.get('jid')}}}"
+            title="{{{o.open_title}}}" href="#">{{{room.getDisplayName()}}}</a>
+
+        {[ if (o.allow_bookmarks) { ]}
+        <a class="list-item-action fa {[ if (o.bookmarked) { ]} fa-bookmark remove-bookmark button-on {[ } else { ]} add-bookmark fa-bookmark {[ } ]}"
+           data-room-jid="{{{room.get('jid')}}}"
+           data-bookmark-name="{{{room.getDisplayName()}}}"
+           title="{[ if (o.bookmarked) { ]} {{{o.info_remove_bookmark}}} {[ } else { ]} {{{o.info_add_bookmark}}} {[ } ]}"
+           href="#"></a>
+        {[ } ]}
+
+        <a class="list-item-action room-info fa fa-info-circle"
+           data-room-jid="{{{room.get('jid')}}}"
+           title="{{{o.info_title}}}" href="#"></a>
+
+        <a class="list-item-action fa fa-sign-out-alt close-room"
+           data-room-jid="{{{room.get('jid')}}}"
+           data-room-name="{{{room.getDisplayName()}}}"
+           title="{{{o.info_leave_room}}}" href="#"></a>
+
+        </div>
+    {[ }) ]}
+</div>
+</div>

+ 0 - 28
src/templates/rooms_list_item.html

@@ -1,28 +0,0 @@
-<div class="list-item controlbox-padded available-chatroom d-flex flex-row
-    {[ if (o.currently_open) { ]} open {[ } ]}
-    {[ if (o.num_unread_general) { ]} unread-msgs {[ } ]}"
-    data-room-jid="{{{o.jid}}}">
-
-{[ if (o.num_unread) { ]}
-    <span class="list-item-badge badge badge-room-color msgs-indicator">{{{ o.num_unread }}}</span>
-{[ } ]}
-<a class="list-item-link open-room available-room w-100"
-    data-room-jid="{{{o.jid}}}"
-    title="{{{o.open_title}}}" href="#">{{{o.name || o.jid}}}</a>
-
-{[ if (o.allow_bookmarks) { ]}
-<a class="list-item-action fa {[ if (o.bookmarked) { ]} fa-bookmark remove-bookmark button-on {[ } else { ]} add-bookmark fa-bookmark {[ } ]}"
-   data-room-jid="{{{o.jid}}}" data-bookmark-name="{{{o.name}}}"
-   title="{[ if (o.bookmarked) { ]} {{{o.info_remove_bookmark}}} {[ } else { ]} {{{o.info_add_bookmark}}} {[ } ]}"
-   href="#"></a>
-{[ } ]}
-
-<a class="list-item-action room-info fa fa-info-circle" data-room-jid="{{{o.jid}}}"
-   title="{{{o.info_title}}}" href="#"></a>
-
-<a class="list-item-action fa fa-sign-out-alt close-room"
-   data-room-jid="{{{o.jid}}}"
-   data-room-name="{{{o.name || o.jid}}}"
-   title="{{{o.info_leave_room}}}" href="#"></a>
-
-</div>