Browse Source

Initial work on refactoring MUC chat rooms. updates #307

In the process of removing the strophe.muc plugin completely.
Already implemented join function and handler delegation in converse.js.
JC Brand 10 years ago
parent
commit
4a5eb7c38a
1 changed files with 114 additions and 46 deletions
  1. 114 46
      converse.js

+ 114 - 46
converse.js

@@ -2146,6 +2146,7 @@
         this.ChatRoomOccupantView = Backbone.View.extend({
             tagName: 'li',
             initialize: function () {
+                this.model.on('add', this.render, this);
                 this.model.on('change', this.render, this);
                 this.model.on('destroy', this.destroy, this);
             },
@@ -2206,31 +2207,62 @@
                 this.$('.participant-list').append(view.render().$el);
             },
 
-            onChatRoomRoster: function (roster, room) {
-                var roster_size = _.size(roster),
-                    $participant_list = this.$('.participant-list'),
-                    participants = [],
-                    keys = _.keys(roster),
-                    occupant, attrs, i, nick;
-
-                for (i=0; i<roster_size; i++) {
-                    nick = Strophe.unescapeNode(keys[i]);
-                    attrs = {
-                        'id': nick,
-                        'role': roster[keys[i]].role,
-                        'nick': nick
-                    };
-                    occupant = this.model.get(nick);
-                    if (occupant) {
-                        occupant.save(attrs);
-                    } else {
-                        this.model.create(attrs);
+            parsePresence: function (pres) {
+                var id = Strophe.getResourceFromJid(pres.getAttribute("from"));
+                var data = {
+                    id: id,
+                    nick: id,
+                    type: pres.getAttribute("type"),
+                    states: []
+                };
+                _.each(pres.childNodes, function (child) {
+                    switch (child.nodeName) {
+                        case "status":
+                            data.status = child.textContent || null;
+                            break;
+                        case "show":
+                            data.show = child.textContent || null;
+                            break;
+                        case "x":
+                            if (child.getAttribute("xmlns") === Strophe.NS.MUC_USER) {
+                                _.each(child.childNodes, function (item) {
+                                    switch (item.nodeName) {
+                                        case "item":
+                                            data.affiliation = item.getAttribute("affiliation");
+                                            data.role = item.getAttribute("role");
+                                            data.jid = item.getAttribute("jid");
+                                            data.nick = item.getAttribute("nick") || data.nick;
+                                            break;
+                                        case "status":
+                                            if (item.getAttribute("code")) {
+                                                data.states.push(item.getAttribute("code"));
+                                            }
+                                    }
+                                });
+                            }
                     }
+                });
+                return data;
+            },
+
+            updateOccupantsOnPresence: function (pres) {
+                var occupant;
+                var data = this.parsePresence(pres);
+                switch (data.type) {
+                    case 'error':
+                        return true;
+                    case 'unavailable':
+                        occupant = this.model.get(data.id);
+                        if (occupant) { occupant.destroy(); }
+                        break;
+                    default:
+                        occupant = this.model.get(data.id);
+                        if (occupant) {
+                            occupant.save(data);
+                        } else {
+                            this.model.create(data);
+                        }
                 }
-                _.each(_.difference(this.model.pluck('id'), keys), function (id) {
-                    this.model.get(id).destroy();
-                }, this);
-                return true;
             },
 
             initInviteWidget: function () {
@@ -2309,7 +2341,7 @@
                 this.occupantsview.chatroomview = this;
                 this.render();
                 this.occupantsview.model.fetch({add:true});
-                this.connect(null);
+                this.join(null);
                 converse.emit('chatRoomOpened', this);
 
                 this.$el.insertAfter(converse.chatboxviews.get("controlbox").$el);
@@ -2442,21 +2474,53 @@
                 }
             },
 
-            connect: function (password) {
-                if (_.has(converse.connection.muc.rooms, this.model.get('jid'))) {
-                    // If the room exists, it already has event listeners, so we
-                    // don't add them again.
-                    converse.connection.muc.join(
-                        this.model.get('jid'), this.model.get('nick'), null, null, null, password);
-                } else {
-                    converse.connection.muc.join(
-                        this.model.get('jid'),
-                        this.model.get('nick'),
-                        $.proxy(this.onChatRoomMessage, this),
-                        $.proxy(this.onChatRoomPresence, this),
-                        $.proxy(this.onChatRoomRoster, this),
-                        password);
+            handleMUCStanza: function (stanza) {
+                var xmlns, xquery, i;
+                var from = stanza.getAttribute('from');
+                if (!from || (this.model.get('id') !== from.split("/")[0])) {
+                    return true;
+                }
+                if (stanza.nodeName === "message") {
+                    this.onChatRoomMessage(stanza);
+                } else if (stanza.nodeName === "presence") {
+                    xquery = stanza.getElementsByTagName("x");
+                    if (xquery.length > 0) {
+                        for (i = 0; i < xquery.length; i++) {
+                            xmlns = xquery[i].getAttribute("xmlns");
+                            if (xmlns && xmlns.match(Strophe.NS.MUC)) {
+                                this.onChatRoomPresence(stanza);
+                                break;
+                            }
+                        }
+                    }
+                }
+                return true;
+            },
+
+            join: function(password, history_attrs, extended_presence) {
+                var nick = this.model.get('nick');
+                var room = this.model.get('jid');
+                var node = Strophe.escapeNode(Strophe.getNodeFromJid(room));
+                var domain = Strophe.getDomainFromJid(room);
+                var msg = $pres({
+                    from: converse.connection.jid,
+                    to: node + "@" + domain + (nick !== null ? "/" + nick : "")
+                }).c("x", {
+                    xmlns: Strophe.NS.MUC
+                });
+                if (typeof history_attrs === "object" && history_attrs.length) {
+                    msg = msg.c("history", history_attrs).up();
+                }
+                if (password) {
+                    msg.cnode(Strophe.xmlElement("password", [], password));
                 }
+                if (typeof extended_presence !== "undefined" && extended_presence !== null) {
+                    msg.up.cnode(extended_presence);
+                }
+                if (!this.handler) {
+                    this.handler = converse.connection.addHandler($.proxy(this.handleMUCStanza, this));
+                }
+                return converse.connection.send(msg);
             },
 
             onLeave: function () {
@@ -2549,7 +2613,7 @@
                 ev.preventDefault();
                 var password = this.$el.find('.chatroom-form').find('input[type=password]').val();
                 this.$el.find('.chatroom-form-container').replaceWith('<span class="spinner centered"/>');
-                this.connect(password);
+                this.join(password);
             },
 
             renderPasswordForm: function () {
@@ -2730,13 +2794,15 @@
                 }
             },
 
-            onChatRoomPresence: function (presence, room) {
-                var $presence = $(presence), is_self;
+            onChatRoomPresence: function (pres) {
+                var $presence = $(pres), is_self;
+                var nick = this.model.get('nick');
                 if ($presence.attr('type') === 'error') {
                     this.model.set('connected', false);
                     this.showErrorMessage($presence.find('error'), room);
                 } else {
-                    is_self = ($presence.find("status[code='110']").length) || ($presence.attr('from') == room.name+'/'+Strophe.escapeNode(room.nick));
+                    is_self = ($presence.find("status[code='110']").length) ||
+                        ($presence.attr('from') == this.model.get('id')+'/'+Strophe.escapeNode(nick));
                     if (!this.model.get('conneced')) {
                         this.model.set('connected', true);
                         this.$('span.centered.spinner').remove();
@@ -2744,7 +2810,7 @@
                     }
                     this.showStatusMessages($presence, is_self);
                 }
-                return true;
+                this.occupantsview.updateOccupantsOnPresence(pres);
             },
 
             onChatRoomMessage: function (message) {
@@ -2784,8 +2850,7 @@
                 return true;
             },
 
-            onChatRoomRoster: function (roster, room) {
-                return this.occupantsview.onChatRoomRoster(roster, room);
+            onChatRoomRoster: function (roster) {
             }
         });
 
@@ -2868,7 +2933,7 @@
                         'password': $x.attr('password')
                     });
                     if (!chatroom.get('connected')) {
-                        converse.chatboxviews.get(room_jid).connect(null);
+                        converse.chatboxviews.get(room_jid).join(null);
                     }
                 }
             },
@@ -5310,6 +5375,9 @@
                 converse.off(evt, handler);
             },
         },
+        'send': function (stanza) {
+            converse.connection.send(stanza);
+        },
         'plugins': {
             'add': function (name, callback) {
                 converse.plugins[name] = callback;