Sfoglia il codice sorgente

Merge branch 'open-room-via-url'

JC Brand 7 anni fa
parent
commit
221798e6e1

+ 4 - 1
CHANGES.md

@@ -3,6 +3,7 @@
 ## 3.3.0 (Unreleased)
 ## 3.3.0 (Unreleased)
 
 
 ### Bugfixes
 ### Bugfixes
+- #800 Could not register successfully in ejabberd 17.01
 - Don't require `auto_login` to be `true` when using the API to log in.
 - Don't require `auto_login` to be `true` when using the API to log in.
 - Moment locale wasn't being set to the value passed via the `i18n` option.
 - Moment locale wasn't being set to the value passed via the `i18n` option.
 - Refetch the roster from the server after reconnection.
 - Refetch the roster from the server after reconnection.
@@ -12,7 +13,9 @@
   Otherwise connected contacts might not get your presence updates.
   Otherwise connected contacts might not get your presence updates.
 
 
 ### New Features
 ### New Features
-- #828 Add routing for the `#converse-login` and `#converse-register` URL
+- #314 Add support for opening chat rooms with a URL fragment such as `#converse/room?jid=room@domain`
+  and private chats with a URL fragment such as `#converse/chat?jid=user@domain`
+- #828 Add routing for the `#converse/login` and `#converse/register` URL
   fragments, which will render the registration and login forms respectively.
   fragments, which will render the registration and login forms respectively.
 
 
 ### UX/UI changes
 ### UX/UI changes

+ 16 - 0
docs/source/events.rst

@@ -300,6 +300,22 @@ have to be registered anew.
 
 
 ``_converse.on('reconnected', function () { ... });``
 ``_converse.on('reconnected', function () { ... });``
 
 
+roomsAutoJoined
+---------------
+
+Emitted once any rooms that have been configured to be automatically joined,
+specified via the _`auto_join_rooms` setting, have been entered.
+
+``_converse.on('roomsAutoJoined', function () { ... });``
+
+Also available as an `ES2015 Promise <http://es6-features.org/#PromiseUsage>`_:
+
+.. code-block:: javascript
+
+    _converse.api.waitUntil('roomsAutoJoined').then(function () {
+        // Your code here...
+    });
+
 roomInviteSent
 roomInviteSent
 ~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~
 
 

+ 10 - 0
docs/source/features.rst

@@ -6,6 +6,16 @@
 Features
 Features
 ========
 ========
 
 
+Open chats via URL
+==================
+
+From version 3.3.0, converse.js now has the ability to open chats (private or
+groupchat) based on the URL fragment.
+
+A room (aka groupchat) can be opened with a URL fragment such as `#converse/room?jid=room@domain`
+and a private chat with a URL fragment such as
+`#converse/chat?jid=user@domain`.
+
 Off-the-record encryption
 Off-the-record encryption
 =========================
 =========================
 
 

+ 24 - 4
src/converse-chatboxes.js

@@ -10,7 +10,7 @@
     define(["converse-core"], factory);
     define(["converse-core"], factory);
 }(this, function (converse) {
 }(this, function (converse) {
     "use strict";
     "use strict";
-    const { Backbone, Strophe, b64_sha1, utils, _ } = converse.env;
+    const { Backbone, Promise, Strophe, b64_sha1, utils, _ } = converse.env;
 
 
     converse.plugins.add('converse-chatboxes', {
     converse.plugins.add('converse-chatboxes', {
 
 
@@ -55,6 +55,23 @@
                 'chatBoxesInitialized'
                 'chatBoxesInitialized'
             ]);
             ]);
 
 
+            function openChat (jid) {
+                if (!utils.isValidJID(jid)) {
+                    return converse.log(
+                        `Invalid JID "${jid}" provided in URL fragment`,
+                        Strophe.LogLevel.WARN
+                    );
+                }
+                Promise.all([
+                    _converse.api.waitUntil('rosterContactsFetched'),
+                    _converse.api.waitUntil('chatBoxesFetched')
+                ]).then(() => {
+                    _converse.api.chats.open(jid);
+                });
+            }
+            _converse.router.route('converse/chat?jid=:jid', openChat);
+
+
             _converse.ChatBoxes = Backbone.Collection.extend({
             _converse.ChatBoxes = Backbone.Collection.extend({
                 comparator: 'time_opened',
                 comparator: 'time_opened',
 
 
@@ -343,9 +360,12 @@
                             _converse.log("chats.open: You need to provide at least one JID", Strophe.LogLevel.ERROR);
                             _converse.log("chats.open: You need to provide at least one JID", Strophe.LogLevel.ERROR);
                             return null;
                             return null;
                         } else if (_.isString(jids)) {
                         } else if (_.isString(jids)) {
-                            return _converse.getViewForChatBox(
-                                _converse.chatboxes.getChatBox(jids, true, attrs).trigger('show')
-                            );
+                            const chatbox = _converse.chatboxes.getChatBox(jids, true, attrs);
+                            if (_.isNil(chatbox)) {
+                                _converse.log("Could not open chatbox for JID: "+jids);
+                                return;
+                            }
+                            return _converse.getViewForChatBox(chatbox.trigger('show'));
                         }
                         }
                         return _.map(jids, (jid) =>
                         return _.map(jids, (jid) =>
                             _converse.getViewForChatBox(
                             _converse.getViewForChatBox(

+ 3 - 0
src/converse-chatview.js

@@ -836,6 +836,9 @@
 
 
                 close (ev) {
                 close (ev) {
                     if (ev && ev.preventDefault) { ev.preventDefault(); }
                     if (ev && ev.preventDefault) { ev.preventDefault(); }
+                    if (Backbone.history.getFragment() === "converse/chat?jid="+this.model.get('jid')) {
+                        _converse.router.navigate('');
+                    }
                     if (_converse.connection.connected) {
                     if (_converse.connection.connected) {
                         // Immediately sending the chat state, because the
                         // Immediately sending the chat state, because the
                         // model is going to be destroyed afterwards.
                         // model is going to be destroyed afterwards.

+ 5 - 1
src/converse-controlbox.js

@@ -511,7 +511,7 @@
                     if (jid_element.value &&
                     if (jid_element.value &&
                             !_converse.locked_domain &&
                             !_converse.locked_domain &&
                             !_converse.default_domain &&
                             !_converse.default_domain &&
-                            _.filter(jid_element.value.split('@')).length < 2) {
+                            !utils.isValidJID(jid_element.value)) {
                         jid_element.setCustomValidity(__('Please enter a valid XMPP address'));
                         jid_element.setCustomValidity(__('Please enter a valid XMPP address'));
                         return false;
                         return false;
                     }
                     }
@@ -550,6 +550,10 @@
                             jid = Strophe.getBareJidFromJid(jid).toLowerCase()+'/'+resource;
                             jid = Strophe.getBareJidFromJid(jid).toLowerCase()+'/'+resource;
                         }
                         }
                     }
                     }
+                    if (_.includes(["converse/login", "converse/register"],
+                            Backbone.history.getFragment())) {
+                        _converse.router.navigate('', {'replace': true});
+                    }
                     _converse.connection.reset();
                     _converse.connection.reset();
                     _converse.connection.connect(jid, password, _converse.onConnectStatusChanged);
                     _converse.connection.connect(jid, password, _converse.onConnectStatusChanged);
                 }
                 }

+ 3 - 0
src/converse-core.js

@@ -230,6 +230,9 @@
         }
         }
     };
     };
 
 
+    _converse.router = new Backbone.Router();
+
+
     _converse.initialize = function (settings, callback) {
     _converse.initialize = function (settings, callback) {
         "use strict";
         "use strict";
         settings = !_.isUndefined(settings) ? settings : {};
         settings = !_.isUndefined(settings) ? settings : {};

+ 35 - 8
src/converse-muc.js

@@ -353,9 +353,28 @@
                     'toggle_occupants': true
                     'toggle_occupants': true
                 },
                 },
             });
             });
-            _converse.api.promises.add('roomsPanelRendered');
+            _converse.api.promises.add(['roomsPanelRendered', 'roomsAutoJoined']);
 
 
-            _converse.openChatRoom = function (settings, bring_to_foreground) {
+
+            function openRoom (jid) {
+                if (!utils.isValidJID(jid)) {
+                    return converse.log(
+                        `Invalid JID "${jid}" provided in URL fragment`,
+                        Strophe.LogLevel.WARN
+                    );
+                }
+                const promises = [_converse.api.waitUntil('roomsAutoJoined')]
+                if (!_converse.allow_bookmarks) {
+                    promises.push( _converse.api.waitUntil('bookmarksInitialized'));
+                }
+                Promise.all(promises).then(() => {
+                    _converse.api.rooms.open(jid);
+                });
+            }
+            _converse.router.route('converse/room?jid=:jid', openRoom);
+
+
+            function openChatRoom (settings, bring_to_foreground) {
                 /* Opens a chat room, making sure that certain attributes
                 /* Opens a chat room, making sure that certain attributes
                  * are correct, for example that the "type" is set to
                  * are correct, for example that the "type" is set to
                  * "chatroom".
                  * "chatroom".
@@ -367,7 +386,7 @@
                 settings.id = settings.jid;
                 settings.id = settings.jid;
                 settings.box_id = b64_sha1(settings.jid)
                 settings.box_id = b64_sha1(settings.jid)
                 return _converse.chatboxviews.showChat(settings, bring_to_foreground);
                 return _converse.chatboxviews.showChat(settings, bring_to_foreground);
-            };
+            }
 
 
             _converse.ChatRoom = _converse.ChatBox.extend({
             _converse.ChatRoom = _converse.ChatBox.extend({
 
 
@@ -823,7 +842,11 @@
                         affiliations = [affiliations];
                         affiliations = [affiliations];
                     }
                     }
                     return new Promise((resolve, reject) => {
                     return new Promise((resolve, reject) => {
-                        const promises = _.map(affiliations, _.partial(this.requestMemberList, this.model.get('jid')));
+                        const promises = _.map(
+                            affiliations,
+                            _.partial(this.requestMemberList, this.model.get('jid'))
+                        );
+
                         Promise.all(promises).then(
                         Promise.all(promises).then(
                             _.flow(this.marshallAffiliationIQs.bind(this), resolve),
                             _.flow(this.marshallAffiliationIQs.bind(this), resolve),
                             _.flow(this.marshallAffiliationIQs.bind(this), resolve)
                             _.flow(this.marshallAffiliationIQs.bind(this), resolve)
@@ -1243,6 +1266,9 @@
                      *      reason for leaving.
                      *      reason for leaving.
                      */
                      */
                     this.hide();
                     this.hide();
+                    if (Backbone.history.getFragment() === "converse/room?jid="+this.model.get('jid')) {
+                        _converse.router.navigate('');
+                    }
                     this.occupantsview.model.reset();
                     this.occupantsview.model.reset();
                     this.occupantsview.model.browserStorage._clear();
                     this.occupantsview.model.browserStorage._clear();
                     if (_converse.connection.connected) {
                     if (_converse.connection.connected) {
@@ -2637,7 +2663,7 @@
                     ev.preventDefault();
                     ev.preventDefault();
                     const data = this.parseRoomDataFromEvent(ev);
                     const data = this.parseRoomDataFromEvent(ev);
                     if (!_.isUndefined(data)) {
                     if (!_.isUndefined(data)) {
-                        _converse.openChatRoom(data);
+                        openChatRoom(data);
                     }
                     }
                 },
                 },
 
 
@@ -2685,7 +2711,7 @@
                     }
                     }
                 }
                 }
                 if (result === true) {
                 if (result === true) {
-                    const chatroom = _converse.openChatRoom({
+                    const chatroom = openChatRoom({
                         'jid': room_jid,
                         'jid': room_jid,
                         'password': $x.attr('password')
                         'password': $x.attr('password')
                     });
                     });
@@ -2724,6 +2750,7 @@
                             Strophe.LogLevel.ERROR);
                             Strophe.LogLevel.ERROR);
                     }
                     }
                 });
                 });
+                _converse.emit('roomsAutoJoined');
             }
             }
             _converse.on('chatBoxesFetched', autoJoinRooms);
             _converse.on('chatBoxesFetched', autoJoinRooms);
 
 
@@ -2775,9 +2802,9 @@
                         if (_.isUndefined(jids)) {
                         if (_.isUndefined(jids)) {
                             throw new TypeError('rooms.open: You need to provide at least one JID');
                             throw new TypeError('rooms.open: You need to provide at least one JID');
                         } else if (_.isString(jids)) {
                         } else if (_.isString(jids)) {
-                            return _converse.getChatRoom(jids, attrs, _converse.openChatRoom);
+                            return _converse.getChatRoom(jids, attrs, openChatRoom);
                         }
                         }
-                        return _.map(jids, _.partial(_converse.getChatRoom, _, attrs, _converse.openChatRoom));
+                        return _.map(jids, _.partial(_converse.getChatRoom, _, attrs, openChatRoom));
                     },
                     },
                     'get' (jids, attrs, create) {
                     'get' (jids, attrs, create) {
                         if (_.isString(attrs)) {
                         if (_.isString(attrs)) {

+ 14 - 21
src/converse-register.js

@@ -59,7 +59,7 @@
             // relevant objects or classes.
             // relevant objects or classes.
             //
             //
             // New functions which don't exist yet can also be added.
             // New functions which don't exist yet can also be added.
-        
+
             LoginPanel: {
             LoginPanel: {
 
 
                 render: function (cfg) {
                 render: function (cfg) {
@@ -80,9 +80,6 @@
 
 
             ControlBoxView: {
             ControlBoxView: {
 
 
-                events: {
-                },
-
                 initialize () {
                 initialize () {
                     this.__super__.initialize.apply(this, arguments);
                     this.__super__.initialize.apply(this, arguments);
                     this.model.on('change:active-form', this.showLoginOrRegisterForm.bind(this))
                     this.model.on('change:active-form', this.showLoginOrRegisterForm.bind(this))
@@ -102,7 +99,6 @@
                     }
                     }
                 },
                 },
 
 
-
                 renderRegistrationPanel () {
                 renderRegistrationPanel () {
                     const { _converse } = this.__super__;
                     const { _converse } = this.__super__;
                     if (_converse.allow_registration) {
                     if (_converse.allow_registration) {
@@ -149,21 +145,15 @@
                 providers_link: 'https://xmpp.net/directory.php', // Link to XMPP providers shown on registration page
                 providers_link: 'https://xmpp.net/directory.php', // Link to XMPP providers shown on registration page
             });
             });
 
 
-            _converse.RegistrationRouter = Backbone.Router.extend({
-
-                initialize () {
-                    this.route('converse-login', _.partial(this.setActiveForm, 'login'));
-                    this.route('converse-register', _.partial(this.setActiveForm, 'register'));
-                },
 
 
-                setActiveForm (value) {
-                    _converse.api.waitUntil('controlboxInitialized').then(() => {
-                        const controlbox = _converse.chatboxes.get('controlbox')
-                        controlbox.set({'active-form': value});
-                    }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
-                }
-            });
-            const router = new _converse.RegistrationRouter();
+            function setActiveForm (value) {
+                _converse.api.waitUntil('controlboxInitialized').then(() => {
+                    const controlbox = _converse.chatboxes.get('controlbox')
+                    controlbox.set({'active-form': value});
+                }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+            }
+            _converse.router.route('converse/login', _.partial(setActiveForm, 'login'));
+            _converse.router.route('converse/register', _.partial(setActiveForm, 'register'));
 
 
 
 
             _converse.RegisterPanel = Backbone.View.extend({
             _converse.RegisterPanel = Backbone.View.extend({
@@ -425,11 +415,14 @@
                         );
                         );
                         this.abortRegistration();
                         this.abortRegistration();
                     } else if (status_code === Strophe.Status.REGISTERED) {
                     } else if (status_code === Strophe.Status.REGISTERED) {
-                        router.navigate(); // Strip the URL fragment
                         _converse.log("Registered successfully.");
                         _converse.log("Registered successfully.");
                         _converse.connection.reset();
                         _converse.connection.reset();
                         this.showSpinner();
                         this.showSpinner();
 
 
+                        if (_.includes(["converse/login", "converse/register"], Backbone.history.getFragment())) {
+                            _converse.router.navigate('', {'replace': true});
+                        }
+
                         if (this.fields.password && this.fields.username) {
                         if (this.fields.password && this.fields.username) {
                             // automatically log the user in
                             // automatically log the user in
                             _converse.connection.connect(
                             _converse.connection.connect(
@@ -464,7 +457,7 @@
                             form.insertAdjacentHTML(
                             form.insertAdjacentHTML(
                                 'beforeend',
                                 'beforeend',
                                 tpl_form_input({
                                 tpl_form_input({
-                                    'label': key, 
+                                    'label': key,
                                     'name': key,
                                     'name': key,
                                     'placeholder': key,
                                     'placeholder': key,
                                     'required': true,
                                     'required': true,

+ 1 - 1
src/converse-vcard.js

@@ -31,7 +31,7 @@
                         function (iq, jid) {
                         function (iq, jid) {
                             _converse.log(
                             _converse.log(
                                 `Error while retrieving vcard for ${jid}`,
                                 `Error while retrieving vcard for ${jid}`,
-                                Strophe.LogLevel.ERROR
+                                Strophe.LogLevel.WARN
                             );
                             );
                             _converse.createRequestingContactFromVCard(presence, iq, jid);
                             _converse.createRequestingContactFromVCard(presence, iq, jid);
                         }
                         }

+ 1 - 1
src/templates/register_link.html

@@ -1,4 +1,4 @@
 <div class="switch-form">
 <div class="switch-form">
     <p>{{{ __("Don't have a chat account?") }}}</p>
     <p>{{{ __("Don't have a chat account?") }}}</p>
-    <p><a class="register-account toggle-register-login" href="#converse-register">{{{__("Create an account")}}}</a></p>
+    <p><a class="register-account toggle-register-login" href="#converse/register">{{{__("Create an account")}}}</a></p>
 </div>
 </div>

+ 1 - 1
src/templates/register_panel.html

@@ -17,6 +17,6 @@
 <div class="switch-form">
 <div class="switch-form">
     <p>{{{ __("Already have a chat account?") }}}</p>
     <p>{{{ __("Already have a chat account?") }}}</p>
     <p>
     <p>
-        <a class="login-here toggle-register-login" href="#converse-login">{{{__("Log in here")}}}</a>
+        <a class="login-here toggle-register-login" href="#converse/login">{{{__("Log in here")}}}</a>
     </p>
     </p>
 </div>
 </div>

+ 4 - 0
src/utils.js

@@ -266,6 +266,10 @@
         }
         }
     };
     };
 
 
+    u.isValidJID = function (jid) {
+        return _.filter(jid.split('@')).length === 2 && !jid.startsWith('@') && !jid.endsWith('@');
+    };
+
     u.isSameBareJID = function (jid1, jid2) {
     u.isSameBareJID = function (jid1, jid2) {
         return Strophe.getBareJidFromJid(jid1).toLowerCase() ===
         return Strophe.getBareJidFromJid(jid1).toLowerCase() ===
                 Strophe.getBareJidFromJid(jid2).toLowerCase();
                 Strophe.getBareJidFromJid(jid2).toLowerCase();