Merge branch 'develop' into kegan/room-settings-refactor
commit
74e16ac83e
|
@ -41,6 +41,7 @@ module.exports.components['views.create_room.RoomAlias'] = require('./components
|
||||||
module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog');
|
module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog');
|
||||||
module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt');
|
module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt');
|
||||||
module.exports.components['views.dialogs.QuestionDialog'] = require('./components/views/dialogs/QuestionDialog');
|
module.exports.components['views.dialogs.QuestionDialog'] = require('./components/views/dialogs/QuestionDialog');
|
||||||
|
module.exports.components['views.dialogs.SetDisplayNameDialog'] = require('./components/views/dialogs/SetDisplayNameDialog');
|
||||||
module.exports.components['views.dialogs.TextInputDialog'] = require('./components/views/dialogs/TextInputDialog');
|
module.exports.components['views.dialogs.TextInputDialog'] = require('./components/views/dialogs/TextInputDialog');
|
||||||
module.exports.components['views.elements.EditableText'] = require('./components/views/elements/EditableText');
|
module.exports.components['views.elements.EditableText'] = require('./components/views/elements/EditableText');
|
||||||
module.exports.components['views.elements.PowerSelector'] = require('./components/views/elements/PowerSelector');
|
module.exports.components['views.elements.PowerSelector'] = require('./components/views/elements/PowerSelector');
|
||||||
|
|
|
@ -586,8 +586,7 @@ module.exports = React.createClass({
|
||||||
Presence.start();
|
Presence.start();
|
||||||
cli.startClient({
|
cli.startClient({
|
||||||
pendingEventOrdering: "end",
|
pendingEventOrdering: "end",
|
||||||
// deliberately huge limit for now to avoid hitting gappy /sync's until gappy /sync performance improves
|
initialSyncLimit: 20,
|
||||||
initialSyncLimit: 250,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,7 @@ module.exports = React.createClass({
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this.last_rr_sent_event_id = undefined;
|
this.last_rr_sent_event_id = undefined;
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
|
MatrixClientPeg.get().on("Room", this.onRoom);
|
||||||
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
||||||
MatrixClientPeg.get().on("Room.name", this.onRoomName);
|
MatrixClientPeg.get().on("Room.name", this.onRoomName);
|
||||||
MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData);
|
MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData);
|
||||||
|
@ -163,10 +164,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
console.log("Attempting to peek into room %s", this.props.roomId);
|
console.log("Attempting to peek into room %s", this.props.roomId);
|
||||||
|
|
||||||
roomProm = MatrixClientPeg.get().peekInRoom(this.props.roomId).catch((err) => {
|
roomProm = MatrixClientPeg.get().peekInRoom(this.props.roomId).then((room) => {
|
||||||
console.error("Failed to peek into room: %s", err);
|
|
||||||
throw err;
|
|
||||||
}).then((room) => {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
room: room
|
room: room
|
||||||
});
|
});
|
||||||
|
@ -180,6 +178,18 @@ module.exports = React.createClass({
|
||||||
roomProm.then((room) => {
|
roomProm.then((room) => {
|
||||||
this._calculatePeekRules(room);
|
this._calculatePeekRules(room);
|
||||||
return this._initTimeline(this.props);
|
return this._initTimeline(this.props);
|
||||||
|
}).catch((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({
|
||||||
|
timelineLoading: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}).done();
|
}).done();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -214,6 +224,8 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
events: [],
|
events: [],
|
||||||
|
searchResults: null, // we may have arrived here by clicking on a
|
||||||
|
// search result. Hide the results.
|
||||||
timelineLoading: true,
|
timelineLoading: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -264,6 +276,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
if (MatrixClientPeg.get()) {
|
if (MatrixClientPeg.get()) {
|
||||||
|
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
||||||
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||||
MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData);
|
MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData);
|
||||||
|
@ -409,6 +422,20 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoom: function(room) {
|
||||||
|
// This event is fired when the room is 'stored' by the JS SDK, which
|
||||||
|
// means it's now a fully-fledged room object ready to be used, so
|
||||||
|
// set it in our state and start using it (ie. init the timeline)
|
||||||
|
// This will happen if we start off viewing a room we're not joined,
|
||||||
|
// then join it whilst RoomView is looking at that room.
|
||||||
|
if (room.roomId == this.props.roomId) {
|
||||||
|
this.setState({
|
||||||
|
room: room
|
||||||
|
});
|
||||||
|
this._initTimeline(this.props).done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onRoomName: function(room) {
|
onRoomName: function(room) {
|
||||||
if (room.roomId == this.props.roomId) {
|
if (room.roomId == this.props.roomId) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -679,12 +706,47 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
onJoinButtonClicked: function(ev) {
|
onJoinButtonClicked: function(ev) {
|
||||||
var self = this;
|
var self = this;
|
||||||
MatrixClientPeg.get().joinRoom(this.props.roomId).done(function() {
|
|
||||||
|
var cli = MatrixClientPeg.get();
|
||||||
|
var display_name_promise = q();
|
||||||
|
// if this is the first room we're joining, check the user has a display name
|
||||||
|
// and if they don't, prompt them to set one.
|
||||||
|
// NB. This unfortunately does not re-use the ChangeDisplayName component because
|
||||||
|
// it doesn't behave quite as desired here (we want an input field here rather than
|
||||||
|
// content-editable, and we want a default).
|
||||||
|
if (MatrixClientPeg.get().getRooms().length == 0) {
|
||||||
|
display_name_promise = cli.getProfileInfo(cli.credentials.userId).then((result) => {
|
||||||
|
if (!result.displayname) {
|
||||||
|
var SetDisplayNameDialog = sdk.getComponent('views.dialogs.SetDisplayNameDialog');
|
||||||
|
var dialog_defer = q.defer();
|
||||||
|
var dialog_ref;
|
||||||
|
var modal;
|
||||||
|
var dialog_instance = <SetDisplayNameDialog currentDisplayName={result.displayname} ref={(r) => {
|
||||||
|
dialog_ref = r;
|
||||||
|
}} onFinished={() => {
|
||||||
|
cli.setDisplayName(dialog_ref.getValue()).done(() => {
|
||||||
|
dialog_defer.resolve();
|
||||||
|
});
|
||||||
|
modal.close();
|
||||||
|
}} />
|
||||||
|
modal = Modal.createDialogWithElement(dialog_instance);
|
||||||
|
return dialog_defer.promise;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
display_name_promise.then(() => {
|
||||||
|
return MatrixClientPeg.get().joinRoom(this.props.roomId)
|
||||||
|
}).done(function() {
|
||||||
// It is possible that there is no Room yet if state hasn't come down
|
// It is possible that there is no Room yet if state hasn't come down
|
||||||
// from /sync - joinRoom will resolve when the HTTP request to join succeeds,
|
// from /sync - joinRoom will resolve when the HTTP request to join succeeds,
|
||||||
// NOT when it comes down /sync. If there is no room, we'll keep the
|
// NOT when it comes down /sync. If there is no room, we'll keep the
|
||||||
// joining flag set until we see it. Likewise, if our state is not
|
// joining flag set until we see it. Likewise, if our state is not
|
||||||
// "join" we'll keep this flag set until it comes down /sync.
|
// "join" we'll keep this flag set until it comes down /sync.
|
||||||
|
|
||||||
|
// We'll need to initialise the timeline when joining, but due to
|
||||||
|
// the above, we can't do it here: we do it in onRoom instead,
|
||||||
|
// once we have a useable room object.
|
||||||
var room = MatrixClientPeg.get().getRoom(self.props.roomId);
|
var room = MatrixClientPeg.get().getRoom(self.props.roomId);
|
||||||
var me = MatrixClientPeg.get().credentials.userId;
|
var me = MatrixClientPeg.get().credentials.userId;
|
||||||
self.setState({
|
self.setState({
|
||||||
|
@ -863,6 +925,14 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSearchResultSelected: function(result) {
|
||||||
|
var event = result.context.getEvent();
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: event.getRoomId(),
|
||||||
|
event_id: event.getId(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSearchResultTiles: function() {
|
getSearchResultTiles: function() {
|
||||||
var EventTile = sdk.getComponent('rooms.EventTile');
|
var EventTile = sdk.getComponent('rooms.EventTile');
|
||||||
|
@ -926,7 +996,8 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
ret.push(<SearchResultTile key={mxEv.getId()}
|
ret.push(<SearchResultTile key={mxEv.getId()}
|
||||||
searchResult={result}
|
searchResult={result}
|
||||||
searchHighlights={this.state.searchHighlights}/>);
|
searchHighlights={this.state.searchHighlights}
|
||||||
|
onSelect={this._onSearchResultSelected.bind(this, result)}/>);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
@ -1005,8 +1076,15 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
var eventId = mxEv.getId();
|
var eventId = mxEv.getId();
|
||||||
var highlight = (eventId == this.props.highlightedEventId);
|
var highlight = (eventId == this.props.highlightedEventId);
|
||||||
|
|
||||||
|
// we can't use local echoes as scroll tokens, because their event IDs change.
|
||||||
|
// Local echos have a send "status".
|
||||||
|
var scrollToken = mxEv.status ? undefined : eventId;
|
||||||
|
|
||||||
ret.push(
|
ret.push(
|
||||||
<li key={eventId} ref={this._collectEventNode.bind(this, eventId)} data-scroll-token={eventId}>
|
<li key={eventId}
|
||||||
|
ref={this._collectEventNode.bind(this, eventId)}
|
||||||
|
data-scroll-token={scrollToken}>
|
||||||
<EventTile mxEvent={mxEv} continuation={continuation}
|
<EventTile mxEvent={mxEv} continuation={continuation}
|
||||||
last={last} isSelectedEvent={highlight}/>
|
last={last} isSelectedEvent={highlight}/>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var React = require("react");
|
||||||
|
var sdk = require("../../../index.js");
|
||||||
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'SetDisplayNameDialog',
|
||||||
|
propTypes: {
|
||||||
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
|
currentDisplayName: React.PropTypes.string,
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
value: this.props.currentDisplayName || "Guest "+MatrixClientPeg.get().getUserIdLocalpart(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue: function() {
|
||||||
|
return this.state.value;
|
||||||
|
},
|
||||||
|
|
||||||
|
onValueChange: function(ev) {
|
||||||
|
this.setState({
|
||||||
|
value: ev.target.value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onFormSubmit: function(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.props.onFinished();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div className="mx_SetDisplayNameDialog">
|
||||||
|
<div className="mx_Dialog_title">
|
||||||
|
Set a Display Name
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
Your display name is how you'll appear to others when you speak in rooms. What would you like it to be?
|
||||||
|
</div>
|
||||||
|
<form onSubmit={this.onFormSubmit}>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<input type="text" value={this.state.value}
|
||||||
|
autoFocus={true} onChange={this.onValueChange} size="30"
|
||||||
|
className="mx_SetDisplayNameDialog_input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<input type="submit" value="Set" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue