Merge remote-tracking branch 'origin/develop' into read_receipts

This commit is contained in:
David Baker 2015-11-05 15:05:29 +00:00
commit 3114422cb7
20 changed files with 145 additions and 233 deletions

View file

@ -18,7 +18,7 @@ var skin = args._[0];
try { try {
fs.accessSync(path.join('src', 'skins', skin), fs.F_OK); fs.accessSync(path.join('src', 'skins', skin), fs.F_OK);
} catch (e) { } catch (e) {
console.log("Skin "+skin+" not found"); console.log("Skin "+skin+" not found: "+e);
process.exit(1); process.exit(1);
} }

View file

@ -173,17 +173,27 @@ function _onAction(payload) {
console.error("Unknown conf call type: %s", payload.type); console.error("Unknown conf call type: %s", payload.type);
} }
} }
var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
switch (payload.action) { switch (payload.action) {
case 'place_call': case 'place_call':
if (module.exports.getAnyActiveCall()) { if (module.exports.getAnyActiveCall()) {
var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Existing Call", title: "Existing Call",
description: "You are already in a call." description: "You are already in a call."
}); });
return; // don't allow >1 call to be placed. 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); var room = MatrixClientPeg.get().getRoom(payload.room_id);
if (!room) { if (!room) {
console.error("Room %s does not exist.", payload.room_id); console.error("Room %s does not exist.", payload.room_id);
@ -218,11 +228,17 @@ function _onAction(payload) {
case 'place_conference_call': case 'place_conference_call':
console.log("Place conference call in %s", payload.room_id); console.log("Place conference call in %s", payload.room_id);
if (!Modulator.hasConferenceHandler()) { if (!Modulator.hasConferenceHandler()) {
var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
description: "Conference calls are not supported in this client" 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(); var ConferenceHandler = Modulator.getConferenceHandler();
ConferenceHandler.createNewMatrixCall( ConferenceHandler.createNewMatrixCall(
MatrixClientPeg.get(), payload.room_id MatrixClientPeg.get(), payload.room_id
@ -238,6 +254,12 @@ function _onAction(payload) {
payload.call.hangup("busy"); payload.call.hangup("busy");
return; // don't allow >1 call to be received, hangup newer one. 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; var call = payload.call;
_setCallListeners(call); _setCallListeners(call);
_setCallState(call, call.roomId, "ringing"); _setCallState(call, call.roomId, "ringing");

View file

@ -31,6 +31,31 @@ module.exports = {
} }
} }
return null; 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;
} }
} }

View file

@ -34,7 +34,7 @@ module.exports = {
return container; return container;
}, },
createDialogWithElement: function(element, props) { createDialogWithElement: function(element, props, className) {
var self = this; var self = this;
var closeDialog = function() { var closeDialog = function() {
@ -44,7 +44,7 @@ module.exports = {
}; };
var dialog = ( var dialog = (
<div className="mx_Dialog_wrapper"> <div className={"mx_Dialog_wrapper " + className}>
<div className="mx_Dialog"> <div className="mx_Dialog">
{element} {element}
</div> </div>
@ -57,7 +57,7 @@ module.exports = {
return {close: closeDialog}; return {close: closeDialog};
}, },
createDialog: function (Element, props) { createDialog: function (Element, props, className) {
var self = this; var self = this;
var closeDialog = function() { var closeDialog = function() {
@ -69,7 +69,7 @@ module.exports = {
// FIXME: If a dialog uses getDefaultProps it clobbers the onFinished // FIXME: If a dialog uses getDefaultProps it clobbers the onFinished
// property set here so you can't close the dialog from a button click! // property set here so you can't close the dialog from a button click!
var dialog = ( var dialog = (
<div className="mx_Dialog_wrapper"> <div className={"mx_Dialog_wrapper " + className}>
<div className="mx_Dialog"> <div className="mx_Dialog">
<Element {...props} onFinished={closeDialog}/> <Element {...props} onFinished={closeDialog}/>
</div> </div>

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
var MatrixClientPeg = require("./MatrixClientPeg"); var MatrixClientPeg = require("./MatrixClientPeg");
var MatrixTools = require("./MatrixTools");
var dis = require("./dispatcher"); var dis = require("./dispatcher");
var encryption = require("./encryption"); var encryption = require("./encryption");
@ -98,28 +99,14 @@ var commands = {
} }
// Try to find a room with this alias // Try to find a room with this alias
var rooms = MatrixClientPeg.get().getRooms(); var foundRoom = MatrixTools.getRoomForAlias(
var roomId; MatrixClientPeg.get().getRooms(),
for (var i = 0; i < rooms.length; i++) { room_alias
var aliasEvents = rooms[i].currentState.getStateEvents( );
"m.room.aliases" if (foundRoom) { // we've already joined this room, view it.
);
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.
dis.dispatch({ dis.dispatch({
action: 'view_room', action: 'view_room',
room_id: roomId room_id: foundRoom.roomId
}); });
return success(); return success();
} }

View file

@ -1,6 +1,7 @@
var MatrixClientPeg = require("./MatrixClientPeg");
function textForMemberEvent(ev) { 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 senderName = ev.sender ? ev.sender.name : ev.getSender();
var targetName = ev.target ? ev.target.name : ev.getStateKey(); var targetName = ev.target ? ev.target.name : ev.getStateKey();
var reason = ev.getContent().reason ? ( var reason = ev.getContent().reason ? (
@ -58,6 +59,12 @@ function textForTopicEvent(ev) {
return senderDisplayName + ' changed the topic to, "' + ev.getContent().topic + '"'; 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) { function textForMessageEvent(ev) {
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
@ -72,12 +79,14 @@ function textForMessageEvent(ev) {
function textForCallAnswerEvent(event) { function textForCallAnswerEvent(event) {
var senderName = event.sender ? event.sender.name : "Someone"; 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) { function textForCallHangupEvent(event) {
var senderName = event.sender ? event.sender.name : "Someone"; 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) { function textForCallInviteEvent(event) {
@ -88,16 +97,18 @@ function textForCallInviteEvent(event) {
event.getContent().offer.sdp.indexOf('m=video') !== -1) { event.getContent().offer.sdp.indexOf('m=video') !== -1) {
type = "video"; 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 = { var handlers = {
'm.room.message': textForMessageEvent, 'm.room.message': textForMessageEvent,
'm.room.topic': textForTopicEvent, 'm.room.name': textForRoomNameEvent,
'm.room.member': textForMemberEvent, 'm.room.topic': textForTopicEvent,
'm.call.invite': textForCallInviteEvent, 'm.room.member': textForMemberEvent,
'm.call.answer': textForCallAnswerEvent, 'm.call.invite': textForCallInviteEvent,
'm.call.hangup': textForCallHangupEvent, 'm.call.answer': textForCallAnswerEvent,
'm.call.hangup': textForCallHangupEvent,
}; };
module.exports = { module.exports = {

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -161,6 +161,7 @@ module.exports = {
onChatClick: function() { onChatClick: function() {
// check if there are any existing rooms with just us and them (1:1) // 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. // If so, just view that room. If not, create a private room with them.
var self = this;
var rooms = MatrixClientPeg.get().getRooms(); var rooms = MatrixClientPeg.get().getRooms();
var userIds = [ var userIds = [
this.props.member.userId, this.props.member.userId,
@ -189,23 +190,28 @@ module.exports = {
action: 'view_room', action: 'view_room',
room_id: existingRoomId room_id: existingRoomId
}); });
this.props.onFinished();
} }
else { else {
self.setState({ creatingRoom: true });
MatrixClientPeg.get().createRoom({ MatrixClientPeg.get().createRoom({
invite: [this.props.member.userId], invite: [this.props.member.userId],
preset: "private_chat" preset: "private_chat"
}).done(function(res) { }).done(function(res) {
self.setState({ creatingRoom: false });
dis.dispatch({ dis.dispatch({
action: 'view_room', action: 'view_room',
room_id: res.room_id room_id: res.room_id
}); });
self.props.onFinished();
}, function(err) { }, function(err) {
self.setState({ creatingRoom: false });
console.error( console.error(
"Failed to create room: %s", JSON.stringify(err) "Failed to create room: %s", JSON.stringify(err)
); );
self.props.onFinished();
}); });
} }
this.props.onFinished();
}, },
// FIXME: this is horribly duplicated with MemberTile's onLeaveClick. // FIXME: this is horribly duplicated with MemberTile's onLeaveClick.
@ -249,7 +255,8 @@ module.exports = {
modifyLevel: false modifyLevel: false
}, },
muted: false, muted: false,
isTargetMod: false isTargetMod: false,
creatingRoom: false
} }
}, },

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -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 = {
};

View file

@ -22,6 +22,7 @@ var dis = require("../../dispatcher");
var sdk = require('../../index'); var sdk = require('../../index');
var MatrixTools = require('../../MatrixTools'); var MatrixTools = require('../../MatrixTools');
var linkifyMatrix = require("../../linkify-matrix");
var Cas = require("../../CasLogic"); var Cas = require("../../CasLogic");
@ -67,6 +68,15 @@ module.exports = {
} else { } else {
this.notifyNewScreen('login'); 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() { componentWillUnmount: function() {
@ -214,7 +224,19 @@ module.exports = {
} }
break; break;
case 'view_room_alias': 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({ dis.dispatch({
action: 'view_room', action: 'view_room',
room_id: result.room_id room_id: result.room_id
@ -325,6 +347,9 @@ module.exports = {
onKeyDown: function(ev) { onKeyDown: function(ev) {
if (ev.altKey) { 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) { if (ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) {
dis.dispatch({ dis.dispatch({
action: 'view_indexed_room', action: 'view_indexed_room',
@ -334,6 +359,7 @@ module.exports = {
ev.preventDefault(); ev.preventDefault();
return; return;
} }
*/
switch (ev.keyCode) { switch (ev.keyCode) {
case 38: case 38:
dis.dispatch({action: 'view_prev_room'}); dis.dispatch({action: 'view_prev_room'});

View file

@ -94,8 +94,14 @@ module.exports = {
self.setStep("stage_m.login.password"); self.setStep("stage_m.login.password");
if (error.httpStatus == 400 && loginParams.medium) { if (error.httpStatus == 400 && loginParams.medium) {
self.setState({errorText: 'This Home Server does not support login using email address.'}); 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 + ")"
});
} }
}); });
}, },

View file

@ -22,7 +22,8 @@ module.exports = {
PasswordMismatch: 'PasswordMismatch', PasswordMismatch: 'PasswordMismatch',
TooShort: 'TooShort', TooShort: 'TooShort',
Missing: 'Missing', Missing: 'Missing',
InUse: 'InUse' InUse: 'InUse',
Length: 'Length'
}, },
getInitialState: function() { getInitialState: function() {

View file

@ -95,17 +95,26 @@ function matrixLinkify(linkify) {
S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID); 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 = { matrixLinkify.options = {
formatHref: function (href, type) { events: function (href, type) {
switch (type) { switch (type) {
case 'roomalias': case "userid":
return '#'; return {
case 'userid': click: function(e) {
return '#'; matrixLinkify.onUserClick(e, href);
default: }
return href; };
case "roomalias":
return {
click: function(e) {
matrixLinkify.onAliasClick(e, href);
}
};
} }
} }
} };
module.exports = matrixLinkify; module.exports = matrixLinkify;