diff --git a/reskindex.js b/reskindex.js index f8d45493d3..e028979122 100755 --- a/reskindex.js +++ b/reskindex.js @@ -18,7 +18,7 @@ var skin = args._[0]; try { fs.accessSync(path.join('src', 'skins', skin), fs.F_OK); } catch (e) { - console.log("Skin "+skin+" not found"); + console.log("Skin "+skin+" not found: "+e); process.exit(1); } diff --git a/src/CallHandler.js b/src/CallHandler.js index cf8460db6c..b3af0e8337 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -173,17 +173,27 @@ function _onAction(payload) { console.error("Unknown conf call type: %s", payload.type); } } + var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); switch (payload.action) { case 'place_call': if (module.exports.getAnyActiveCall()) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Existing Call", description: "You are already in a call." }); return; // don't allow >1 call to be placed. } + + // if the runtime env doesn't do VoIP, whine. + if (!MatrixClientPeg.get().supportsVoip()) { + Modal.createDialog(ErrorDialog, { + title: "VoIP is unsupported", + description: "You cannot place VoIP calls in this browser." + }); + return; + } + var room = MatrixClientPeg.get().getRoom(payload.room_id); if (!room) { console.error("Room %s does not exist.", payload.room_id); @@ -218,11 +228,17 @@ function _onAction(payload) { case 'place_conference_call': console.log("Place conference call in %s", payload.room_id); if (!Modulator.hasConferenceHandler()) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); Modal.createDialog(ErrorDialog, { description: "Conference calls are not supported in this client" }); - } else { + } + else if (!MatrixClientPeg.get().supportsVoip()) { + Modal.createDialog(ErrorDialog, { + title: "VoIP is unsupported", + description: "You cannot place VoIP calls in this browser." + }); + } + else { var ConferenceHandler = Modulator.getConferenceHandler(); ConferenceHandler.createNewMatrixCall( MatrixClientPeg.get(), payload.room_id @@ -238,6 +254,12 @@ function _onAction(payload) { payload.call.hangup("busy"); return; // don't allow >1 call to be received, hangup newer one. } + + // if the runtime env doesn't do VoIP, stop here. + if (!MatrixClientPeg.get().supportsVoip()) { + return; + } + var call = payload.call; _setCallListeners(call); _setCallState(call, call.roomId, "ringing"); diff --git a/src/MatrixTools.js b/src/MatrixTools.js index 5c6dca8b33..6c7a9ee9ba 100644 --- a/src/MatrixTools.js +++ b/src/MatrixTools.js @@ -31,6 +31,31 @@ module.exports = { } } return null; + }, + + /** + * 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/Modal.js b/src/Modal.js index 8566022060..bf7758a1a8 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -34,7 +34,7 @@ module.exports = { return container; }, - createDialogWithElement: function(element, props) { + createDialogWithElement: function(element, props, className) { var self = this; var closeDialog = function() { @@ -44,7 +44,7 @@ module.exports = { }; var dialog = ( -
+
{element}
@@ -57,7 +57,7 @@ module.exports = { return {close: closeDialog}; }, - createDialog: function (Element, props) { + createDialog: function (Element, props, className) { var self = this; var closeDialog = function() { @@ -69,7 +69,7 @@ module.exports = { // FIXME: If a dialog uses getDefaultProps it clobbers the onFinished // property set here so you can't close the dialog from a button click! var dialog = ( -
+
diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 08d68331f8..e6ea7533dc 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -15,6 +15,7 @@ limitations under the License. */ var MatrixClientPeg = require("./MatrixClientPeg"); +var MatrixTools = require("./MatrixTools"); var dis = require("./dispatcher"); var encryption = require("./encryption"); @@ -98,28 +99,14 @@ var commands = { } // Try to find a room with this alias - var rooms = MatrixClientPeg.get().getRooms(); - var roomId; - 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) { - roomId = rooms[i].roomId; - break; - } - } - if (roomId) { break; } - } - if (roomId) { break; } - } - if (roomId) { // we've already joined this room, view it. + var foundRoom = MatrixTools.getRoomForAlias( + MatrixClientPeg.get().getRooms(), + room_alias + ); + if (foundRoom) { // we've already joined this room, view it. dis.dispatch({ action: 'view_room', - room_id: roomId + room_id: foundRoom.roomId }); return success(); } diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 71354325bd..439d7b9ef5 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -1,6 +1,7 @@ +var MatrixClientPeg = require("./MatrixClientPeg"); function textForMemberEvent(ev) { - // XXX: SYJS-16 + // XXX: SYJS-16 "sender is sometimes null for join messages" var senderName = ev.sender ? ev.sender.name : ev.getSender(); var targetName = ev.target ? ev.target.name : ev.getStateKey(); var reason = ev.getContent().reason ? ( @@ -58,6 +59,12 @@ function textForTopicEvent(ev) { return senderDisplayName + ' changed the topic to, "' + ev.getContent().topic + '"'; }; +function textForRoomNameEvent(ev) { + var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + + return senderDisplayName + ' changed the room name to "' + ev.getContent().name + '"'; +}; + function textForMessageEvent(ev) { var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); @@ -72,12 +79,14 @@ function textForMessageEvent(ev) { function textForCallAnswerEvent(event) { var senderName = event.sender ? event.sender.name : "Someone"; - return senderName + " answered the call."; + var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)"; + return senderName + " answered the call." + supported; }; function textForCallHangupEvent(event) { var senderName = event.sender ? event.sender.name : "Someone"; - return senderName + " ended the call."; + var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)"; + return senderName + " ended the call." + supported; }; function textForCallInviteEvent(event) { @@ -88,16 +97,18 @@ function textForCallInviteEvent(event) { event.getContent().offer.sdp.indexOf('m=video') !== -1) { type = "video"; } - return senderName + " placed a " + type + " call."; + var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)"; + return senderName + " placed a " + type + " call." + supported; }; var handlers = { 'm.room.message': textForMessageEvent, - 'm.room.topic': textForTopicEvent, - 'm.room.member': textForMemberEvent, - 'm.call.invite': textForCallInviteEvent, - 'm.call.answer': textForCallAnswerEvent, - 'm.call.hangup': textForCallHangupEvent, + 'm.room.name': textForRoomNameEvent, + 'm.room.topic': textForTopicEvent, + 'm.room.member': textForMemberEvent, + 'm.call.invite': textForCallInviteEvent, + 'm.call.answer': textForCallAnswerEvent, + 'm.call.hangup': textForCallHangupEvent, }; module.exports = { diff --git a/src/controllers/atoms/MessageTimestamp.js b/src/controllers/atoms/MessageTimestamp.js deleted file mode 100644 index 8aa688b21e..0000000000 --- a/src/controllers/atoms/MessageTimestamp.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; - diff --git a/src/controllers/atoms/voip/VideoFeed.js b/src/controllers/atoms/voip/VideoFeed.js deleted file mode 100644 index 3d34134daa..0000000000 --- a/src/controllers/atoms/voip/VideoFeed.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -module.exports = { -}; - diff --git a/src/controllers/molecules/EventAsTextTile.js b/src/controllers/molecules/EventAsTextTile.js deleted file mode 100644 index 3d34134daa..0000000000 --- a/src/controllers/molecules/EventAsTextTile.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -module.exports = { -}; - diff --git a/src/controllers/molecules/MImageTile.js b/src/controllers/molecules/MImageTile.js deleted file mode 100644 index 8aa688b21e..0000000000 --- a/src/controllers/molecules/MImageTile.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; - diff --git a/src/controllers/molecules/MRoomMemberTile.js b/src/controllers/molecules/MRoomMemberTile.js deleted file mode 100644 index 8aa688b21e..0000000000 --- a/src/controllers/molecules/MRoomMemberTile.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; - diff --git a/src/controllers/molecules/MatrixToolbar.js b/src/controllers/molecules/MatrixToolbar.js deleted file mode 100644 index 8aa688b21e..0000000000 --- a/src/controllers/molecules/MatrixToolbar.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; - diff --git a/src/controllers/molecules/MemberInfo.js b/src/controllers/molecules/MemberInfo.js index 24e4afe5fd..23ae2e5fb1 100644 --- a/src/controllers/molecules/MemberInfo.js +++ b/src/controllers/molecules/MemberInfo.js @@ -161,6 +161,7 @@ module.exports = { onChatClick: function() { // check if there are any existing rooms with just us and them (1:1) // If so, just view that room. If not, create a private room with them. + var self = this; var rooms = MatrixClientPeg.get().getRooms(); var userIds = [ this.props.member.userId, @@ -189,23 +190,28 @@ module.exports = { action: 'view_room', room_id: existingRoomId }); + this.props.onFinished(); } else { + self.setState({ creatingRoom: true }); MatrixClientPeg.get().createRoom({ invite: [this.props.member.userId], preset: "private_chat" }).done(function(res) { + self.setState({ creatingRoom: false }); dis.dispatch({ action: 'view_room', room_id: res.room_id }); + self.props.onFinished(); }, function(err) { + self.setState({ creatingRoom: false }); console.error( "Failed to create room: %s", JSON.stringify(err) ); + self.props.onFinished(); }); } - this.props.onFinished(); }, // FIXME: this is horribly duplicated with MemberTile's onLeaveClick. @@ -249,7 +255,8 @@ module.exports = { modifyLevel: false }, muted: false, - isTargetMod: false + isTargetMod: false, + creatingRoom: false } }, diff --git a/src/controllers/molecules/SenderProfile.js b/src/controllers/molecules/SenderProfile.js deleted file mode 100644 index 8aa688b21e..0000000000 --- a/src/controllers/molecules/SenderProfile.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; - diff --git a/src/controllers/molecules/UnknownMessageTile.js b/src/controllers/molecules/UnknownMessageTile.js deleted file mode 100644 index d0977e0043..0000000000 --- a/src/controllers/molecules/UnknownMessageTile.js +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -module.exports = { -}; diff --git a/src/controllers/molecules/voip/VideoView.js b/src/controllers/molecules/voip/VideoView.js deleted file mode 100644 index 3d34134daa..0000000000 --- a/src/controllers/molecules/voip/VideoView.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -module.exports = { -}; - diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index edb55eb1b0..fd23607b87 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -22,6 +22,7 @@ var dis = require("../../dispatcher"); var sdk = require('../../index'); var MatrixTools = require('../../MatrixTools'); +var linkifyMatrix = require("../../linkify-matrix"); var Cas = require("../../CasLogic"); @@ -67,6 +68,15 @@ module.exports = { } else { this.notifyNewScreen('login'); } + + // this can technically be done anywhere but doing this here keeps all + // the routing url path logic together. + if (this.onAliasClick) { + linkifyMatrix.onAliasClick = this.onAliasClick; + } + if (this.onUserClick) { + linkifyMatrix.onUserClick = this.onUserClick; + } }, componentWillUnmount: function() { @@ -214,7 +224,19 @@ module.exports = { } break; case 'view_room_alias': - MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done(function(result) { + var foundRoom = MatrixTools.getRoomForAlias( + MatrixClientPeg.get().getRooms(), payload.room_alias + ); + if (foundRoom) { + dis.dispatch({ + action: 'view_room', + room_id: foundRoom.roomId + }); + return; + } + // resolve the alias and *then* view it + MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done( + function(result) { dis.dispatch({ action: 'view_room', room_id: result.room_id @@ -325,6 +347,9 @@ module.exports = { onKeyDown: function(ev) { if (ev.altKey) { + /* + // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers + // Will need to find a better meta key if anyone actually cares about using this. if (ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) { dis.dispatch({ action: 'view_indexed_room', @@ -334,6 +359,7 @@ module.exports = { ev.preventDefault(); return; } + */ switch (ev.keyCode) { case 38: dis.dispatch({action: 'view_prev_room'}); diff --git a/src/controllers/templates/Login.js b/src/controllers/templates/Login.js index c14ed28c4a..3472bf32ce 100644 --- a/src/controllers/templates/Login.js +++ b/src/controllers/templates/Login.js @@ -94,8 +94,14 @@ module.exports = { self.setStep("stage_m.login.password"); if (error.httpStatus == 400 && loginParams.medium) { self.setState({errorText: 'This Home Server does not support login using email address.'}); - } else { - self.setState({errorText: 'Login failed.'}); + } + else if (error.httpStatus === 403) { + self.setState({errorText: 'Incorrect username and/or password.'}); + } + else { + self.setState({ + errorText: 'There was a problem logging in. (HTTP ' + error.httpStatus + ")" + }); } }); }, diff --git a/src/controllers/templates/Register.js b/src/controllers/templates/Register.js index 294329e42e..53d1ad1219 100644 --- a/src/controllers/templates/Register.js +++ b/src/controllers/templates/Register.js @@ -22,7 +22,8 @@ module.exports = { PasswordMismatch: 'PasswordMismatch', TooShort: 'TooShort', Missing: 'Missing', - InUse: 'InUse' + InUse: 'InUse', + Length: 'Length' }, getInitialState: function() { diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index e92a3efc91..90b1938d51 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -95,17 +95,26 @@ function matrixLinkify(linkify) { S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID); } +matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); }; +matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); }; + matrixLinkify.options = { - formatHref: function (href, type) { + events: function (href, type) { switch (type) { - case 'roomalias': - return '#'; - case 'userid': - return '#'; - default: - return href; + case "userid": + return { + click: function(e) { + matrixLinkify.onUserClick(e, href); + } + }; + case "roomalias": + return { + click: function(e) { + matrixLinkify.onAliasClick(e, href); + } + }; } } -} +}; module.exports = matrixLinkify;