diff --git a/src/MatrixTools.js b/src/MatrixTools.js index 372f17f69c..b003d8d2d7 100644 --- a/src/MatrixTools.js +++ b/src/MatrixTools.js @@ -24,30 +24,5 @@ module.exports = { getDisplayAliasForRoom: function(room) { return room.getCanonicalAlias() || room.getAliases()[0]; }, - - /** - * Given a list of room objects, return the room which has the given alias, - * else null. - */ - getRoomForAlias: function(rooms, room_alias) { - var room; - for (var i = 0; i < rooms.length; i++) { - var aliasEvents = rooms[i].currentState.getStateEvents( - "m.room.aliases" - ); - for (var j = 0; j < aliasEvents.length; j++) { - var aliases = aliasEvents[j].getContent().aliases || []; - for (var k = 0; k < aliases.length; k++) { - if (aliases[k] === room_alias) { - room = rooms[i]; - break; - } - } - if (room) { break; } - } - if (room) { break; } - } - return room || null; - } } diff --git a/src/SlashCommands.js b/src/SlashCommands.js index e4c0d5973a..d4e63018d3 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -132,46 +132,25 @@ var commands = { }), // Join a room - join: new Command("join", "", function(room_id, args) { + join: new Command("join", "#alias:domain", function(room_id, args) { if (args) { var matches = args.match(/^(\S+)$/); if (matches) { var room_alias = matches[1]; if (room_alias[0] !== '#') { - return reject("Usage: /join #alias:domain"); + return reject(this.getUsage()); } if (!room_alias.match(/:/)) { room_alias += ':' + MatrixClientPeg.get().getDomain(); } - // Try to find a room with this alias - // XXX: do we need to do this? Doesn't the JS SDK suppress duplicate attempts to join the same room? - var foundRoom = MatrixTools.getRoomForAlias( - MatrixClientPeg.get().getRooms(), - room_alias - ); + dis.dispatch({ + action: 'view_room', + room_alias: room_alias, + auto_join: true, + }); - if (foundRoom) { // we've already joined this room, view it if it's not archived. - var me = foundRoom.getMember(MatrixClientPeg.get().credentials.userId); - if (me && me.membership !== "leave") { - dis.dispatch({ - action: 'view_room', - room_id: foundRoom.roomId - }); - return success(); - } - } - - // otherwise attempt to join this alias. - return success( - MatrixClientPeg.get().joinRoom(room_alias).then( - function(room) { - dis.dispatch({ - action: 'view_room', - room_id: room.roomId - }); - }) - ); + return success(); } } return reject(this.getUsage()); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 1973fedbcd..37bcbe7cb0 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -403,10 +403,7 @@ module.exports = React.createClass({ // known to be in (eg. user clicks on a room in the recents panel), supply the ID // If the user is clicking on a room in the context of the alias being presented // to them, supply the room alias. If both are supplied, the room ID will be ignored. - this._viewRoom( - payload.room_id, payload.room_alias, payload.show_settings, payload.event_id, - payload.third_party_invite, payload.oob_data - ); + this._viewRoom(payload); break; case 'view_prev_room': roomIndexDelta = -1; @@ -423,7 +420,7 @@ module.exports = React.createClass({ } roomIndex = (roomIndex + roomIndexDelta) % allRooms.length; if (roomIndex < 0) roomIndex = allRooms.length - 1; - this._viewRoom(allRooms[roomIndex].roomId); + this._viewRoom({ room_id: allRooms[roomIndex].roomId }); break; case 'view_indexed_room': var allRooms = RoomListSorter.mostRecentActivityFirst( @@ -431,7 +428,7 @@ module.exports = React.createClass({ ); var roomIndex = payload.roomIndex; if (allRooms[roomIndex]) { - this._viewRoom(allRooms[roomIndex].roomId); + this._viewRoom({ room_id: allRooms[roomIndex].roomId }); } break; case 'view_user_settings': @@ -491,39 +488,45 @@ module.exports = React.createClass({ // switch view to the given room // - // eventId is optional and will cause a switch to the context of that - // particular event. - // @param {Object} thirdPartyInvite Object containing data about the third party + // @param {Object} room_info Object containing data about the room to be joined + // @param {string=} room_info.room_id ID of the room to join. One of room_id or room_alias must be given. + // @param {string=} room_info.room_alias Alias of the room to join. One of room_id or room_alias must be given. + // @param {boolean=} room_info.auto_join If true, automatically attempt to join the room if not already a member. + // @param {boolean=} room_info.show_settings Makes RoomView show the room settings dialog. + // @param {string=} room_info.event_id ID of the event in this room to show: this will cause a switch to the + // context of that particular event. + // @param {Object=} room_info.third_party_invite Object containing data about the third party // we received to join the room, if any. - // @param {string} thirdPartyInvite.inviteSignUrl 3pid invite sign URL - // @param {string} thirdPartyInvite.invitedwithEmail The email address the invite was sent to - // @param {Object} oob_data Object of additional data about the room + // @param {string=} room_info.third_party_invite.inviteSignUrl 3pid invite sign URL + // @param {string=} room_info.third_party_invite.invitedEmail The email address the invite was sent to + // @param {Object=} room_info.oob_data Object of additional data about the room // that has been passed out-of-band (eg. // room name and avatar from an invite email) - _viewRoom: function(roomId, roomAlias, showSettings, eventId, thirdPartyInvite, oob_data) { + _viewRoom: function(room_info) { // before we switch room, record the scroll state of the current room this._updateScrollMap(); this.focusComposer = true; var newState = { - initialEventId: eventId, - highlightedEventId: eventId, + initialEventId: room_info.event_id, + highlightedEventId: room_info.event_id, initialEventPixelOffset: undefined, page_type: this.PageTypes.RoomView, - thirdPartyInvite: thirdPartyInvite, - roomOobData: oob_data, - currentRoomAlias: roomAlias, + thirdPartyInvite: room_info.third_party_invite, + roomOobData: room_info.oob_data, + currentRoomAlias: room_info.room_alias, + autoJoin: room_info.auto_join, }; - if (!roomAlias) { - newState.currentRoomId = roomId; + if (!room_info.room_alias) { + newState.currentRoomId = room_info.room_id; } // if we aren't given an explicit event id, look for one in the // scrollStateMap. - if (!eventId) { - var scrollState = this.scrollStateMap[roomId]; + if (!room_info.event_id) { + var scrollState = this.scrollStateMap[room_info.room_id]; if (scrollState) { newState.initialEventId = scrollState.focussedEvent; newState.initialEventPixelOffset = scrollState.pixelOffset; @@ -536,8 +539,8 @@ module.exports = React.createClass({ // the new screen yet (we won't be showing it yet) // The normal case where this happens is navigating // to the room in the URL bar on page load. - var presentedId = roomAlias || roomId; - var room = MatrixClientPeg.get().getRoom(roomId); + var presentedId = room_info.room_alias || room_info.room_id; + var room = MatrixClientPeg.get().getRoom(room_info.room_id); if (room) { var theAlias = MatrixTools.getDisplayAliasForRoom(room); if (theAlias) presentedId = theAlias; @@ -553,15 +556,15 @@ module.exports = React.createClass({ // Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color); } - if (eventId) { - presentedId += "/"+eventId; + if (room_info.event_id) { + presentedId += "/"+room_info.event_id; } this.notifyNewScreen('room/'+presentedId); newState.ready = true; } this.setState(newState); - if (this.refs.roomView && showSettings) { + if (this.refs.roomView && room_info.showSettings) { this.refs.roomView.showSettings(true); } }, @@ -1030,6 +1033,7 @@ module.exports = React.createClass({ { this.setState({ roomLoading: false, @@ -172,11 +172,11 @@ module.exports = React.createClass({ room: room, roomLoading: !room, hasUnsentMessages: this._hasUnsentMessages(room), - }, this._updatePeeking); + }, this._onHaveRoom); } }, - _updatePeeking: function() { + _onHaveRoom: function() { // if this is an unknown room then we're in one of three states: // - This is a room we can peek into (search engine) (we can /peek) // - This is a room we can publicly join or were invited to. (we can /join) @@ -187,29 +187,44 @@ module.exports = React.createClass({ // Note that peeking works by room ID and room ID only, as opposed to joining // which must be by alias or invite wherever possible (peeking currently does // not work over federation). - if (!this.state.room && this.state.roomId) { - console.log("Attempting to peek into room %s", this.state.roomId); - MatrixClientPeg.get().peekInRoom(this.state.roomId).then((room) => { - this.setState({ - room: room, - roomLoading: false, - }); - this._onRoomLoaded(room); - }, (err) => { - // This won't necessarily be a MatrixError, but we duck-type - // here and say if it's got an 'errcode' key with the right value, - // it means we can't peek. - if (err.errcode == "M_GUEST_ACCESS_FORBIDDEN") { - // This is fine: the room just isn't peekable (we assume). + // NB. We peek if we are not in the room, although if we try to peek into + // a room in which we have a member event (ie. we've left) synapse will just + // send us the same data as we get in the sync (ie. the last events we saw). + var user_is_in_room = null; + if (this.state.room) { + user_is_in_room = this.state.room.hasMembershipState( + MatrixClientPeg.get().credentials.userId, 'join' + ); + } + + if (!user_is_in_room && this.state.roomId) { + if (this.props.autoJoin) { + this.onJoinButtonClicked(); + } else if (this.state.roomId) { + console.log("Attempting to peek into room %s", this.state.roomId); + + MatrixClientPeg.get().peekInRoom(this.state.roomId).then((room) => { this.setState({ + room: room, roomLoading: false, }); - } else { - throw err; - } - }).done(); - } else if (this.state.room) { + this._onRoomLoaded(room); + }, (err) => { + // This won't necessarily be a MatrixError, but we duck-type + // here and say if it's got an 'errcode' key with the right value, + // it means we can't peek. + if (err.errcode == "M_GUEST_ACCESS_FORBIDDEN") { + // This is fine: the room just isn't peekable (we assume). + this.setState({ + roomLoading: false, + }); + } else { + throw err; + } + }).done(); + } + } else if (user_is_in_room) { MatrixClientPeg.get().stopPeeking(); this._onRoomLoaded(this.state.room); } @@ -992,7 +1007,7 @@ module.exports = React.createClass({ this.setState({ rejecting: true }); - MatrixClientPeg.get().leave(this.props.roomAddress).done(function() { + MatrixClientPeg.get().leave(this.state.roomId).done(function() { dis.dispatch({ action: 'view_next_room' }); self.setState({ rejecting: false