mirror of
https://github.com/element-hq/element-web
synced 2024-11-26 11:15:53 +03:00
Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing
This commit is contained in:
commit
0b1b6057d6
25 changed files with 434 additions and 88 deletions
1
examples/trivial/fonts
Symbolic link
1
examples/trivial/fonts
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../skins/base/fonts/
|
|
@ -40,9 +40,17 @@ function routeUrl(location) {
|
|||
}
|
||||
}
|
||||
window.matrixChat.showScreen('register', params);
|
||||
} else {
|
||||
window.matrixChat.showScreen(location.hash.substring(2));
|
||||
}
|
||||
}
|
||||
|
||||
function onHashChange(ev) {
|
||||
routeUrl(window.location);
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
var loaded = false;
|
||||
|
||||
window.onload = function() {
|
||||
|
|
|
@ -55,6 +55,8 @@ limitations under the License.
|
|||
|
||||
.mx_MemberInfo_field {
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_button {
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
.mx_MemberTile {
|
||||
cursor: pointer;
|
||||
display: table-row;
|
||||
height: 49px;
|
||||
}
|
||||
|
||||
.mx_MemberTile_avatar {
|
||||
|
@ -36,6 +37,24 @@ limitations under the License.
|
|||
background-color: #dbdbdb;
|
||||
}
|
||||
|
||||
.mx_MemberTile_inviteEditing .mx_MemberTile_avatar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_MemberTile_inviteEditing .mx_MemberTile_name {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.mx_MemberTile_inviteEditing .mx_MemberTile_name input {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #c7c7c7;
|
||||
font-weight: 300;
|
||||
font-size: 14px;
|
||||
padding: 9px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.mx_MemberTile_power {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
|
@ -52,10 +71,14 @@ limitations under the License.
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mx_MemberTile_unavailable {
|
||||
.mx_MemberTile_unavailable .mx_MemberTile_avatar,
|
||||
.mx_MemberTile_unavailable .mx_MemberTile_name
|
||||
{
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.mx_MemberTile_offline {
|
||||
.mx_MemberTile_offline .mx_MemberTile_avatar,
|
||||
.mx_MemberTile_offline .mx_MemberTile_name
|
||||
{
|
||||
opacity: 0.5;
|
||||
}
|
|
@ -43,6 +43,26 @@ limitations under the License.
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_hangupButton {
|
||||
height: 48px;
|
||||
margin-top: 18px;
|
||||
background-color: #80cef4;
|
||||
border-radius: 48px;
|
||||
margin-right: 8px;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
|
||||
-webkit-box-ordinal-group: 2;
|
||||
-moz-box-ordinal-group: 2;
|
||||
-ms-flex-order: 2;
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
|
||||
-webkit-flex: 0 0 90px;
|
||||
flex: 0 0 90px;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_rightRow {
|
||||
height: 48px;
|
||||
margin-top: 18px;
|
||||
|
@ -50,11 +70,11 @@ limitations under the License.
|
|||
border-radius: 48px;
|
||||
border: 1px solid #a9dbf4;
|
||||
|
||||
-webkit-box-ordinal-group: 2;
|
||||
-moz-box-ordinal-group: 2;
|
||||
-ms-flex-order: 2;
|
||||
-webkit-order: 2;
|
||||
order: 2;
|
||||
-webkit-box-ordinal-group: 3;
|
||||
-moz-box-ordinal-group: 3;
|
||||
-ms-flex-order: 3;
|
||||
-webkit-order: 3;
|
||||
order: 3;
|
||||
|
||||
-webkit-flex: 0 0 200px;
|
||||
flex: 0 0 200px;
|
||||
|
@ -66,6 +86,15 @@ limitations under the License.
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_simpleHeader {
|
||||
line-height: 88px;
|
||||
color: #80cef4;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
overflow: scroll;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_name {
|
||||
vertical-align: middle;
|
||||
height: 28px;
|
||||
|
|
|
@ -43,7 +43,7 @@ limitations under the License.
|
|||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_DirectoryMenu {
|
||||
.mx_LeftPanel .mx_BottomLeftMenu {
|
||||
-webkit-box-ordinal-group: 3;
|
||||
-moz-box-ordinal-group: 3;
|
||||
-ms-flex-order: 3;
|
||||
|
@ -56,15 +56,15 @@ limitations under the License.
|
|||
border-top: 1px solid #f3f8fa;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_DirectoryMenu .mx_RoomTile {
|
||||
.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile {
|
||||
color: #378bb4;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_DirectoryMenu .mx_RoomTile_avatar {
|
||||
.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile_avatar {
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_DirectoryMenu .mx_DirectoryMenu_options {
|
||||
.mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
}
|
40
skins/base/css/organisms/RoomDirectory.css
Normal file
40
skins/base/css/organisms/RoomDirectory.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_RoomDirectory {
|
||||
max-width: 720px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_input {
|
||||
margin: auto;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #c7c7c7;
|
||||
font-weight: 300;
|
||||
font-size: 14px;
|
||||
padding: 9px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_table td,
|
||||
.mx_RoomDirectory_table th, {
|
||||
padding: 6px;
|
||||
}
|
|
@ -105,6 +105,20 @@ limitations under the License.
|
|||
border-top: 1px solid #a8dbf3;
|
||||
}
|
||||
|
||||
.mx_RoomView_typingBar {
|
||||
margin-top: 17px;
|
||||
margin-left: 56px;
|
||||
color: #818794;
|
||||
}
|
||||
|
||||
.mx_RoomView_typingBar img {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
margin-left: -64px;
|
||||
margin-top: -7px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.mx_RoomView .mx_MessageComposer {
|
||||
-webkit-box-ordinal-group: 5;
|
||||
-moz-box-ordinal-group: 5;
|
||||
|
|
BIN
skins/base/img/typing.png
Normal file
BIN
skins/base/img/typing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 236 B |
|
@ -33,6 +33,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
onClickDiv: function() {
|
||||
console.log("onClickDiv triggered");
|
||||
this.setState({
|
||||
phase: this.Phases.Edit,
|
||||
})
|
||||
|
@ -57,12 +58,12 @@ module.exports = React.createClass({
|
|||
if (this.state.value) {
|
||||
editable_el = <div ref="display_div" onClick={this.onClickDiv}>{this.state.value}</div>;
|
||||
} else {
|
||||
editable_el = <div ref="display_div" onClick={this.onClickDiv}><i>{this.props.placeHolder}</i></div>;
|
||||
editable_el = <div ref="display_div" onClick={this.onClickDiv}>{this.props.label}</div>;
|
||||
}
|
||||
} else if (this.state.phase == this.Phases.Edit) {
|
||||
editable_el = (
|
||||
<div>
|
||||
<input type="text" defaultValue={this.state.value} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onFinish} autoFocus/>
|
||||
<input type="text" defaultValue={this.state.value} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onFinish} placeholder={this.props.placeHolder} autoFocus/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -21,34 +21,34 @@ var classNames = require('classnames');
|
|||
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
//var DirectoryMenuController = require("../../../../src/controllers/molecules/DirectoryMenuController");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'DirectoryMenu',
|
||||
// mixins: [DirectoryMenuController],
|
||||
displayName: 'BottomLeftMenu',
|
||||
|
||||
// FIXME: should these onClicks be in the controller instead?
|
||||
onSettingsClick: function() {
|
||||
dis.dispatch({action: 'view_user_settings'});
|
||||
},
|
||||
|
||||
onRoomDirectoryClick: function() {
|
||||
dis.dispatch({action: 'view_room_directory'});
|
||||
},
|
||||
|
||||
onCreateRoomClick: function() {
|
||||
dis.dispatch({action: 'view_create_room'});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_DirectoryMenu">
|
||||
<div className="mx_DirectoryMenu_options">
|
||||
<div className="mx_BottomLeftMenu">
|
||||
<div className="mx_BottomLeftMenu_options">
|
||||
<div className="mx_RoomTile" onClick={this.onCreateRoomClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/create-big.png" width="42" height="42"/>
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">Create new room</div>
|
||||
</div>
|
||||
<div className="mx_RoomTile">
|
||||
<div className="mx_RoomTile" onClick={this.onRoomDirectoryClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/directory-big.png" width="42" height="42"/>
|
||||
</div>
|
|
@ -59,8 +59,7 @@ module.exports = React.createClass({
|
|||
mainClassName += presenceClass;
|
||||
|
||||
return (
|
||||
<div className={mainClassName} onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }
|
||||
>
|
||||
<div className={mainClassName} onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
|
||||
<div className="mx_MemberTile_avatar">
|
||||
<img className="mx_MemberTile_avatarImg"
|
||||
src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null }
|
||||
|
|
|
@ -39,46 +39,55 @@ module.exports = React.createClass({
|
|||
|
||||
render: function() {
|
||||
|
||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
||||
var header;
|
||||
if (this.props.simpleHeader) {
|
||||
header =
|
||||
<div className="mx_RoomHeader_wrapper">
|
||||
<div className="mx_RoomHeader_simpleHeader">
|
||||
{ this.props.simpleHeader }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
||||
|
||||
var callButtons;
|
||||
if (this.state) {
|
||||
switch (this.state.call_state) {
|
||||
case "ringback":
|
||||
case "connected":
|
||||
callButtons = (
|
||||
<div className="mx_RoomHeader_button" onClick={this.onHangupClick}>
|
||||
BYEBYE
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
var callButtons;
|
||||
if (this.state) {
|
||||
switch (this.state.call_state) {
|
||||
case "ringback":
|
||||
case "connected":
|
||||
callButtons = (
|
||||
<div className="mx_RoomHeader_hangupButton" onClick={this.onHangupClick}>
|
||||
End call
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var name = null;
|
||||
var topic_el = null;
|
||||
var save_button = null;
|
||||
var settings_button = null;
|
||||
if (this.props.editing) {
|
||||
name = <input type="text" defaultValue={this.props.room.name} ref="name_edit"/>;
|
||||
// if (topic) topic_el = <div className="mx_RoomHeader_topic"><textarea>{ topic.getContent().topic }</textarea></div>
|
||||
save_button = (
|
||||
<div className="mx_RoomHeader_button"onClick={this.props.onSaveClick}>
|
||||
Save
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
name = <EditableText initialValue={this.props.room.name} onValueChanged={this.onNameChange} />;
|
||||
if (topic) topic_el = <div className="mx_RoomHeader_topic">{ topic.getContent().topic }</div>;
|
||||
settings_button = (
|
||||
<div className="mx_RoomHeader_button" onClick={this.props.onSettingsClick}>
|
||||
<img src="img/settings.png" width="32" height="32"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var name = null;
|
||||
var topic_el = null;
|
||||
var save_button = null;
|
||||
var settings_button = null;
|
||||
if (this.props.editing) {
|
||||
name = <input type="text" defaultValue={this.props.room.name} ref="name_edit"/>;
|
||||
// if (topic) topic_el = <div className="mx_RoomHeader_topic"><textarea>{ topic.getContent().topic }</textarea></div>
|
||||
save_button = (
|
||||
<div className="mx_RoomHeader_button"onClick={this.props.onSaveClick}>
|
||||
Save
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
name = <EditableText initialValue={this.props.room.name} onValueChanged={this.onNameChange} />;
|
||||
if (topic) topic_el = <div className="mx_RoomHeader_topic">{ topic.getContent().topic }</div>;
|
||||
settings_button = (
|
||||
<div className="mx_RoomHeader_button" onClick={this.props.onSettingsClick}>
|
||||
<img src="img/settings.png" width="32" height="32"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomHeader">
|
||||
header =
|
||||
<div className="mx_RoomHeader_wrapper">
|
||||
<div className="mx_RoomHeader_leftRow">
|
||||
<div className="mx_RoomHeader_avatar">
|
||||
|
@ -91,13 +100,13 @@ module.exports = React.createClass({
|
|||
{ topic_el }
|
||||
</div>
|
||||
</div>
|
||||
{callButtons}
|
||||
<div className="mx_RoomHeader_rightRow">
|
||||
{ save_button }
|
||||
{ settings_button }
|
||||
<div className="mx_RoomHeader_button">
|
||||
<img src="img/search.png" width="32" height="32"/>
|
||||
</div>
|
||||
{callButtons}
|
||||
<div className="mx_RoomHeader_button" onClick={this.onVideoClick}>
|
||||
<img src="img/video.png" width="32" height="32"/>
|
||||
</div>
|
||||
|
@ -106,6 +115,11 @@ module.exports = React.createClass({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomHeader">
|
||||
{ header }
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -20,7 +20,7 @@ var React = require('react');
|
|||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var RoomList = ComponentBroker.get('organisms/RoomList');
|
||||
var DirectoryMenu = ComponentBroker.get('molecules/DirectoryMenu');
|
||||
var BottomLeftMenu = ComponentBroker.get('molecules/BottomLeftMenu');
|
||||
var IncomingCallBox = ComponentBroker.get('molecules/voip/IncomingCallBox');
|
||||
var RoomCreate = ComponentBroker.get('molecules/RoomCreate');
|
||||
|
||||
|
@ -33,7 +33,7 @@ module.exports = React.createClass({
|
|||
<img className="mx_LeftPanel_hideButton" src="img/hide.png" width="32" height="32" alt="<"/>
|
||||
<IncomingCallBox />
|
||||
<RoomList selectedRoom={this.props.selectedRoom} />
|
||||
<DirectoryMenu />
|
||||
<BottomLeftMenu />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var classNames = require('classnames');
|
||||
|
||||
var MemberListController = require("../../../../src/controllers/organisms/MemberList");
|
||||
|
||||
|
@ -30,6 +31,10 @@ module.exports = React.createClass({
|
|||
displayName: 'MemberList',
|
||||
mixins: [MemberListController],
|
||||
|
||||
getInitialState: function() {
|
||||
return { editing: false };
|
||||
},
|
||||
|
||||
// FIXME: combine this more nicely with the MemberInfo positioning stuff...
|
||||
onMemberListScroll: function(ev) {
|
||||
if (this.refs.memberListScroll) {
|
||||
|
@ -55,23 +60,40 @@ module.exports = React.createClass({
|
|||
onPopulateInvite: function(inputText, shouldSubmit) {
|
||||
// reset back to placeholder
|
||||
this.refs.invite.setValue("Invite", false, true);
|
||||
this.setState({ editing: false });
|
||||
if (!shouldSubmit) {
|
||||
return; // enter key wasn't pressed
|
||||
}
|
||||
this.onInvite(inputText);
|
||||
},
|
||||
|
||||
onClickInvite: function(ev) {
|
||||
this.setState({ editing: true });
|
||||
this.refs.invite.onClickDiv();
|
||||
console.log("forcing update on memberlist after having clicked invite");
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
},
|
||||
|
||||
inviteTile: function() {
|
||||
if (this.state.inviting) {
|
||||
return (
|
||||
<div></div>
|
||||
);
|
||||
}
|
||||
// if (this.state.inviting) {
|
||||
// return (
|
||||
// <div></div>
|
||||
// );
|
||||
// }
|
||||
|
||||
var classes = classNames({
|
||||
mx_MemberTile: true,
|
||||
mx_MemberTile_inviteEditing: this.state.editing,
|
||||
});
|
||||
|
||||
console.log("rendering inviteTile, with phase as " + (this.refs.invite ? this.refs.invite.state.phase : "unknown"));
|
||||
|
||||
return (
|
||||
<div className="mx_MemberTile">
|
||||
<div className={ classes } onClick={ this.onClickInvite } >
|
||||
<div className="mx_MemberTile_avatar"><img src="img/create-big.png" width="40" height="40" alt=""/></div>
|
||||
<div className="mx_MemberTile_name">
|
||||
<EditableText ref="invite" placeHolder="Invite" onValueChanged={this.onPopulateInvite}/>
|
||||
<EditableText ref="invite" label="Invite" placeHolder="@user:domain.com" initialValue="" onValueChanged={this.onPopulateInvite}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -24,20 +24,53 @@ var MemberList = ComponentBroker.get('organisms/MemberList');
|
|||
module.exports = React.createClass({
|
||||
displayName: 'RightPanel',
|
||||
|
||||
Phase : {
|
||||
Blank: 'Blank',
|
||||
None: 'None',
|
||||
MemberList: 'MemberList',
|
||||
FileList: 'FileList',
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
phase : this.Phase.None
|
||||
}
|
||||
},
|
||||
|
||||
onMemberListButtonClick: function() {
|
||||
if (this.state.phase == this.Phase.None) {
|
||||
this.setState({ phase: this.Phase.MemberList });
|
||||
}
|
||||
else {
|
||||
this.setState({ phase: this.Phase.None });
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RightPanel">
|
||||
<div className="mx_RightPanel_header">
|
||||
var buttonGroup;
|
||||
var panel;
|
||||
if (this.props.roomId) {
|
||||
buttonGroup =
|
||||
<div className="mx_RightPanel_headerButtonGroup">
|
||||
<div className="mx_RightPanel_headerButton">
|
||||
<img src="img/file.png" width="32" height="32" alt="Files"/>
|
||||
</div>
|
||||
<div className="mx_RightPanel_headerButton">
|
||||
<div className="mx_RightPanel_headerButton" onClick={ this.onMemberListButtonClick }>
|
||||
<img src="img/members.png" width="32" height="32" alt="Members"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
if (this.state.phase == this.Phase.MemberList) {
|
||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RightPanel">
|
||||
<div className="mx_RightPanel_header">
|
||||
{ buttonGroup }
|
||||
</div>
|
||||
<MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||
{ panel }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
130
skins/base/views/organisms/RoomDirectory.js
Normal file
130
skins/base/views/organisms/RoomDirectory.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
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';
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var Modal = require("../../../../src/Modal");
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
|
||||
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomDirectory',
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
publicRooms: [],
|
||||
roomAlias: '',
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
var self = this;
|
||||
MatrixClientPeg.get().publicRooms(function (err, data) {
|
||||
if (err) {
|
||||
console.error("Failed to get publicRooms: %s", JSON.stringify(err));
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to get public room list",
|
||||
description: err.message
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.setState({
|
||||
publicRooms: data.chunk
|
||||
});
|
||||
self.forceUpdate();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
joinRoom: function(roomId) {
|
||||
// XXX: check that JS SDK suppresses duplicate attempts to join the same room
|
||||
MatrixClientPeg.get().joinRoom(roomId).done(function() {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: roomId
|
||||
});
|
||||
}, function(err) {
|
||||
console.error("Failed to join room: %s", JSON.stringify(err));
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to join room",
|
||||
description: err.message
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getRows: function(filter) {
|
||||
if (!this.state.publicRooms) return [];
|
||||
|
||||
var rooms = this.state.publicRooms.filter(function(a) {
|
||||
// FIXME: if incrementally typing, keep narrowing down the search set
|
||||
return (a.aliases[0].search(filter) >= 0);
|
||||
}).sort(function(a,b) {
|
||||
return a.num_joined_members > b.num_joined_members;
|
||||
});
|
||||
var rows = [];
|
||||
var self = this;
|
||||
for (var i = 0; i < rooms.length; i++) {
|
||||
var name = rooms[i].name;
|
||||
if (!name) {
|
||||
if (rooms[i].aliases[0]) name = rooms[i].aliases[0]
|
||||
}
|
||||
else {
|
||||
if (rooms[i].aliases[0]) name += " (" + rooms[i].aliases[0] + ")";
|
||||
}
|
||||
rows.unshift(
|
||||
<tr key={ rooms[i].room_id } onClick={ function() { self.joinRoom(rooms[i].room_id); } }>
|
||||
<td><img src={ MatrixClientPeg.get().getAvatarUrlForRoom(rooms[i].room_id, 40, 40, "crop") } width="40" height="40" alt=""/> { name }</td>
|
||||
<td>{ rooms[i].topic }</td>
|
||||
<td style={ {'text-align' : 'center'} }>{ rooms[i].num_joined_members }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
|
||||
onKeyUp: function(ev) {
|
||||
this.forceUpdate();
|
||||
this.setState({ roomAlias : this.refs.roomAlias.getDOMNode().value })
|
||||
if (ev.key == "Enter") {
|
||||
this.joinRoom(this.refs.roomAlias.getDOMNode().value);
|
||||
}
|
||||
if (ev.key == "Down") {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<RoomHeader simpleHeader="Public Rooms" />
|
||||
<div className="mx_RoomDirectory_list">
|
||||
<input ref="roomAlias" placeholder="Join a room (e.g. #foo:domain.com)" className="mx_RoomDirectory_input" size="64" onKeyUp={ this.onKeyUp }/>
|
||||
<table className="mx_RoomDirectory_table">
|
||||
<tr><th>Room</th><th>Topic</th><th>Users</th></tr>
|
||||
{ this.getRows(this.state.roomAlias) }
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -166,6 +166,7 @@ module.exports = React.createClass({
|
|||
if (typingString) {
|
||||
statusBar = (
|
||||
<div className="mx_RoomView_typingBar">
|
||||
<img src="img/typing.png" width="40" height="40" alt=""/>
|
||||
{typingString}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -73,7 +73,7 @@ module.exports = React.createClass({
|
|||
</div>
|
||||
|
||||
<div className="mx_UserSettings_DisplayName">
|
||||
<EditableText ref="displayname" initialValue={this.state.displayName} placeHolder="Click to set display name." onValueChanged={this.changeDisplayname}/>
|
||||
<EditableText ref="displayname" initialValue={this.state.displayName} label="Click to set display name." onValueChanged={this.changeDisplayname}/>
|
||||
<div className="mx_UserSettings_DisplayName_Edit" onClick={this.editDisplayName}>Edit</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ var Login = ComponentBroker.get('templates/Login');
|
|||
var UserSettings = ComponentBroker.get('organisms/UserSettings');
|
||||
var Register = ComponentBroker.get('templates/Register');
|
||||
var CreateRoom = ComponentBroker.get('organisms/CreateRoom');
|
||||
var RoomDirectory = ComponentBroker.get('organisms/RoomDirectory');
|
||||
|
||||
var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat");
|
||||
|
||||
|
@ -59,9 +60,15 @@ module.exports = React.createClass({
|
|||
break;
|
||||
case this.PageTypes.UserSettings:
|
||||
page_element = <UserSettings />
|
||||
right_panel = <RightPanel/>
|
||||
break;
|
||||
case this.PageTypes.CreateRoom:
|
||||
page_element = <CreateRoom onRoomCreated={this.onRoomCreated}/>
|
||||
right_panel = <RightPanel/>
|
||||
break;
|
||||
case this.PageTypes.RoomDirectory:
|
||||
page_element = <RoomDirectory />
|
||||
right_panel = <RightPanel/>
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,9 +97,10 @@ require('../skins/base/views/molecules/RoomSettings');
|
|||
require('../skins/base/views/organisms/LeftPanel');
|
||||
require('../skins/base/views/organisms/RightPanel');
|
||||
require('../skins/base/views/organisms/LogoutPrompt');
|
||||
require('../skins/base/views/organisms/RoomDirectory');
|
||||
require('../skins/base/views/molecules/RoomCreate');
|
||||
require('../skins/base/views/molecules/RoomDropTarget');
|
||||
require('../skins/base/views/molecules/DirectoryMenu');
|
||||
require('../skins/base/views/molecules/BottomLeftMenu');
|
||||
require('../skins/base/views/molecules/DateSeparator');
|
||||
require('../skins/base/views/atoms/voip/VideoFeed');
|
||||
require('../skins/base/views/molecules/voip/VideoView');
|
||||
|
|
|
@ -22,6 +22,7 @@ module.exports = {
|
|||
propTypes: {
|
||||
onValueChanged: React.PropTypes.func,
|
||||
initialValue: React.PropTypes.string,
|
||||
label: React.PropTypes.string,
|
||||
placeHolder: React.PropTypes.string,
|
||||
},
|
||||
|
||||
|
@ -34,7 +35,8 @@ module.exports = {
|
|||
return {
|
||||
onValueChanged: function() {},
|
||||
initialValue: '',
|
||||
placeHolder: 'Click to set',
|
||||
label: 'Click to set',
|
||||
placeholder: '',
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -77,6 +79,7 @@ module.exports = {
|
|||
this.setState({
|
||||
phase: this.Phases.Display,
|
||||
});
|
||||
this.onValueChanged(false);
|
||||
},
|
||||
|
||||
onValueChanged: function(shouldSubmit) {
|
||||
|
|
|
@ -200,7 +200,7 @@ module.exports = {
|
|||
}, function(err) {
|
||||
console.error("Command failure: %s", err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Server Error",
|
||||
title: "Server error",
|
||||
description: err.message
|
||||
});
|
||||
});
|
||||
|
@ -208,7 +208,7 @@ module.exports = {
|
|||
else if (cmd.error) {
|
||||
console.error(cmd.error);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Command Error",
|
||||
title: "Command error",
|
||||
description: cmd.error
|
||||
});
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ module.exports = {
|
|||
}, function(err) {
|
||||
console.error("Failed to invite: %s", JSON.stringify(err));
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Invite Server Error",
|
||||
title: "Server error whilst inviting",
|
||||
description: err.message
|
||||
});
|
||||
self.setState({
|
||||
|
|
|
@ -33,6 +33,7 @@ module.exports = {
|
|||
RoomView: "room_view",
|
||||
UserSettings: "user_settings",
|
||||
CreateRoom: "create_room",
|
||||
RoomDirectory: "room_directory",
|
||||
},
|
||||
|
||||
AuxPanel: {
|
||||
|
@ -43,7 +44,7 @@ module.exports = {
|
|||
return {
|
||||
logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
|
||||
ready: false,
|
||||
page_type: this.PageTypes.RoomView,
|
||||
page_type: MatrixClientPeg.get().getRooms().length ? this.PageTypes.RoomView : this.PageTypes.RoomDirectory,
|
||||
aux_panel: null,
|
||||
};
|
||||
},
|
||||
|
@ -127,6 +128,7 @@ module.exports = {
|
|||
currentRoom: payload.room_id,
|
||||
page_type: this.PageTypes.RoomView,
|
||||
});
|
||||
this.notifyNewScreen('room/'+payload.room_id);
|
||||
break;
|
||||
case 'view_prev_room':
|
||||
roomIndexDelta = -1;
|
||||
|
@ -156,6 +158,11 @@ module.exports = {
|
|||
page_type: this.PageTypes.CreateRoom,
|
||||
});
|
||||
break;
|
||||
case 'view_room_directory':
|
||||
this.setState({
|
||||
page_type: this.PageTypes.RoomDirectory,
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -172,13 +179,18 @@ module.exports = {
|
|||
var cli = MatrixClientPeg.get();
|
||||
var self = this;
|
||||
cli.on('syncComplete', function() {
|
||||
var firstRoom = null;
|
||||
if (cli.getRooms() && cli.getRooms().length) {
|
||||
firstRoom = RoomListSorter.mostRecentActivityFirst(
|
||||
cli.getRooms()
|
||||
)[0].roomId;
|
||||
if (!self.state.currentRoom) {
|
||||
var firstRoom = null;
|
||||
if (cli.getRooms() && cli.getRooms().length) {
|
||||
firstRoom = RoomListSorter.mostRecentActivityFirst(
|
||||
cli.getRooms()
|
||||
)[0].roomId;
|
||||
}
|
||||
self.setState({ready: true, currentRoom: firstRoom});
|
||||
self.notifyNewScreen('room/'+firstRoom);
|
||||
} else {
|
||||
self.setState({ready: true});
|
||||
}
|
||||
self.setState({ready: true, currentRoom: firstRoom});
|
||||
dis.dispatch({action: 'focus_composer'});
|
||||
});
|
||||
cli.on('Call.incoming', function(call) {
|
||||
|
@ -222,6 +234,12 @@ module.exports = {
|
|||
action: 'start_login',
|
||||
params: params
|
||||
});
|
||||
} else if (screen.indexOf('room/') == 0) {
|
||||
var roomId = screen.split('/')[1];
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: roomId
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue