Merge branch 'open-room-via-url'
This commit is contained in:
commit
221798e6e1
@ -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
|
||||||
|
@ -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
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -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
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -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(
|
const chatbox = _converse.chatboxes.getChatBox(jids, true, attrs);
|
||||||
_converse.chatboxes.getChatBox(jids, true, attrs).trigger('show')
|
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(
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 : {};
|
||||||
|
@ -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)) {
|
||||||
|
@ -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 () {
|
function setActiveForm (value) {
|
||||||
this.route('converse-login', _.partial(this.setActiveForm, 'login'));
|
_converse.api.waitUntil('controlboxInitialized').then(() => {
|
||||||
this.route('converse-register', _.partial(this.setActiveForm, 'register'));
|
const controlbox = _converse.chatboxes.get('controlbox')
|
||||||
},
|
controlbox.set({'active-form': value});
|
||||||
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||||
setActiveForm (value) {
|
}
|
||||||
_converse.api.waitUntil('controlboxInitialized').then(() => {
|
_converse.router.route('converse/login', _.partial(setActiveForm, 'login'));
|
||||||
const controlbox = _converse.chatboxes.get('controlbox')
|
_converse.router.route('converse/register', _.partial(setActiveForm, 'register'));
|
||||||
controlbox.set({'active-form': value});
|
|
||||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const router = new _converse.RegistrationRouter();
|
|
||||||
|
|
||||||
|
|
||||||
_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,
|
||||||
|
@ -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,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>
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user