Rename base skin to vector
This commit is contained in:
parent
682392d02a
commit
148dbc23ed
146 changed files with 0 additions and 0 deletions
76
src/skins/vector/views/atoms/EditableText.js
Normal file
76
src/skins/vector/views/atoms/EditableText.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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 EditableTextController = require("../../../../src/controllers/atoms/EditableText");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EditableText',
|
||||
mixins: [EditableTextController],
|
||||
|
||||
onKeyUp: function(ev) {
|
||||
if (ev.key == "Enter") {
|
||||
this.onFinish(ev);
|
||||
} else if (ev.key == "Escape") {
|
||||
this.cancelEdit();
|
||||
}
|
||||
},
|
||||
|
||||
onClickDiv: function() {
|
||||
this.setState({
|
||||
phase: this.Phases.Edit,
|
||||
})
|
||||
},
|
||||
|
||||
onFocus: function(ev) {
|
||||
ev.target.setSelectionRange(0, ev.target.value.length);
|
||||
},
|
||||
|
||||
onFinish: function(ev) {
|
||||
if (ev.target.value) {
|
||||
this.setValue(ev.target.value, ev.key === "Enter");
|
||||
} else {
|
||||
this.cancelEdit();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var editable_el;
|
||||
|
||||
if (this.state.phase == this.Phases.Display) {
|
||||
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}>{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} placeholder={this.props.placeHolder} autoFocus/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_EditableText">
|
||||
{editable_el}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
38
src/skins/vector/views/atoms/EnableNotificationsButton.js
Normal file
38
src/skins/vector/views/atoms/EnableNotificationsButton.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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 EnableNotificationsButtonController = require("../../../../src/controllers/atoms/EnableNotificationsButton");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EnableNotificationsButton',
|
||||
mixins: [EnableNotificationsButtonController],
|
||||
|
||||
render: function() {
|
||||
if (this.enabled()) {
|
||||
return (
|
||||
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>Disable Notifications</button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>Enable Notifications</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
76
src/skins/vector/views/atoms/ImageView.js
Normal file
76
src/skins/vector/views/atoms/ImageView.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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 ImageViewController = require("../../../../src/controllers/atoms/ImageView");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ImageView',
|
||||
mixins: [ImageViewController],
|
||||
|
||||
// XXX: keyboard shortcuts for managing dialogs should be done by the modal dialog base class omehow, surely...
|
||||
componentDidMount: function() {
|
||||
document.addEventListener("keydown", this.onKeyDown);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
document.removeEventListener("keydown", this.onKeyDown);
|
||||
},
|
||||
|
||||
onKeyDown: function(ev) {
|
||||
if (ev.keyCode == 27) { // escape
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
// XXX: can't we just do max-width: 80%, max-height: 80% on the CSS?
|
||||
|
||||
var width = this.props.width || 500;
|
||||
var height = this.props.height || 500;
|
||||
|
||||
var maxWidth = document.documentElement.clientWidth * 0.8;
|
||||
var maxHeight = document.documentElement.clientHeight * 0.8;
|
||||
|
||||
var widthFrac = width / maxWidth;
|
||||
var heightFrac = height / maxHeight;
|
||||
|
||||
var displayWidth;
|
||||
var displayHeight;
|
||||
if (widthFrac > heightFrac) {
|
||||
displayWidth = Math.min(width, maxWidth);
|
||||
displayHeight = (displayWidth / width) * height;
|
||||
} else {
|
||||
displayHeight = Math.min(height, maxHeight);
|
||||
displayWidth = (displayHeight / height) * width;
|
||||
}
|
||||
|
||||
var style = {
|
||||
width: displayWidth,
|
||||
height: displayHeight
|
||||
};
|
||||
|
||||
return (
|
||||
<img className="mx_ImageView" src={this.props.src} style={style} />
|
||||
);
|
||||
}
|
||||
});
|
32
src/skins/vector/views/atoms/LogoutButton.js
Normal file
32
src/skins/vector/views/atoms/LogoutButton.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
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 LogoutButtonController = require("../../../../src/controllers/atoms/LogoutButton");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'LogoutButton',
|
||||
mixins: [LogoutButtonController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<button className="mx_LogoutButton" onClick={this.onClick}>Sign out</button>
|
||||
);
|
||||
}
|
||||
});
|
34
src/skins/vector/views/atoms/MemberAvatar.js
Normal file
34
src/skins/vector/views/atoms/MemberAvatar.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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 MemberAvatarController = require("../../../../src/controllers/atoms/MemberAvatar");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MemberAvatar',
|
||||
mixins: [MemberAvatarController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<img className="mx_MemberAvatar" src={this.state.imageUrl}
|
||||
onError={this.onError}
|
||||
width={this.props.width} height={this.props.height} />
|
||||
);
|
||||
}
|
||||
});
|
36
src/skins/vector/views/atoms/MessageTimestamp.js
Normal file
36
src/skins/vector/views/atoms/MessageTimestamp.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 MessageTimestampController = require("../../../../src/controllers/atoms/MessageTimestamp");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageTimestamp',
|
||||
mixins: [MessageTimestampController],
|
||||
|
||||
render: function() {
|
||||
var date = new Date(this.props.ts);
|
||||
return (
|
||||
<span className="mx_MessageTimestamp">
|
||||
{date.toLocaleTimeString()}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
34
src/skins/vector/views/atoms/RoomAvatar.js
Normal file
34
src/skins/vector/views/atoms/RoomAvatar.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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 RoomAvatarController = require("../../../../src/controllers/atoms/RoomAvatar");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomAvatar',
|
||||
mixins: [RoomAvatarController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<img className="mx_RoomAvatar" src={this.state.imageUrl} onError={this.onError}
|
||||
width={this.props.width} height={this.props.height}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
32
src/skins/vector/views/atoms/create_room/CreateRoomButton.js
Normal file
32
src/skins/vector/views/atoms/create_room/CreateRoomButton.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
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 CreateRoomButtonController = require("../../../../../src/controllers/atoms/create_room/CreateRoomButton");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'CreateRoomButton',
|
||||
mixins: [CreateRoomButtonController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<button className="mx_CreateRoomButton" onClick={this.onClick}>Create Room</button>
|
||||
);
|
||||
}
|
||||
});
|
40
src/skins/vector/views/atoms/create_room/Presets.js
Normal file
40
src/skins/vector/views/atoms/create_room/Presets.js
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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var PresetsController = require("../../../../../src/controllers/atoms/create_room/Presets");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'CreateRoomPresets',
|
||||
mixins: [PresetsController],
|
||||
|
||||
onValueChanged: function(ev) {
|
||||
this.props.onChange(ev.target.value)
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<select className="mx_Presets" onChange={this.onValueChanged} value={this.props.preset}>
|
||||
<option value={this.Presets.PrivateChat}>Private Chat</option>
|
||||
<option value={this.Presets.PublicChat}>Public Chat</option>
|
||||
<option value={this.Presets.Custom}>Custom</option>
|
||||
</select>
|
||||
);
|
||||
}
|
||||
});
|
79
src/skins/vector/views/atoms/create_room/RoomAlias.js
Normal file
79
src/skins/vector/views/atoms/create_room/RoomAlias.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
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 RoomAliasController = require("../../../../../src/controllers/atoms/create_room/RoomAlias");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomAlias',
|
||||
mixins: [RoomAliasController],
|
||||
|
||||
onValueChanged: function(ev) {
|
||||
this.props.onChange(ev.target.value);
|
||||
},
|
||||
|
||||
onFocus: function(ev) {
|
||||
var target = ev.target;
|
||||
var curr_val = ev.target.value;
|
||||
|
||||
if (this.props.homeserver) {
|
||||
if (curr_val == "") {
|
||||
setTimeout(function() {
|
||||
target.value = "#:" + this.props.homeserver;
|
||||
target.setSelectionRange(1, 1);
|
||||
}, 0);
|
||||
} else {
|
||||
var suffix = ":" + this.props.homeserver;
|
||||
setTimeout(function() {
|
||||
target.setSelectionRange(
|
||||
curr_val.startsWith("#") ? 1 : 0,
|
||||
curr_val.endsWith(suffix) ? (target.value.length - suffix.length) : target.value.length
|
||||
);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onBlur: function(ev) {
|
||||
var curr_val = ev.target.value;
|
||||
|
||||
if (this.props.homeserver) {
|
||||
if (curr_val == "#:" + this.props.homeserver) {
|
||||
ev.target.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (curr_val != "") {
|
||||
var new_val = ev.target.value;
|
||||
var suffix = ":" + this.props.homeserver;
|
||||
if (!curr_val.startsWith("#")) new_val = "#" + new_val;
|
||||
if (!curr_val.endsWith(suffix)) new_val = new_val + suffix;
|
||||
ev.target.value = new_val;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<input type="text" className="mx_RoomAlias" placeholder="Alias (optional)"
|
||||
onChange={this.onValueChanged} onFocus={this.onFocus} onBlur={this.onBlur}
|
||||
value={this.props.alias}/>
|
||||
);
|
||||
}
|
||||
});
|
34
src/skins/vector/views/atoms/voip/VideoFeed.js
Normal file
34
src/skins/vector/views/atoms/voip/VideoFeed.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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 VideoFeedController = require("../../../../../src/controllers/atoms/voip/VideoFeed");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'VideoFeed',
|
||||
mixins: [VideoFeedController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<video>
|
||||
</video>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
67
src/skins/vector/views/molecules/BottomLeftMenu.js
Normal file
67
src/skins/vector/views/molecules/BottomLeftMenu.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'BottomLeftMenu',
|
||||
|
||||
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_BottomLeftMenu">
|
||||
<div className="mx_BottomLeftMenu_options">
|
||||
<div className="mx_RoomTile" onClick={this.onCreateRoomClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/create-big.png" alt="Create new room" title="Create new room" width="42" height="42"/>
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">Create new room</div>
|
||||
</div>
|
||||
<div className="mx_RoomTile" onClick={this.onRoomDirectoryClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/directory-big.png" alt="Directory" title="Directory" width="42" height="42"/>
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">Directory</div>
|
||||
</div>
|
||||
<div className="mx_RoomTile" onClick={this.onSettingsClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/settings-big.png" alt="Settings" title="Settings" width="42" height="42"/>
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">Settings</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
65
src/skins/vector/views/molecules/ChangeAvatar.js
Normal file
65
src/skins/vector/views/molecules/ChangeAvatar.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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 ChangeAvatarController = require("../../../../src/controllers/molecules/ChangeAvatar");
|
||||
|
||||
var Loader = require("react-loader");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ChangeAvatar',
|
||||
mixins: [ChangeAvatarController],
|
||||
|
||||
onFileSelected: function(ev) {
|
||||
this.setAvatarFromFile(ev.target.files[0]);
|
||||
},
|
||||
|
||||
onError: function(error) {
|
||||
this.setState({
|
||||
errorText: "Failed to upload profile picture!"
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
switch (this.state.phase) {
|
||||
case this.Phases.Display:
|
||||
case this.Phases.Error:
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_Dialog_content">
|
||||
<img src={this.state.avatarUrl}/>
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
Upload new:
|
||||
<input type="file" onChange={this.onFileSelected}/>
|
||||
{this.state.errorText}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.props.onFinished}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case this.Phases.Uploading:
|
||||
return (
|
||||
<Loader />
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
85
src/skins/vector/views/molecules/ChangePassword.js
Normal file
85
src/skins/vector/views/molecules/ChangePassword.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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 ChangePasswordController = require("../../../../src/controllers/molecules/ChangePassword");
|
||||
var Loader = require("react-loader");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ChangePassword',
|
||||
mixins: [ChangePasswordController],
|
||||
|
||||
onClickChange: function() {
|
||||
var old_password = this.refs.old_input.getDOMNode().value;
|
||||
var new_password = this.refs.new_input.getDOMNode().value;
|
||||
var confirm_password = this.refs.confirm_input.getDOMNode().value;
|
||||
if (new_password != confirm_password) {
|
||||
this.setState({
|
||||
state: this.Phases.Error,
|
||||
errorString: "Passwords don't match"
|
||||
});
|
||||
} else if (new_password == '' || old_password == '') {
|
||||
this.setState({
|
||||
state: this.Phases.Error,
|
||||
errorString: "Passwords can't be empty"
|
||||
});
|
||||
} else {
|
||||
this.changePassword(old_password, new_password);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
switch (this.state.phase) {
|
||||
case this.Phases.Edit:
|
||||
case this.Phases.Error:
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_Dialog_content">
|
||||
<div>{this.state.errorString}</div>
|
||||
<div><label>Old password <input type="password" ref="old_input"/></label></div>
|
||||
<div><label>New password <input type="password" ref="new_input"/></label></div>
|
||||
<div><label>Confirm password <input type="password" ref="confirm_input"/></label></div>
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.onClickChange}>Change Password</button>
|
||||
<button onClick={this.props.onFinished}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case this.Phases.Uploading:
|
||||
return (
|
||||
<div className="mx_Dialog_content">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
case this.Phases.Success:
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_Dialog_content">
|
||||
Success!
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.props.onFinished}>Ok</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
35
src/skins/vector/views/molecules/ContextualMenu.js
Normal file
35
src/skins/vector/views/molecules/ContextualMenu.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ContextualMenu',
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_ContextualMenu">
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
56
src/skins/vector/views/molecules/DateSeparator.js
Normal file
56
src/skins/vector/views/molecules/DateSeparator.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
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 days = [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
];
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'DateSeparator',
|
||||
render: function() {
|
||||
var date = new Date(this.props.ts);
|
||||
var today = new Date();
|
||||
var yesterday = new Date();
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
var label;
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
label = "Today";
|
||||
}
|
||||
else if (date.toDateString() === yesterday.toDateString()) {
|
||||
label = "Yesterday";
|
||||
}
|
||||
else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
|
||||
label = days[date.getDay()];
|
||||
}
|
||||
else {
|
||||
label = date.toDateString();
|
||||
}
|
||||
|
||||
return (
|
||||
<h2>{ label }</h2>
|
||||
);
|
||||
}
|
||||
});
|
52
src/skins/vector/views/molecules/EventAsTextTile.js
Normal file
52
src/skins/vector/views/molecules/EventAsTextTile.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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 EventAsTextTileController = require("../../../../src/controllers/molecules/EventAsTextTile");
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
var TextForEvent = require("../../../../src/TextForEvent");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EventAsTextTile',
|
||||
mixins: [EventAsTextTileController],
|
||||
|
||||
render: function() {
|
||||
var text = TextForEvent.textForEvent(this.props.mxEvent);
|
||||
if (text == null || text.length == 0) return null;
|
||||
|
||||
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
|
||||
var avatar = this.props.mxEvent.sender ? <MemberAvatar member={this.props.mxEvent.sender} /> : null;
|
||||
return (
|
||||
<div className="mx_MessageTile mx_MessageTile_notice">
|
||||
<div className="mx_MessageTile_avatar">
|
||||
{ avatar }
|
||||
</div>
|
||||
{ timestamp }
|
||||
<span className="mx_SenderProfile"></span>
|
||||
<span className="mx_MessageTile_content">
|
||||
{TextForEvent.textForEvent(this.props.mxEvent)}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
38
src/skins/vector/views/molecules/MEmoteTile.js
Normal file
38
src/skins/vector/views/molecules/MEmoteTile.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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 MEmoteTileController = require("../../../../src/controllers/molecules/MEmoteTile");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MEmoteTile',
|
||||
mixins: [MEmoteTileController],
|
||||
|
||||
render: function() {
|
||||
var mxEvent = this.props.mxEvent;
|
||||
var content = mxEvent.getContent();
|
||||
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
return (
|
||||
<span ref="content" className="mx_MEmoteTile mx_MessageTile_content">
|
||||
* {name} {content.body}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
44
src/skins/vector/views/molecules/MFileTile.js
Normal file
44
src/skins/vector/views/molecules/MFileTile.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
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 MFileTileController = require("../../../../src/controllers/molecules/MFileTile");
|
||||
|
||||
var MatrixClientPeg = require('../../../../src/MatrixClientPeg');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MFileTile',
|
||||
mixins: [MFileTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
return (
|
||||
<span className="mx_MFileTile">
|
||||
<div className="mx_MImageTile_download">
|
||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
||||
<img src="img/download.png" width="10" height="12"/>
|
||||
Download {this.presentableTextForFile(content)}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
94
src/skins/vector/views/molecules/MImageTile.js
Normal file
94
src/skins/vector/views/molecules/MImageTile.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
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 filesize = require('filesize');
|
||||
|
||||
var MImageTileController = require("../../../../src/controllers/molecules/MImageTile");
|
||||
|
||||
var MatrixClientPeg = require('../../../../src/MatrixClientPeg');
|
||||
var Modal = require('../../../../src/Modal');
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var ImageView = ComponentBroker.get("atoms/ImageView");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MImageTile',
|
||||
mixins: [MImageTileController],
|
||||
|
||||
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
||||
if (!fullWidth || !fullHeight) {
|
||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
||||
// log this because it's spammy
|
||||
return undefined;
|
||||
}
|
||||
if (fullWidth < thumbWidth && fullHeight < thumbHeight) {
|
||||
// no scaling needs to be applied
|
||||
return fullHeight;
|
||||
}
|
||||
var widthMulti = thumbWidth / fullWidth;
|
||||
var heightMulti = thumbHeight / fullHeight;
|
||||
if (widthMulti < heightMulti) {
|
||||
// width is the dominant dimension so scaling will be fixed on that
|
||||
return Math.floor(widthMulti * fullHeight);
|
||||
}
|
||||
else {
|
||||
// height is the dominant dimension so scaling will be fixed on that
|
||||
return Math.floor(heightMulti * fullHeight);
|
||||
}
|
||||
},
|
||||
|
||||
onClick: function(ev) {
|
||||
var ms = ev.getModifierState();
|
||||
if (ev.button == 0 && !ev.metaKey) {
|
||||
ev.preventDefault();
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(content.url);
|
||||
Modal.createDialog(ImageView, {
|
||||
src: httpUrl,
|
||||
width: content.info.w,
|
||||
height: content.info.h
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
var thumbHeight = null;
|
||||
if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 320, 240);
|
||||
|
||||
var imgStyle = {};
|
||||
if (thumbHeight) imgStyle['height'] = thumbHeight;
|
||||
|
||||
return (
|
||||
<span className="mx_MImageTile">
|
||||
<a href={cli.mxcUrlToHttp(content.url)} onClick={ this.onClick }>
|
||||
<img className="mx_MImageTile_thumbnail" src={cli.mxcUrlToHttp(content.url, 320, 240)} alt={content.body} style={imgStyle} />
|
||||
</a>
|
||||
<div className="mx_MImageTile_download">
|
||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
||||
<img src="img/download.png" width="10" height="12"/>
|
||||
Download {content.body} ({ filesize(content.info.size) })
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
36
src/skins/vector/views/molecules/MNoticeTile.js
Normal file
36
src/skins/vector/views/molecules/MNoticeTile.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 MNoticeTileController = require("../../../../src/controllers/molecules/MNoticeTile");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MNoticeTile',
|
||||
mixins: [MNoticeTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
return (
|
||||
<span ref="content" className="mx_MNoticeTile mx_MessageTile_content">
|
||||
{content.body}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
56
src/skins/vector/views/molecules/MRoomMemberTile.js
Normal file
56
src/skins/vector/views/molecules/MRoomMemberTile.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
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 MRoomMemberTileController = require("../../../../src/controllers/molecules/MRoomMemberTile");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var TextForEvent = require('../../../../src/TextForEvent');
|
||||
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MRoomMemberTile',
|
||||
mixins: [MRoomMemberTileController],
|
||||
|
||||
getMemberEventText: function() {
|
||||
return TextForEvent.textForEvent(this.props.mxEvent);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// XXX: for now, just cheekily borrow the css from message tile...
|
||||
var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
|
||||
var text = this.getMemberEventText();
|
||||
if (!text) return <div/>;
|
||||
return (
|
||||
<div className="mx_MessageTile mx_MessageTile_notice">
|
||||
<div className="mx_MessageTile_avatar">
|
||||
<MemberAvatar member={this.props.mxEvent.sender} />
|
||||
</div>
|
||||
{ timestamp }
|
||||
<span className="mx_SenderProfile"></span>
|
||||
<span className="mx_MessageTile_content">
|
||||
{ text }
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
36
src/skins/vector/views/molecules/MTextTile.js
Normal file
36
src/skins/vector/views/molecules/MTextTile.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 MTextTileController = require("../../../../src/controllers/molecules/MTextTile");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MTextTile',
|
||||
mixins: [MTextTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
return (
|
||||
<span ref="content" className="mx_MTextTile mx_MessageTile_content">
|
||||
{content.body}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
46
src/skins/vector/views/molecules/MatrixToolbar.js
Normal file
46
src/skins/vector/views/molecules/MatrixToolbar.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var LogoutButton = ComponentBroker.get("atoms/LogoutButton");
|
||||
var EnableNotificationsButton = ComponentBroker.get("atoms/EnableNotificationsButton");
|
||||
|
||||
var MatrixToolbarController = require("../../../../src/controllers/molecules/MatrixToolbar");
|
||||
var Notifier = ComponentBroker.get('organisms/Notifier');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MatrixToolbar',
|
||||
mixins: [MatrixToolbarController],
|
||||
|
||||
hideToolbar: function() {
|
||||
Notifier.setToolbarHidden(true);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_MatrixToolbar">
|
||||
You are not receiving desktop notifications. <EnableNotificationsButton />
|
||||
<div className="mx_MatrixToolbar_close"><img src="img/close-white.png" width="16" height="16" onClick={ this.hideToolbar } /></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
72
src/skins/vector/views/molecules/MemberInfo.js
Normal file
72
src/skins/vector/views/molecules/MemberInfo.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
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 MemberInfoController = require("../../../../src/controllers/molecules/MemberInfo");
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MemberInfo',
|
||||
mixins: [MemberInfoController],
|
||||
|
||||
render: function() {
|
||||
var interactButton, kickButton, banButton, muteButton, giveModButton;
|
||||
if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
|
||||
interactButton = <div className="mx_ContextualMenu_field" onClick={this.onLeaveClick}>Leave room</div>;
|
||||
}
|
||||
else {
|
||||
interactButton = <div className="mx_ContextualMenu_field" onClick={this.onChatClick}>Start chat</div>;
|
||||
}
|
||||
|
||||
if (this.state.can.kick) {
|
||||
kickButton = <div className="mx_ContextualMenu_field" onClick={this.onKick}>
|
||||
Kick
|
||||
</div>;
|
||||
}
|
||||
if (this.state.can.ban) {
|
||||
banButton = <div className="mx_ContextualMenu_field" onClick={this.onBan}>
|
||||
Ban
|
||||
</div>;
|
||||
}
|
||||
if (this.state.can.mute) {
|
||||
var muteLabel = this.state.muted ? "Unmute" : "Mute";
|
||||
muteButton = <div className="mx_ContextualMenu_field" onClick={this.onMuteToggle}>
|
||||
{muteLabel}
|
||||
</div>;
|
||||
}
|
||||
if (this.state.can.modifyLevel) {
|
||||
var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
|
||||
giveModButton = <div className="mx_ContextualMenu_field" onClick={this.onModToggle}>
|
||||
{giveOpLabel}
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{interactButton}
|
||||
{muteButton}
|
||||
{kickButton}
|
||||
{banButton}
|
||||
{giveModButton}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
166
src/skins/vector/views/molecules/MemberTile.js
Normal file
166
src/skins/vector/views/molecules/MemberTile.js
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var Modal = require("../../../../src/Modal");
|
||||
var ContextualMenu = require("../../../../src/ContextualMenu");
|
||||
var MemberTileController = require("../../../../src/controllers/molecules/MemberTile");
|
||||
var MemberInfo = ComponentBroker.get('molecules/MemberInfo');
|
||||
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
|
||||
// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
|
||||
// Revert to Arial when this happens, which on OSX works at least.
|
||||
var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MemberTile',
|
||||
mixins: [MemberTileController],
|
||||
|
||||
mouseEnter: function(e) {
|
||||
this.setState({ 'hover': true });
|
||||
},
|
||||
|
||||
mouseLeave: function(e) {
|
||||
this.setState({ 'hover': false });
|
||||
},
|
||||
|
||||
onClick: function(e) {
|
||||
var self = this;
|
||||
self.setState({ 'menu': true });
|
||||
ContextualMenu.createMenu(MemberInfo, {
|
||||
member: self.props.member,
|
||||
right: window.innerWidth - e.pageX,
|
||||
top: e.pageY,
|
||||
onFinished: function() {
|
||||
self.setState({ 'menu': false });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getDuration: function(time) {
|
||||
if (!time) return;
|
||||
var t = parseInt(time / 1000);
|
||||
var s = t % 60;
|
||||
var m = parseInt(t / 60) % 60;
|
||||
var h = parseInt(t / (60 * 60)) % 24;
|
||||
var d = parseInt(t / (60 * 60 * 24));
|
||||
if (t < 60) {
|
||||
if (t < 0) {
|
||||
return "0s";
|
||||
}
|
||||
return s + "s";
|
||||
}
|
||||
if (t < 60 * 60) {
|
||||
return m + "m";
|
||||
}
|
||||
if (t < 24 * 60 * 60) {
|
||||
return h + "h";
|
||||
}
|
||||
return d + "d ";
|
||||
},
|
||||
|
||||
getPrettyPresence: function(user) {
|
||||
if (!user) return "Unknown";
|
||||
var presence = user.presence;
|
||||
if (presence === "online") return "Online";
|
||||
if (presence === "unavailable") return "Idle"; // XXX: is this actually right?
|
||||
if (presence === "offline") return "Offline";
|
||||
return "Unknown";
|
||||
},
|
||||
|
||||
getPowerLabel: function() {
|
||||
var label = this.props.member.userId;
|
||||
if (this.state.isTargetMod) {
|
||||
label += " - Mod (" + this.props.member.powerLevelNorm + "%)";
|
||||
}
|
||||
return label;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var isMyUser = MatrixClientPeg.get().credentials.userId == this.props.member.userId;
|
||||
|
||||
var power;
|
||||
if (this.props.member && this.props.member.powerLevelNorm > 0) {
|
||||
var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
|
||||
power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>;
|
||||
}
|
||||
var presenceClass = "mx_MemberTile_offline";
|
||||
var mainClassName = "mx_MemberTile ";
|
||||
if (this.props.member.user) {
|
||||
if (this.props.member.user.presence === "online") {
|
||||
presenceClass = "mx_MemberTile_online";
|
||||
}
|
||||
else if (this.props.member.user.presence === "unavailable") {
|
||||
presenceClass = "mx_MemberTile_unavailable";
|
||||
}
|
||||
}
|
||||
mainClassName += presenceClass;
|
||||
if (this.state.hover || this.state.menu) {
|
||||
mainClassName += " mx_MemberTile_hover";
|
||||
}
|
||||
|
||||
var name = this.props.member.name;
|
||||
// if (isMyUser) name += " (me)"; // this does nothing other than introduce line wrapping and pain
|
||||
var leave = isMyUser ? <img className="mx_MemberTile_leave" src="img/delete.png" width="10" height="10" onClick={this.onLeaveClick}/> : null;
|
||||
|
||||
var nameClass = "mx_MemberTile_name";
|
||||
if (zalgo.test(name)) {
|
||||
nameClass += " mx_MemberTile_zalgo";
|
||||
}
|
||||
|
||||
var nameEl;
|
||||
if (this.state.hover || this.state.menu) {
|
||||
var presence;
|
||||
// FIXME: make presence data update whenever User.presence changes...
|
||||
var active = this.props.member.user ? (this.props.member.user.lastActiveAgo || -1) : -1;
|
||||
if (active >= 0) {
|
||||
presence = <div className="mx_MemberTile_presence">{ this.getPrettyPresence(this.props.member.user) } for { this.getDuration(active) }</div>;
|
||||
}
|
||||
else {
|
||||
presence = <div className="mx_MemberTile_presence">{ this.getPrettyPresence(this.props.member.user) }</div>;
|
||||
}
|
||||
|
||||
nameEl =
|
||||
<div className="mx_MemberTile_details">
|
||||
{ leave }
|
||||
<div className="mx_MemberTile_userId">{ this.props.member.userId }</div>
|
||||
{ presence }
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
nameEl =
|
||||
<div className={nameClass}>
|
||||
{ name }
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={mainClassName} title={ this.getPowerLabel() } onClick={ this.onClick } onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
|
||||
<div className="mx_MemberTile_avatar">
|
||||
<MemberAvatar member={this.props.member} />
|
||||
{ power }
|
||||
</div>
|
||||
{ nameEl }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
68
src/skins/vector/views/molecules/MessageComposer.js
Normal file
68
src/skins/vector/views/molecules/MessageComposer.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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 MessageComposerController = require("../../../../src/controllers/molecules/MessageComposer");
|
||||
var ContentMessages = require("../../../../src/ContentMessages");
|
||||
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageComposer',
|
||||
mixins: [MessageComposerController],
|
||||
|
||||
onUploadClick: function(ev) {
|
||||
this.refs.uploadInput.getDOMNode().click();
|
||||
},
|
||||
|
||||
onUploadFileSelected: function(ev) {
|
||||
var files = ev.target.files;
|
||||
// MessageComposer shouldn't have to rely on it's parent passing in a callback to upload a file
|
||||
if (files && files.length > 0) {
|
||||
this.props.uploadFile(files[0]);
|
||||
}
|
||||
this.refs.uploadInput.getDOMNode().value = null;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
|
||||
var uploadInputStyle = {display: 'none'};
|
||||
return (
|
||||
<div className="mx_MessageComposer">
|
||||
<div className="mx_MessageComposer_wrapper">
|
||||
<div className="mx_MessageComposer_row">
|
||||
<div className="mx_MessageComposer_avatar">
|
||||
<MemberAvatar member={me} />
|
||||
</div>
|
||||
<div className="mx_MessageComposer_input">
|
||||
<textarea ref="textarea" onKeyDown={this.onKeyDown} placeholder="Type a message" />
|
||||
</div>
|
||||
<div className="mx_MessageComposer_upload" onClick={this.onUploadClick}>
|
||||
<img src="img/upload.png" width="32" height="32"/>
|
||||
<input type="file" style={uploadInputStyle} ref="uploadInput" onChange={this.onUploadFileSelected} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
96
src/skins/vector/views/molecules/MessageTile.js
Normal file
96
src/skins/vector/views/molecules/MessageTile.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
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 classNames = require("classnames");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
|
||||
var SenderProfile = ComponentBroker.get('molecules/SenderProfile');
|
||||
var MemberAvatar = ComponentBroker.get('atoms/MemberAvatar');
|
||||
|
||||
var UnknownMessageTile = ComponentBroker.get('molecules/UnknownMessageTile');
|
||||
|
||||
var tileTypes = {
|
||||
'm.text': ComponentBroker.get('molecules/MTextTile'),
|
||||
'm.notice': ComponentBroker.get('molecules/MNoticeTile'),
|
||||
'm.emote': ComponentBroker.get('molecules/MEmoteTile'),
|
||||
'm.image': ComponentBroker.get('molecules/MImageTile'),
|
||||
'm.file': ComponentBroker.get('molecules/MFileTile')
|
||||
};
|
||||
|
||||
var MessageTileController = require("../../../../src/controllers/molecules/MessageTile");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageTile',
|
||||
mixins: [MessageTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var msgtype = content.msgtype;
|
||||
var TileType = UnknownMessageTile;
|
||||
if (msgtype && tileTypes[msgtype]) {
|
||||
TileType = tileTypes[msgtype];
|
||||
}
|
||||
var classes = classNames({
|
||||
mx_MessageTile: true,
|
||||
mx_MessageTile_sending: ['sending', 'queued'].indexOf(
|
||||
this.props.mxEvent.status
|
||||
) !== -1,
|
||||
mx_MessageTile_notSent: this.props.mxEvent.status == 'not_sent',
|
||||
mx_MessageTile_highlight: this.shouldHighlight(),
|
||||
mx_MessageTile_continuation: this.props.continuation,
|
||||
mx_MessageTile_last: this.props.last,
|
||||
});
|
||||
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
|
||||
|
||||
var aux = null;
|
||||
if (msgtype === 'm.image') aux = "sent an image";
|
||||
else if (msgtype === 'm.video') aux = "sent a video";
|
||||
else if (msgtype === 'm.file') aux = "uploaded a file";
|
||||
|
||||
var avatar, sender, resend;
|
||||
if (!this.props.continuation) {
|
||||
if (this.props.mxEvent.sender) {
|
||||
avatar = (
|
||||
<div className="mx_MessageTile_avatar">
|
||||
<MemberAvatar member={this.props.mxEvent.sender} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />;
|
||||
}
|
||||
if (this.props.mxEvent.status === "not_sent" && !this.state.resending) {
|
||||
resend = <button className="mx_MessageTile_msgOption" onClick={this.onResend}>
|
||||
Resend
|
||||
</button>;
|
||||
}
|
||||
return (
|
||||
<div className={classes}>
|
||||
{ avatar }
|
||||
{ timestamp }
|
||||
{ resend }
|
||||
{ sender }
|
||||
<TileType mxEvent={this.props.mxEvent} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
37
src/skins/vector/views/molecules/ProgressBar.js
Normal file
37
src/skins/vector/views/molecules/ProgressBar.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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 ProgressBarController = require("../../../../src/controllers/molecules/ProgressBar");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ProgressBar',
|
||||
mixins: [ProgressBarController],
|
||||
|
||||
render: function() {
|
||||
// Would use an HTML5 progress tag but if that doesn't animate if you
|
||||
// use the HTML attributes rather than styles
|
||||
var progressStyle = {
|
||||
width: ((this.props.value / this.props.max) * 100)+"%"
|
||||
};
|
||||
return (
|
||||
<div className="mx_ProgressBar"><div className="mx_ProgressBar_fill" style={progressStyle}></div></div>
|
||||
);
|
||||
}
|
||||
});
|
43
src/skins/vector/views/molecules/RoomCreate.js
Normal file
43
src/skins/vector/views/molecules/RoomCreate.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
//var RoomCreateController = require("../../../../src/controllers/molecules/RoomCreateController");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomCreate',
|
||||
// mixins: [RoomCreateController],
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RoomCreate">
|
||||
<div className="mx_RoomCreate_table">
|
||||
<div className="mx_RoomTile">
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<img src="img/create.png" width="32" height="32"/>
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">Create new room</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
36
src/skins/vector/views/molecules/RoomDropTarget.js
Normal file
36
src/skins/vector/views/molecules/RoomDropTarget.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
//var RoomDropTargetController = require("../../../../src/controllers/molecules/RoomDropTargetController");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomDropTarget',
|
||||
// mixins: [RoomDropTargetController],
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RoomDropTarget">
|
||||
{this.props.text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
139
src/skins/vector/views/molecules/RoomHeader.js
Normal file
139
src/skins/vector/views/molecules/RoomHeader.js
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var RoomHeaderController = require("../../../../src/controllers/molecules/RoomHeader");
|
||||
var EditableText = ComponentBroker.get("atoms/EditableText");
|
||||
var RoomAvatar = ComponentBroker.get('atoms/RoomAvatar');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomHeader',
|
||||
mixins: [RoomHeaderController],
|
||||
|
||||
onNameChange: function(new_name) {
|
||||
if (this.props.room.name != new_name && new_name) {
|
||||
MatrixClientPeg.get().setRoomName(this.props.room.roomId, new_name);
|
||||
}
|
||||
},
|
||||
|
||||
getRoomName: function() {
|
||||
return this.refs.name_edit.getDOMNode().value;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
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_textButton" onClick={this.onHangupClick}>
|
||||
End call
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var name = null;
|
||||
var topic_el = null;
|
||||
var cancel_button = null;
|
||||
var save_button = null;
|
||||
var settings_button = null;
|
||||
var actual_name = this.props.room.currentState.getStateEvents('m.room.name', '');
|
||||
if (actual_name) actual_name = actual_name.getContent().name;
|
||||
if (this.props.editing) {
|
||||
name =
|
||||
<div className="mx_RoomHeader_nameEditing">
|
||||
<input className="mx_RoomHeader_nameInput" type="text" defaultValue={actual_name} placeholder="Name" ref="name_edit"/>
|
||||
</div>
|
||||
// if (topic) topic_el = <div className="mx_RoomHeader_topic"><textarea>{ topic.getContent().topic }</textarea></div>
|
||||
cancel_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onCancelClick}>Cancel</div>
|
||||
save_button = <div className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save Changes</div>
|
||||
} else {
|
||||
name =
|
||||
<div className="mx_RoomHeader_name">
|
||||
<EditableText label={this.props.room.name} initialValue={actual_name} placeHolder="Name" onValueChanged={this.onNameChange} />
|
||||
</div>
|
||||
if (topic) topic_el = <div className="mx_RoomHeader_topic" title={topic.getContent().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 roomAvatar = null;
|
||||
if (this.props.room) {
|
||||
roomAvatar = (
|
||||
<RoomAvatar room={this.props.room} />
|
||||
);
|
||||
}
|
||||
|
||||
header =
|
||||
<div className="mx_RoomHeader_wrapper">
|
||||
<div className="mx_RoomHeader_leftRow">
|
||||
<div className="mx_RoomHeader_avatar">
|
||||
{ roomAvatar }
|
||||
</div>
|
||||
<div className="mx_RoomHeader_info">
|
||||
{ name }
|
||||
{ topic_el }
|
||||
</div>
|
||||
</div>
|
||||
{callButtons}
|
||||
{cancel_button}
|
||||
{save_button}
|
||||
<div className="mx_RoomHeader_rightRow">
|
||||
{ settings_button }
|
||||
<div className="mx_RoomHeader_button mx_RoomHeader_search">
|
||||
<img src="img/search.png" title="Search" alt="Search" width="32" height="32"/>
|
||||
</div>
|
||||
<div className="mx_RoomHeader_button mx_RoomHeader_video" onClick={this.onVideoClick}>
|
||||
<img src="img/video.png" title="Video call" alt="Video call" width="32" height="32"/>
|
||||
</div>
|
||||
<div className="mx_RoomHeader_button mx_RoomHeader_voice" onClick={this.onVoiceClick}>
|
||||
<img src="img/voip.png" title="VoIP call" alt="VoIP call" width="32" height="32"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomHeader">
|
||||
{ header }
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
213
src/skins/vector/views/molecules/RoomSettings.js
Normal file
213
src/skins/vector/views/molecules/RoomSettings.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
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 RoomSettingsController = require("../../../../src/controllers/molecules/RoomSettings");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomSettings',
|
||||
mixins: [RoomSettingsController],
|
||||
|
||||
getTopic: function() {
|
||||
return this.refs.topic.getDOMNode().value;
|
||||
},
|
||||
|
||||
getJoinRules: function() {
|
||||
return this.refs.is_private.getDOMNode().checked ? "invite" : "public";
|
||||
},
|
||||
|
||||
getHistoryVisibility: function() {
|
||||
return this.refs.share_history.getDOMNode().checked ? "shared" : "invited";
|
||||
},
|
||||
|
||||
getPowerLevels: function() {
|
||||
if (!this.state.power_levels_changed) return undefined;
|
||||
|
||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
power_levels = power_levels.getContent();
|
||||
|
||||
var new_power_levels = {
|
||||
ban: parseInt(this.refs.ban.getDOMNode().value),
|
||||
kick: parseInt(this.refs.kick.getDOMNode().value),
|
||||
redact: parseInt(this.refs.redact.getDOMNode().value),
|
||||
invite: parseInt(this.refs.invite.getDOMNode().value),
|
||||
events_default: parseInt(this.refs.events_default.getDOMNode().value),
|
||||
state_default: parseInt(this.refs.state_default.getDOMNode().value),
|
||||
users_default: parseInt(this.refs.users_default.getDOMNode().value),
|
||||
users: power_levels.users,
|
||||
events: power_levels.events,
|
||||
};
|
||||
|
||||
return new_power_levels;
|
||||
},
|
||||
|
||||
onPowerLevelsChanged: function() {
|
||||
this.setState({
|
||||
power_levels_changed: true
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
||||
if (topic) topic = topic.getContent().topic;
|
||||
|
||||
var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', '');
|
||||
if (join_rule) join_rule = join_rule.getContent().join_rule;
|
||||
|
||||
var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', '');
|
||||
if (history_visibility) history_visibility = history_visibility.getContent().history_visibility;
|
||||
|
||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
|
||||
if (power_levels) {
|
||||
power_levels = power_levels.getContent();
|
||||
|
||||
var ban_level = parseInt(power_levels.ban);
|
||||
var kick_level = parseInt(power_levels.kick);
|
||||
var redact_level = parseInt(power_levels.redact);
|
||||
var invite_level = parseInt(power_levels.invite || 0);
|
||||
var send_level = parseInt(power_levels.events_default || 0);
|
||||
var state_level = parseInt(power_levels.state_default || 0);
|
||||
var default_user_level = parseInt(power_levels.users_default || 0);
|
||||
|
||||
if (power_levels.ban == undefined) ban_level = 50;
|
||||
if (power_levels.kick == undefined) kick_level = 50;
|
||||
if (power_levels.redact == undefined) redact_level = 50;
|
||||
|
||||
var user_levels = power_levels.users || [];
|
||||
var events_levels = power_levels.events || [];
|
||||
|
||||
var user_id = MatrixClientPeg.get().credentials.userId;
|
||||
|
||||
var current_user_level = user_levels[user_id];
|
||||
if (current_user_level == undefined) current_user_level = default_user_level;
|
||||
|
||||
var power_level_level = events_levels["m.room.power_levels"];
|
||||
if (power_level_level == undefined) {
|
||||
power_level_level = state_level;
|
||||
}
|
||||
|
||||
var can_change_levels = current_user_level >= power_level_level;
|
||||
} else {
|
||||
var ban_level = 50;
|
||||
var kick_level = 50;
|
||||
var redact_level = 50;
|
||||
var invite_level = 0;
|
||||
var send_level = 0;
|
||||
var state_level = 0;
|
||||
var default_user_level = 0;
|
||||
|
||||
var user_levels = [];
|
||||
var events_levels = [];
|
||||
|
||||
var current_user_level = 0;
|
||||
|
||||
var power_level_level = 0;
|
||||
|
||||
var can_change_levels = false;
|
||||
}
|
||||
|
||||
var banned = this.props.room.getMembersWithMemership("ban");
|
||||
|
||||
return (
|
||||
<div className="mx_RoomSettings">
|
||||
<textarea className="mx_RoomSettings_description" placeholder="Topic" defaultValue={topic} ref="topic"/> <br/>
|
||||
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label> <br/>
|
||||
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility == "shared"}/> Share message history with new users</label> <br/>
|
||||
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label> <br/>
|
||||
|
||||
<h3>Power levels</h3>
|
||||
<div className="mx_RoomSettings_power_levels mx_RoomSettings_settings">
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_ban_level">Ban level</label>
|
||||
<input type="text" defaultValue={ban_level} size="3" ref="ban" id="mx_RoomSettings_ban_level"
|
||||
disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_kick_level">Kick level</label>
|
||||
<input type="text" defaultValue={kick_level} size="3" ref="kick" id="mx_RoomSettings_kick_level"
|
||||
disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_redact_level">Redact level</label>
|
||||
<input type="text" defaultValue={redact_level} size="3" ref="redact" id="mx_RoomSettings_redact_level"
|
||||
disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_invite_level">Invite level</label>
|
||||
<input type="text" defaultValue={invite_level} size="3" ref="invite" id="mx_RoomSettings_invite_level"
|
||||
disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_event_level">Send event level</label>
|
||||
<input type="text" defaultValue={send_level} size="3" ref="events_default" id="mx_RoomSettings_event_level"
|
||||
disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_state_level">Set state level</label>
|
||||
<input type="text" defaultValue={state_level} size="3" ref="state_default" id="mx_RoomSettings_state_level"
|
||||
disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="mx_RoomSettings_user_level">Default user level</label>
|
||||
<input type="text" defaultValue={default_user_level} size="3" ref="users_default"
|
||||
id="mx_RoomSettings_user_level" disabled={!can_change_levels || current_user_level < default_user_level}
|
||||
onChange={this.onPowerLevelsChanged}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>User levels</h3>
|
||||
<div className="mx_RoomSettings_user_levels mx_RoomSettings_settings">
|
||||
{Object.keys(user_levels).map(function(user, i) {
|
||||
return (
|
||||
<div key={user}>
|
||||
<label htmlFor={"mx_RoomSettings_user_"+i}>{user}</label>
|
||||
<input type="text" defaultValue={user_levels[user]} size="3" id={"mx_RoomSettings_user_"+i} disabled/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<h3>Event levels</h3>
|
||||
<div className="mx_RoomSettings_event_lvels mx_RoomSettings_settings">
|
||||
{Object.keys(events_levels).map(function(event_type, i) {
|
||||
return (
|
||||
<div key={event_type}>
|
||||
<label htmlFor={"mx_RoomSettings_event_"+i}>{event_type}</label>
|
||||
<input type="text" defaultValue={events_levels[event_type]} size="3" id={"mx_RoomSettings_event_"+i} disabled/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<h3>Banned users</h3>
|
||||
<div className="mx_RoomSettings_banned">
|
||||
{banned.map(function(member, i) {
|
||||
return (
|
||||
<div key={i}>
|
||||
{member.userId}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
71
src/skins/vector/views/molecules/RoomTile.js
Normal file
71
src/skins/vector/views/molecules/RoomTile.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
var RoomTileController = require("../../../../src/controllers/molecules/RoomTile");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var RoomAvatar = ComponentBroker.get('atoms/RoomAvatar');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomTile',
|
||||
mixins: [RoomTileController],
|
||||
render: function() {
|
||||
var myUserId = MatrixClientPeg.get().credentials.userId;
|
||||
var classes = classNames({
|
||||
'mx_RoomTile': true,
|
||||
'mx_RoomTile_selected': this.props.selected,
|
||||
'mx_RoomTile_unread': this.props.unread,
|
||||
'mx_RoomTile_highlight': this.props.highlight,
|
||||
'mx_RoomTile_invited': this.props.room.currentState.members[myUserId].membership == 'invite'
|
||||
});
|
||||
var name = this.props.room.name.replace(":", ":\u200b");
|
||||
var badge;
|
||||
if (this.props.highlight) {
|
||||
badge = <div className="mx_RoomTile_badge"/>;
|
||||
}
|
||||
/*
|
||||
if (this.props.highlight) {
|
||||
badge = <div className="mx_RoomTile_badge">!</div>;
|
||||
}
|
||||
else if (this.props.unread) {
|
||||
badge = <div className="mx_RoomTile_badge">1</div>;
|
||||
}
|
||||
var nameCell;
|
||||
if (badge) {
|
||||
nameCell = <div className="mx_RoomTile_nameBadge"><div className="mx_RoomTile_name">{name}</div><div className="mx_RoomTile_badgeCell">{badge}</div></div>;
|
||||
}
|
||||
else {
|
||||
nameCell = <div className="mx_RoomTile_name">{name}</div>;
|
||||
}
|
||||
*/
|
||||
return (
|
||||
<div className={classes} onClick={this.onClick}>
|
||||
<div className="mx_RoomTile_avatar">
|
||||
<RoomAvatar room={this.props.room} />
|
||||
{ badge }
|
||||
</div>
|
||||
<div className="mx_RoomTile_name">{name}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
53
src/skins/vector/views/molecules/SenderProfile.js
Normal file
53
src/skins/vector/views/molecules/SenderProfile.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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 classNames = require("classnames");
|
||||
|
||||
var SenderProfileController = require("../../../../src/controllers/molecules/SenderProfile");
|
||||
|
||||
// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them.
|
||||
// Revert to Arial when this happens, which on OSX works at least.
|
||||
var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SenderProfile',
|
||||
mixins: [SenderProfileController],
|
||||
|
||||
render: function() {
|
||||
var mxEvent = this.props.mxEvent;
|
||||
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
|
||||
var classes = classNames({
|
||||
mx_SenderProfile: true,
|
||||
// taken from https://en.wikipedia.org/wiki/Combining_character
|
||||
mx_SenderProfile_zalgo: zalgo.test(name),
|
||||
});
|
||||
|
||||
var msgtype = mxEvent.getContent().msgtype;
|
||||
if (msgtype && msgtype == 'm.emote') {
|
||||
name = ''; // emote message must include the name so don't duplicate it
|
||||
}
|
||||
return (
|
||||
<span className={classes}>
|
||||
{name} { this.props.aux }
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
51
src/skins/vector/views/molecules/ServerConfig.js
Normal file
51
src/skins/vector/views/molecules/ServerConfig.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
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 Modal = require('../../../../src/Modal');
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var ErrorDialog = ComponentBroker.get('organisms/ErrorDialog');
|
||||
|
||||
var ServerConfigController = require("../../../../src/controllers/molecules/ServerConfig");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ServerConfig',
|
||||
mixins: [ServerConfigController],
|
||||
|
||||
showHelpPopup: function() {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: 'Custom Server Options',
|
||||
description: "You can use the custom server options to log into other Matrix servers by specifying a different Home server URL. This allows you to use Vector with an existing Matrix account on a different Home server. You can also set a cutom Identity server but this will affect people ability to find you if you use a server in a group other than tha main Matrix.org group.",
|
||||
button: "Dismiss",
|
||||
focus: true
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_ServerConfig">
|
||||
<label className="mx_Login_label mx_ServerConfig_hslabel" htmlFor="hsurl">Home server URL</label>
|
||||
<input className="mx_Login_field" id="hsurl" type="text" value={this.state.hs_url} onChange={this.hsChanged} />
|
||||
<label className="mx_Login_label mx_ServerConfig_islabel" htmlFor="isurl">Identity server URL</label>
|
||||
<input className="mx_Login_field" type="text" value={this.state.is_url} onChange={this.isChanged} />
|
||||
<a className="mx_ServerConfig_help" href="#" onClick={this.showHelpPopup}>What does this mean?</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
35
src/skins/vector/views/molecules/UnknownMessageTile.js
Normal file
35
src/skins/vector/views/molecules/UnknownMessageTile.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
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 UnknownMessageTileController = require("../../../../src/controllers/molecules/UnknownMessageTile");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UnknownMessageTile',
|
||||
mixins: [UnknownMessageTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
return (
|
||||
<span className="mx_UnknownMessageTile">
|
||||
{content.body}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
46
src/skins/vector/views/molecules/UserSelector.js
Normal file
46
src/skins/vector/views/molecules/UserSelector.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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 UserSelectorController = require("../../../../src/controllers/molecules/UserSelector");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UserSelector',
|
||||
mixins: [UserSelectorController],
|
||||
|
||||
onAddUserId: function() {
|
||||
this.addUser(this.refs.user_id_input.getDOMNode().value);
|
||||
this.refs.user_id_input.getDOMNode().value = "";
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
return (
|
||||
<div>
|
||||
<ul className="mx_UserSelector_UserIdList" ref="list">
|
||||
{this.props.selected_users.map(function(user_id, i) {
|
||||
return <li key={user_id}>{user_id} - <span onClick={function() {self.removeUser(user_id);}}>X</span></li>
|
||||
})}
|
||||
</ul>
|
||||
<input type="text" ref="user_id_input" defaultValue="" className="mx_UserSelector_userIdInput" placeholder="ex. @bob:example.com"/>
|
||||
<button onClick={this.onAddUserId} className="mx_UserSelector_AddUserId">Add User</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
41
src/skins/vector/views/molecules/voip/CallView.js
Normal file
41
src/skins/vector/views/molecules/voip/CallView.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../../src/ComponentBroker');
|
||||
var CallViewController = require(
|
||||
"../../../../../src/controllers/molecules/voip/CallView"
|
||||
);
|
||||
var VideoView = ComponentBroker.get('molecules/voip/VideoView');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'CallView',
|
||||
mixins: [CallViewController],
|
||||
|
||||
getVideoView: function() {
|
||||
return this.refs.video;
|
||||
},
|
||||
|
||||
render: function(){
|
||||
return (
|
||||
<VideoView ref="video"/>
|
||||
);
|
||||
}
|
||||
});
|
70
src/skins/vector/views/molecules/voip/IncomingCallBox.js
Normal file
70
src/skins/vector/views/molecules/voip/IncomingCallBox.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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 IncomingCallBoxController = require(
|
||||
"../../../../../src/controllers/molecules/voip/IncomingCallBox"
|
||||
);
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'IncomingCallBox',
|
||||
mixins: [IncomingCallBoxController],
|
||||
|
||||
getRingAudio: function() {
|
||||
return this.refs.ringAudio.getDOMNode();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.incomingCall || !this.state.incomingCall.roomId) {
|
||||
return (
|
||||
<div>
|
||||
<audio ref="ringAudio" loop>
|
||||
<source src="media/ring.ogg" type="audio/ogg" />
|
||||
<source src="media/ring.mp3" type="audio/mpeg" />
|
||||
</audio>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name;
|
||||
return (
|
||||
<div className="mx_IncomingCallBox">
|
||||
<img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" />
|
||||
<audio ref="ringAudio" loop>
|
||||
<source src="media/ring.ogg" type="audio/ogg" />
|
||||
<source src="media/ring.mp3" type="audio/mpeg" />
|
||||
</audio>
|
||||
<div className="mx_IncomingCallBox_title">
|
||||
Incoming { this.state.incomingCall ? this.state.incomingCall.type : '' } call from { caller }
|
||||
</div>
|
||||
<div className="mx_IncomingCallBox_buttons">
|
||||
<div className="mx_IncomingCallBox_buttons_cell">
|
||||
<div className="mx_IncomingCallBox_buttons_decline" onClick={this.onRejectClick}>
|
||||
Decline
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx_IncomingCallBox_buttons_cell">
|
||||
<div className="mx_IncomingCallBox_buttons_accept" onClick={this.onAnswerClick}>
|
||||
Accept
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
50
src/skins/vector/views/molecules/voip/VideoView.js
Normal file
50
src/skins/vector/views/molecules/voip/VideoView.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../../src/ComponentBroker');
|
||||
var VideoViewController = require("../../../../../src/controllers/molecules/voip/VideoView");
|
||||
var VideoFeed = ComponentBroker.get('atoms/voip/VideoFeed');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'VideoView',
|
||||
mixins: [VideoViewController],
|
||||
|
||||
getRemoteVideoElement: function() {
|
||||
return this.refs.remote.getDOMNode();
|
||||
},
|
||||
|
||||
getLocalVideoElement: function() {
|
||||
return this.refs.local.getDOMNode();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_VideoView">
|
||||
<div className="mx_VideoView_remoteVideoFeed">
|
||||
<VideoFeed ref="remote"/>
|
||||
</div>
|
||||
<div className="mx_VideoView_localVideoFeed">
|
||||
<VideoFeed ref="local"/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
170
src/skins/vector/views/organisms/CreateRoom.js
Normal file
170
src/skins/vector/views/organisms/CreateRoom.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
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 CreateRoomController = require("../../../../src/controllers/organisms/CreateRoom");
|
||||
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var PresetValues = require('../../../../src/controllers/atoms/create_room/Presets').Presets;
|
||||
|
||||
var CreateRoomButton = ComponentBroker.get("atoms/create_room/CreateRoomButton");
|
||||
var RoomAlias = ComponentBroker.get("atoms/create_room/RoomAlias");
|
||||
var Presets = ComponentBroker.get("atoms/create_room/Presets");
|
||||
var UserSelector = ComponentBroker.get("molecules/UserSelector");
|
||||
var RoomHeader = ComponentBroker.get("molecules/RoomHeader");
|
||||
|
||||
var Loader = require("react-loader");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'CreateRoom',
|
||||
mixins: [CreateRoomController],
|
||||
|
||||
getPreset: function() {
|
||||
return this.refs.presets.getPreset();
|
||||
},
|
||||
|
||||
getName: function() {
|
||||
return this.refs.name_textbox.getName();
|
||||
},
|
||||
|
||||
getTopic: function() {
|
||||
return this.refs.topic.getTopic();
|
||||
},
|
||||
|
||||
getAliasLocalpart: function() {
|
||||
return this.refs.alias.getAliasLocalpart();
|
||||
},
|
||||
|
||||
getInvitedUsers: function() {
|
||||
return this.refs.user_selector.getUserIds();
|
||||
},
|
||||
|
||||
onPresetChanged: function(preset) {
|
||||
switch (preset) {
|
||||
case PresetValues.PrivateChat:
|
||||
this.setState({
|
||||
preset: preset,
|
||||
is_private: true,
|
||||
share_history: false,
|
||||
});
|
||||
break;
|
||||
case PresetValues.PublicChat:
|
||||
this.setState({
|
||||
preset: preset,
|
||||
is_private: false,
|
||||
share_history: true,
|
||||
});
|
||||
break;
|
||||
case PresetValues.Custom:
|
||||
this.setState({
|
||||
preset: preset,
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onPrivateChanged: function(ev) {
|
||||
this.setState({
|
||||
preset: PresetValues.Custom,
|
||||
is_private: ev.target.checked,
|
||||
});
|
||||
},
|
||||
|
||||
onShareHistoryChanged: function(ev) {
|
||||
this.setState({
|
||||
preset: PresetValues.Custom,
|
||||
share_history: ev.target.checked,
|
||||
});
|
||||
},
|
||||
|
||||
onTopicChange: function(ev) {
|
||||
this.setState({
|
||||
topic: ev.target.value,
|
||||
});
|
||||
},
|
||||
|
||||
onNameChange: function(ev) {
|
||||
this.setState({
|
||||
room_name: ev.target.value,
|
||||
});
|
||||
},
|
||||
|
||||
onInviteChanged: function(invited_users) {
|
||||
this.setState({
|
||||
invited_users: invited_users,
|
||||
});
|
||||
},
|
||||
|
||||
onAliasChanged: function(alias) {
|
||||
this.setState({
|
||||
alias: alias
|
||||
})
|
||||
},
|
||||
|
||||
onEncryptChanged: function(ev) {
|
||||
this.setState({
|
||||
encrypt: ev.target.checked,
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var curr_phase = this.state.phase;
|
||||
if (curr_phase == this.phases.CREATING) {
|
||||
return (
|
||||
<Loader/>
|
||||
);
|
||||
} else {
|
||||
var error_box = "";
|
||||
if (curr_phase == this.phases.ERROR) {
|
||||
error_box = (
|
||||
<div className="mx_Error">
|
||||
An error occured: {this.state.error_string}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="mx_CreateRoom">
|
||||
<RoomHeader simpleHeader="Create room" />
|
||||
<div className="mx_CreateRoom_body">
|
||||
<input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder="Name"/> <br />
|
||||
<textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder="Topic"/> <br />
|
||||
<RoomAlias ref="alias" alias={this.state.alias} onChange={this.onAliasChanged}/> <br />
|
||||
<UserSelector ref="user_selector" selected_users={this.state.invited_users} onChange={this.onInviteChanged}/> <br />
|
||||
<Presets ref="presets" onChange={this.onPresetChanged} preset={this.state.preset}/> <br />
|
||||
<div>
|
||||
<label><input type="checkbox" ref="is_private" checked={this.state.is_private} onChange={this.onPrivateChanged}/> Make this room private</label>
|
||||
</div>
|
||||
<div>
|
||||
<label><input type="checkbox" ref="share_history" checked={this.state.share_history} onChange={this.onShareHistoryChanged}/> Share message history with new users</label>
|
||||
</div>
|
||||
<div className="mx_CreateRoom_encrypt">
|
||||
<label><input type="checkbox" ref="encrypt" checked={this.state.encrypt} onChange={this.onEncryptChanged}/> Encrypt room</label>
|
||||
</div>
|
||||
<div>
|
||||
<CreateRoomButton onCreateRoom={this.onCreateRoom} /> <br />
|
||||
</div>
|
||||
{error_box}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
54
src/skins/vector/views/organisms/ErrorDialog.js
Normal file
54
src/skins/vector/views/organisms/ErrorDialog.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
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';
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
* Modal.createDialog(ErrorDialog, {
|
||||
* title: "some text", (default: "Error")
|
||||
* description: "some more text",
|
||||
* button: "Button Text",
|
||||
* onClose: someFunction,
|
||||
* focus: true|false (default: true)
|
||||
* });
|
||||
*/
|
||||
|
||||
var React = require('react');
|
||||
var ErrorDialogController = require("../../../../src/controllers/organisms/ErrorDialog");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ErrorDialog',
|
||||
mixins: [ErrorDialogController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_ErrorDialog">
|
||||
<div className="mx_ErrorDialogTitle">
|
||||
{this.props.title}
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
{this.props.description}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.props.onFinished} autoFocus={this.props.focus}>
|
||||
{this.props.button}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
41
src/skins/vector/views/organisms/LeftPanel.js
Normal file
41
src/skins/vector/views/organisms/LeftPanel.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var RoomList = ComponentBroker.get('organisms/RoomList');
|
||||
var BottomLeftMenu = ComponentBroker.get('molecules/BottomLeftMenu');
|
||||
var IncomingCallBox = ComponentBroker.get('molecules/voip/IncomingCallBox');
|
||||
var RoomCreate = ComponentBroker.get('molecules/RoomCreate');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'LeftPanel',
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<aside className="mx_LeftPanel">
|
||||
<img className="mx_LeftPanel_hideButton" src="img/hide.png" width="32" height="32" alt="<"/>
|
||||
<IncomingCallBox />
|
||||
<RoomList selectedRoom={this.props.selectedRoom} />
|
||||
<BottomLeftMenu />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
41
src/skins/vector/views/organisms/LogoutPrompt.js
Normal file
41
src/skins/vector/views/organisms/LogoutPrompt.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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 LogoutPromptController = require("../../../../src/controllers/organisms/LogoutPrompt");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'LogoutPrompt',
|
||||
mixins: [LogoutPromptController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_Dialog_content">
|
||||
Sign out?
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.logOut}>Sign Out</button>
|
||||
<button onClick={this.cancelPrompt}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
111
src/skins/vector/views/organisms/MemberList.js
Normal file
111
src/skins/vector/views/organisms/MemberList.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
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 classNames = require('classnames');
|
||||
|
||||
var MemberListController = require("../../../../src/controllers/organisms/MemberList");
|
||||
|
||||
var ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var MemberTile = ComponentBroker.get("molecules/MemberTile");
|
||||
var EditableText = ComponentBroker.get("atoms/EditableText");
|
||||
|
||||
|
||||
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) {
|
||||
var memberListScroll = this.refs.memberListScroll.getDOMNode();
|
||||
// offset the current MemberInfo bubble
|
||||
var memberInfo = document.getElementsByClassName("mx_MemberInfo")[0];
|
||||
if (memberInfo) {
|
||||
memberInfo.style.top = (memberInfo.parentElement.offsetTop - memberListScroll.scrollTop) + "px";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
makeMemberTiles: function() {
|
||||
var self = this;
|
||||
return Object.keys(self.state.memberDict).map(function(userId) {
|
||||
var m = self.state.memberDict[userId];
|
||||
return (
|
||||
<MemberTile key={userId} member={m} ref={userId} />
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
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();
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
},
|
||||
|
||||
inviteTile: function() {
|
||||
var classes = classNames({
|
||||
mx_MemberTile: true,
|
||||
mx_MemberTile_inviteTile: true,
|
||||
mx_MemberTile_inviteEditing: this.state.editing,
|
||||
});
|
||||
|
||||
return (
|
||||
<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" label="Invite" placeHolder="@user:domain.com" initialValue="" onValueChanged={this.onPopulateInvite}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_MemberList">
|
||||
<div className="mx_MemberList_chevron">
|
||||
<img src="img/chevron.png" width="24" height="13"/>
|
||||
</div>
|
||||
<div className="mx_MemberList_border" ref="memberListScroll" onScroll={ this.onMemberListScroll }>
|
||||
<h2>Members</h2>
|
||||
<div className="mx_MemberList_wrapper">
|
||||
{this.makeMemberTiles()}
|
||||
{this.inviteTile()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
100
src/skins/vector/views/organisms/Notifier.js
Normal file
100
src/skins/vector/views/organisms/Notifier.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
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 NotifierController = require("../../../../src/controllers/organisms/Notifier");
|
||||
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
var TextForEvent = require("../../../../src/TextForEvent");
|
||||
var extend = require("../../../../src/extend");
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
var Avatar = require("../../../../src/Avatar");
|
||||
|
||||
|
||||
var NotifierView = {
|
||||
notificationMessageForEvent: function(ev) {
|
||||
return TextForEvent.textForEvent(ev);
|
||||
},
|
||||
|
||||
displayNotification: function(ev, room) {
|
||||
if (!global.Notification || global.Notification.permission != 'granted') {
|
||||
return;
|
||||
}
|
||||
if (global.document.hasFocus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = this.notificationMessageForEvent(ev);
|
||||
if (!msg) return;
|
||||
|
||||
var title;
|
||||
if (!ev.sender || room.name == ev.sender.name) {
|
||||
title = room.name;
|
||||
// notificationMessageForEvent includes sender,
|
||||
// but we already have the sender here
|
||||
if (ev.getContent().body) msg = ev.getContent().body;
|
||||
} else if (ev.getType() == 'm.room.member') {
|
||||
// context is all in the message here, we don't need
|
||||
// to display sender info
|
||||
title = room.name;
|
||||
} else if (ev.sender) {
|
||||
title = ev.sender.name + " (" + room.name + ")";
|
||||
// notificationMessageForEvent includes sender,
|
||||
// but we've just out sender in the title
|
||||
if (ev.getContent().body) msg = ev.getContent().body;
|
||||
}
|
||||
|
||||
var avatarUrl = Avatar.avatarUrlForMember(
|
||||
ev.sender, 40, 40, 'crop'
|
||||
);
|
||||
|
||||
var notification = new global.Notification(
|
||||
title,
|
||||
{
|
||||
"body": msg,
|
||||
"icon": avatarUrl
|
||||
}
|
||||
);
|
||||
|
||||
notification.onclick = function() {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: room.roomId
|
||||
});
|
||||
global.focus();
|
||||
};
|
||||
|
||||
/*var audioClip;
|
||||
|
||||
if (audioNotification) {
|
||||
audioClip = playAudio(audioNotification);
|
||||
}*/
|
||||
|
||||
global.setTimeout(function() {
|
||||
notification.close();
|
||||
}, 5 * 1000);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var NotifierClass = function() {};
|
||||
extend(NotifierClass.prototype, NotifierController);
|
||||
extend(NotifierClass.prototype, NotifierView);
|
||||
|
||||
module.exports = new NotifierClass();
|
||||
|
66
src/skins/vector/views/organisms/QuestionDialog.js
Normal file
66
src/skins/vector/views/organisms/QuestionDialog.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
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';
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
* Modal.createDialog(ErrorDialog, {
|
||||
* title: "some text", (default: "Error")
|
||||
* description: "some more text",
|
||||
* button: "Button Text",
|
||||
* onClose: someFunction,
|
||||
* focus: true|false (default: true)
|
||||
* });
|
||||
*/
|
||||
|
||||
var React = require('react');
|
||||
var QuestionDialogController = require("../../../../src/controllers/organisms/QuestionDialog");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'QuestionDialog',
|
||||
mixins: [QuestionDialogController],
|
||||
|
||||
onOk: function() {
|
||||
this.props.onFinished(true);
|
||||
},
|
||||
|
||||
onCancel: function() {
|
||||
this.props.onFinished(false);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_QuestionDialog">
|
||||
<div className="mx_QuestionDialogTitle">
|
||||
{this.props.title}
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
{this.props.description}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button onClick={this.onOk} autoFocus={this.props.focus}>
|
||||
{this.props.button}
|
||||
</button>
|
||||
|
||||
<button onClick={this.onCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
78
src/skins/vector/views/organisms/RightPanel.js
Normal file
78
src/skins/vector/views/organisms/RightPanel.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
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.MemberList
|
||||
}
|
||||
},
|
||||
|
||||
onMemberListButtonClick: function() {
|
||||
if (this.state.phase == this.Phase.None) {
|
||||
this.setState({ phase: this.Phase.MemberList });
|
||||
}
|
||||
else {
|
||||
this.setState({ phase: this.Phase.None });
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var buttonGroup;
|
||||
var panel;
|
||||
if (this.props.roomId) {
|
||||
buttonGroup =
|
||||
<div className="mx_RightPanel_headerButtonGroup">
|
||||
<div className="mx_RightPanel_headerButton mx_RightPanel_filebutton">
|
||||
<img src="img/file.png" width="32" height="32" title="Files" alt="Files"/>
|
||||
</div>
|
||||
<div className="mx_RightPanel_headerButton" onClick={ this.onMemberListButtonClick }>
|
||||
<img src="img/members.png" width="32" height="32" title="Members" alt="Members"/>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
if (this.state.phase == this.Phase.MemberList) {
|
||||
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="mx_RightPanel">
|
||||
<div className="mx_RightPanel_header">
|
||||
{ buttonGroup }
|
||||
</div>
|
||||
{ panel }
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
147
src/skins/vector/views/organisms/RoomDirectory.js
Normal file
147
src/skins/vector/views/organisms/RoomDirectory.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
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");
|
||||
|
||||
var Loader = require("react-loader");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomDirectory',
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
publicRooms: [],
|
||||
roomAlias: '',
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
var self = this;
|
||||
MatrixClientPeg.get().publicRooms(function (err, data) {
|
||||
if (err) {
|
||||
self.setState({ loading: false });
|
||||
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,
|
||||
loading: false,
|
||||
});
|
||||
self.forceUpdate();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
joinRoom: function(roomId) {
|
||||
var self = this;
|
||||
self.setState({ loading: true });
|
||||
// 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
|
||||
// incrementally rather than starting over each time.
|
||||
return (a.aliases[0].search(filter) >= 0 && a.num_joined_members > 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 || rooms[i].aliases[0];
|
||||
// <img src={ MatrixClientPeg.get().getAvatarUrlForRoom(rooms[i].room_id, 40, 40, "crop") } width="40" height="40" alt=""/>
|
||||
rows.unshift(
|
||||
<tbody key={ rooms[i].room_id }>
|
||||
<tr onClick={self.joinRoom.bind(null, rooms[i].room_id)}>
|
||||
<td className="mx_RoomDirectory_name">{ name }</td>
|
||||
<td>{ rooms[i].aliases[0] }</td>
|
||||
<td>{ rooms[i].num_joined_members }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="mx_RoomDirectory_topic" colSpan="3">{ rooms[i].topic }</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
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() {
|
||||
if (this.state.loading) {
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
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 }/>
|
||||
<div className="mx_RoomDirectory_tableWrapper">
|
||||
<table className="mx_RoomDirectory_table">
|
||||
<tr><th width="45%">Room</th><th width="45%">Alias</th><th width="10%">Members</th></tr>
|
||||
{ this.getRows(this.state.roomAlias) }
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
53
src/skins/vector/views/organisms/RoomList.js
Normal file
53
src/skins/vector/views/organisms/RoomList.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var CallView = ComponentBroker.get('molecules/voip/CallView');
|
||||
var RoomDropTarget = ComponentBroker.get('molecules/RoomDropTarget');
|
||||
|
||||
var RoomListController = require("../../../../src/controllers/organisms/RoomList");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomList',
|
||||
mixins: [RoomListController],
|
||||
|
||||
render: function() {
|
||||
var callElement;
|
||||
if (this.state.show_call_element) {
|
||||
callElement = <CallView className="mx_MatrixChat_callView"/>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomList">
|
||||
{callElement}
|
||||
<h2 className="mx_RoomList_favourites_label">Favourites</h2>
|
||||
<RoomDropTarget text="Drop here to favourite"/>
|
||||
|
||||
<h2 className="mx_RoomList_recents_label">Recents</h2>
|
||||
<div className="mx_RoomList_recents">
|
||||
{this.makeRoomTiles()}
|
||||
</div>
|
||||
|
||||
<h2 className="mx_RoomList_archive_label">Archive</h2>
|
||||
<RoomDropTarget text="Drop here to archive"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
227
src/skins/vector/views/organisms/RoomView.js
Normal file
227
src/skins/vector/views/organisms/RoomView.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var classNames = require("classnames");
|
||||
var filesize = require('filesize');
|
||||
var q = require('q');
|
||||
|
||||
var MessageTile = ComponentBroker.get('molecules/MessageTile');
|
||||
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
|
||||
var MessageComposer = ComponentBroker.get('molecules/MessageComposer');
|
||||
var CallView = ComponentBroker.get("molecules/voip/CallView");
|
||||
var RoomSettings = ComponentBroker.get("molecules/RoomSettings");
|
||||
var RoomViewController = require("../../../../src/controllers/organisms/RoomView");
|
||||
|
||||
var Loader = require("react-loader");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomView',
|
||||
mixins: [RoomViewController],
|
||||
|
||||
onSettingsClick: function() {
|
||||
this.setState({editingRoomSettings: true});
|
||||
},
|
||||
|
||||
onSaveClick: function() {
|
||||
this.setState({
|
||||
editingRoomSettings: false,
|
||||
uploadingRoomSettings: true,
|
||||
});
|
||||
|
||||
var new_name = this.refs.header.getRoomName();
|
||||
var new_topic = this.refs.room_settings.getTopic();
|
||||
var new_join_rule = this.refs.room_settings.getJoinRules();
|
||||
var new_history_visibility = this.refs.room_settings.getHistoryVisibility();
|
||||
var new_power_levels = this.refs.room_settings.getPowerLevels();
|
||||
|
||||
this.uploadNewState(
|
||||
new_name,
|
||||
new_topic,
|
||||
new_join_rule,
|
||||
new_history_visibility,
|
||||
new_power_levels
|
||||
);
|
||||
},
|
||||
|
||||
onCancelClick: function() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
||||
getUnreadMessagesString: function() {
|
||||
if (!this.state.numUnreadMessages) {
|
||||
return "";
|
||||
}
|
||||
return this.state.numUnreadMessages + " new message" + (this.state.numUnreadMessages > 1 ? "s" : "");
|
||||
},
|
||||
|
||||
scrollToBottom: function() {
|
||||
if (!this.refs.messageWrapper) return;
|
||||
var messageWrapper = this.refs.messageWrapper.getDOMNode();
|
||||
messageWrapper.scrollTop = messageWrapper.scrollHeight;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.room) {
|
||||
if (this.props.roomId) {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.onJoinButtonClicked}>Join Room</button>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var myUserId = MatrixClientPeg.get().credentials.userId;
|
||||
if (this.state.room.currentState.members[myUserId].membership == 'invite') {
|
||||
if (this.state.joining) {
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
var inviteEvent = this.state.room.currentState.members[myUserId].events.member.event;
|
||||
// XXX: Leaving this intentionally basic for now because invites are about to change totally
|
||||
var joinErrorText = this.state.joinError ? "Failed to join room!" : "";
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
<RoomHeader ref="header" room={this.state.room} simpleHeader="Room invite"/>
|
||||
<div className="mx_RoomView_invitePrompt">
|
||||
<div>{inviteEvent.user_id} has invited you to a room</div>
|
||||
<br/>
|
||||
<button ref="joinButton" onClick={this.onJoinButtonClicked}>Join</button>
|
||||
<div className="error">{joinErrorText}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
var scrollheader_classes = classNames({
|
||||
mx_RoomView_scrollheader: true,
|
||||
loading: this.state.paginating
|
||||
});
|
||||
|
||||
var statusBar = (
|
||||
<div />
|
||||
);
|
||||
|
||||
if (this.state.upload) {
|
||||
var innerProgressStyle = {
|
||||
width: ((this.state.upload.uploadedBytes / this.state.upload.totalBytes) * 100) + '%'
|
||||
};
|
||||
statusBar = (
|
||||
<div className="mx_RoomView_uploadBar">
|
||||
<span className="mx_RoomView_uploadFilename">Uploading {this.state.upload.fileName}</span>
|
||||
<span className="mx_RoomView_uploadBytes">
|
||||
{filesize(this.state.upload.uploadedBytes)} / {filesize(this.state.upload.totalBytes)}
|
||||
</span>
|
||||
<div className="mx_RoomView_uploadProgressOuter">
|
||||
<div className="mx_RoomView_uploadProgressInner" style={innerProgressStyle}></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
var typingString = this.getWhoIsTypingString();
|
||||
var unreadMsgs = this.getUnreadMessagesString();
|
||||
// unread count trumps who is typing since the unread count is only
|
||||
// set when you've scrolled up
|
||||
if (unreadMsgs) {
|
||||
statusBar = (
|
||||
<div className="mx_RoomView_unreadMessagesBar" onClick={ this.scrollToBottom }>
|
||||
<img src="img/newmessages.png" width="10" height="12" alt=""/>
|
||||
{unreadMsgs}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else if (typingString) {
|
||||
statusBar = (
|
||||
<div className="mx_RoomView_typingBar">
|
||||
<img src="img/typing.png" width="40" height="40" alt=""/>
|
||||
{typingString}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var roomEdit = null;
|
||||
if (this.state.editingRoomSettings) {
|
||||
roomEdit = <RoomSettings ref="room_settings" onSaveClick={this.onSaveClick} room={this.state.room} />;
|
||||
}
|
||||
if (this.state.uploadingRoomSettings) {
|
||||
roomEdit = <Loader/>;
|
||||
}
|
||||
|
||||
var conferenceCallNotification = null;
|
||||
if (this.state.displayConfCallNotification) {
|
||||
conferenceCallNotification = (
|
||||
<div className="mx_RoomView_ongoingConfCallNotification" onClick={this.onConferenceNotificationClick}>
|
||||
Ongoing conference call
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
var fileDropTarget = null;
|
||||
if (this.state.draggingFile) {
|
||||
fileDropTarget = <div className="mx_RoomView_fileDropTarget">
|
||||
<div className="mx_RoomView_fileDropTargetLabel">
|
||||
<img src="img/upload-big.png" width="46" height="61" alt="Drop File Here"/><br/>
|
||||
Drop File Here
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
<RoomHeader ref="header" room={this.state.room} editing={this.state.editingRoomSettings}
|
||||
onSettingsClick={this.onSettingsClick} onSaveClick={this.onSaveClick} onCancelClick={this.onCancelClick} />
|
||||
<div className="mx_RoomView_auxPanel">
|
||||
<CallView room={this.state.room}/>
|
||||
{ conferenceCallNotification }
|
||||
{ roomEdit }
|
||||
</div>
|
||||
<div ref="messageWrapper" className="mx_RoomView_messagePanel" onScroll={ this.onMessageListScroll }>
|
||||
<div className="mx_RoomView_messageListWrapper">
|
||||
{ fileDropTarget }
|
||||
<ol className="mx_RoomView_MessageList" aria-live="polite">
|
||||
<li className={scrollheader_classes}>
|
||||
</li>
|
||||
{this.getEventTiles()}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx_RoomView_statusArea">
|
||||
<div className="mx_RoomView_statusAreaBox">
|
||||
{statusBar}
|
||||
</div>
|
||||
</div>
|
||||
<MessageComposer room={this.state.room} uploadFile={this.uploadFile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
113
src/skins/vector/views/organisms/UserSettings.js
Normal file
113
src/skins/vector/views/organisms/UserSettings.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
var UserSettingsController = require("../../../../src/controllers/organisms/UserSettings");
|
||||
|
||||
var EditableText = ComponentBroker.get('atoms/EditableText');
|
||||
var EnableNotificationsButton = ComponentBroker.get('atoms/EnableNotificationsButton');
|
||||
var ChangeAvatar = ComponentBroker.get('molecules/ChangeAvatar');
|
||||
var ChangePassword = ComponentBroker.get('molecules/ChangePassword');
|
||||
var LogoutPrompt = ComponentBroker.get('organisms/LogoutPrompt');
|
||||
var Loader = require("react-loader");
|
||||
|
||||
var Modal = require("../../../../src/Modal");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UserSettings',
|
||||
mixins: [UserSettingsController],
|
||||
|
||||
editAvatar: function() {
|
||||
var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
|
||||
Modal.createDialog(ChangeAvatar, {initialAvatarUrl: url});
|
||||
},
|
||||
|
||||
addEmail: function() {
|
||||
|
||||
},
|
||||
|
||||
editDisplayName: function() {
|
||||
this.refs.displayname.edit();
|
||||
},
|
||||
|
||||
changePassword: function() {
|
||||
Modal.createDialog(ChangePassword);
|
||||
},
|
||||
|
||||
onLogoutClicked: function(ev) {
|
||||
this.logoutModal = Modal.createDialog(LogoutPrompt, {onCancel: this.onLogoutPromptCancel});
|
||||
},
|
||||
|
||||
onLogoutPromptCancel: function() {
|
||||
this.logoutModal.closeDialog();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
switch (this.state.phase) {
|
||||
case this.Phases.Loading:
|
||||
return <Loader />
|
||||
case this.Phases.Display:
|
||||
return (
|
||||
<div className="mx_UserSettings">
|
||||
<div className="mx_UserSettings_User">
|
||||
<h1>User Settings</h1>
|
||||
<hr/>
|
||||
<div className="mx_UserSettings_User_Inner">
|
||||
<div className="mx_UserSettings_Avatar">
|
||||
<div className="mx_UserSettings_Avatar_Text">Profile Photo</div>
|
||||
<div className="mx_UserSettings_Avatar_Edit" onClick={this.editAvatar}>Edit</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_DisplayName">
|
||||
<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>
|
||||
|
||||
<div className="mx_UserSettings_3pids">
|
||||
{this.state.threepids.map(function(val) {
|
||||
return <div>{val.address}</div>;
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_Add3pid" onClick={this.addEmail}>Add email</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_Global">
|
||||
<h1>Global Settings</h1>
|
||||
<hr/>
|
||||
<div className="mx_UserSettings_Global_Inner">
|
||||
<div className="mx_UserSettings_ChangePassword" onClick={this.changePassword}>
|
||||
Change Password
|
||||
</div>
|
||||
<div className="mx_UserSettings_ClientVersion">
|
||||
Version {this.state.clientVersion}
|
||||
</div>
|
||||
<div className="mx_UserSettings_EnableNotifications">
|
||||
<EnableNotificationsButton />
|
||||
</div>
|
||||
<div className="mx_UserSettings_Logout">
|
||||
<button onClick={this.onLogoutClicked}>Sign Out</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
122
src/skins/vector/views/pages/MatrixChat.js
Normal file
122
src/skins/vector/views/pages/MatrixChat.js
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
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 ComponentBroker = require('../../../../src/ComponentBroker');
|
||||
|
||||
var LeftPanel = ComponentBroker.get('organisms/LeftPanel');
|
||||
var RoomView = ComponentBroker.get('organisms/RoomView');
|
||||
var RightPanel = ComponentBroker.get('organisms/RightPanel');
|
||||
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 MatrixToolbar = ComponentBroker.get('molecules/MatrixToolbar');
|
||||
var Notifier = ComponentBroker.get('organisms/Notifier');
|
||||
|
||||
var MatrixChatController = require('../../../../src/controllers/pages/MatrixChat');
|
||||
|
||||
// should be atomised
|
||||
var Loader = require("react-loader");
|
||||
var classNames = require("classnames");
|
||||
|
||||
var dis = require("../../../../src/dispatcher");
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MatrixChat',
|
||||
mixins: [MatrixChatController],
|
||||
|
||||
onRoomCreated: function(room_id) {
|
||||
dis.dispatch({
|
||||
action: "view_room",
|
||||
room_id: room_id,
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.logged_in && this.state.ready) {
|
||||
|
||||
var page_element;
|
||||
var right_panel = "";
|
||||
|
||||
switch (this.state.page_type) {
|
||||
case this.PageTypes.RoomView:
|
||||
page_element = <RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
|
||||
right_panel = <RightPanel roomId={this.state.currentRoom} />
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: Fix duplication here and do conditionals like we do above
|
||||
if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) {
|
||||
return (
|
||||
<div className="mx_MatrixChat_wrapper">
|
||||
<MatrixToolbar />
|
||||
<div className="mx_MatrixChat mx_MatrixChat_toolbarShowing">
|
||||
<LeftPanel selectedRoom={this.state.currentRoom} />
|
||||
<main className="mx_MatrixChat_middlePanel">
|
||||
{page_element}
|
||||
</main>
|
||||
{right_panel}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<div className="mx_MatrixChat">
|
||||
<LeftPanel selectedRoom={this.state.currentRoom} />
|
||||
<main className="mx_MatrixChat_middlePanel">
|
||||
{page_element}
|
||||
</main>
|
||||
{right_panel}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} else if (this.state.logged_in) {
|
||||
return (
|
||||
<Loader />
|
||||
);
|
||||
} else if (this.state.screen == 'register') {
|
||||
return (
|
||||
<Register onLoggedIn={this.onLoggedIn} clientSecret={this.state.register_client_secret}
|
||||
sessionId={this.state.register_session_id} idSid={this.state.register_id_sid}
|
||||
hsUrl={this.state.register_hs_url} isUrl={this.state.register_is_url}
|
||||
registrationUrl={this.props.registrationUrl}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Login onLoggedIn={this.onLoggedIn} />
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
191
src/skins/vector/views/templates/Login.js
Normal file
191
src/skins/vector/views/templates/Login.js
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
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 ComponentBroker = require("../../../../src/ComponentBroker");
|
||||
var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
|
||||
|
||||
var ProgressBar = ComponentBroker.get("molecules/ProgressBar");
|
||||
var Loader = require("react-loader");
|
||||
|
||||
var LoginController = require("../../../../src/controllers/templates/Login");
|
||||
|
||||
var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
|
||||
|
||||
module.exports = React.createClass({
|
||||
DEFAULT_HS_URL: 'https://matrix.org',
|
||||
DEFAULT_IS_URL: 'https://vector.im',
|
||||
|
||||
displayName: 'Login',
|
||||
mixins: [LoginController],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
serverConfigVisible: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.onHSChosen();
|
||||
this.customHsUrl = this.DEFAULT_HS_URL;
|
||||
this.customIsUrl = this.DEFAULT_IS_URL;
|
||||
},
|
||||
|
||||
getHsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customHsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_HS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
getIsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customIsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_IS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
onServerConfigVisibleChange: function(ev) {
|
||||
this.setState({
|
||||
serverConfigVisible: ev.target.checked
|
||||
}, this.onHsUrlChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the form field values for the current login stage
|
||||
*/
|
||||
getFormVals: function() {
|
||||
return {
|
||||
'username': this.refs.user.getDOMNode().value.trim(),
|
||||
'password': this.refs.pass.getDOMNode().value.trim()
|
||||
};
|
||||
},
|
||||
|
||||
onHsUrlChanged: function() {
|
||||
var newHsUrl = this.refs.serverConfig.getHsUrl().trim();
|
||||
var newIsUrl = this.refs.serverConfig.getIsUrl().trim();
|
||||
|
||||
if (newHsUrl == this.customHsUrl &&
|
||||
newIsUrl == this.customIsUrl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else {
|
||||
this.customHsUrl = newHsUrl;
|
||||
this.customIsUrl = newIsUrl;
|
||||
}
|
||||
|
||||
MatrixClientPeg.replaceUsingUrls(
|
||||
this.getHsUrl(),
|
||||
this.getIsUrl()
|
||||
);
|
||||
this.setState({
|
||||
hs_url: this.getHsUrl(),
|
||||
is_url: this.getIsUrl()
|
||||
});
|
||||
// XXX: HSes do not have to offer password auth, so we
|
||||
// need to update and maybe show a different component
|
||||
// when a new HS is entered.
|
||||
if (this.updateHsTimeout) {
|
||||
clearTimeout(this.updateHsTimeout);
|
||||
}
|
||||
var self = this;
|
||||
this.updateHsTimeout = setTimeout(function() {
|
||||
self.onHSChosen();
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
componentForStep: function(step) {
|
||||
switch (step) {
|
||||
case 'choose_hs':
|
||||
case 'fetch_stages':
|
||||
var serverConfigStyle = {};
|
||||
serverConfigStyle.display = this.state.serverConfigVisible ? 'block' : 'none';
|
||||
return (
|
||||
<div>
|
||||
<input className="mx_Login_checkbox" id="advanced" type="checkbox" checked={this.state.serverConfigVisible} onChange={this.onServerConfigVisibleChange} />
|
||||
<label className="mx_Login_label" htmlFor="advanced">Use custom server options (advanced)</label>
|
||||
<div style={serverConfigStyle}>
|
||||
<ServerConfig ref="serverConfig"
|
||||
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
|
||||
onHsUrlChanged={this.onHsUrlChanged}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
// XXX: clearly these should be separate organisms
|
||||
case 'stage_m.login.password':
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={this.onUserPassEntered}>
|
||||
<input className="mx_Login_field" ref="user" type="text" value={this.state.username} onChange={this.onUsernameChanged} placeholder="Email or user name" /><br />
|
||||
<input className="mx_Login_field" ref="pass" type="password" value={this.state.password} onChange={this.onPasswordChanged} placeholder="Password" /><br />
|
||||
{ this.componentForStep('choose_hs') }
|
||||
<input className="mx_Login_submit" type="submit" value="Log in" />
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
onUsernameChanged: function(ev) {
|
||||
this.setState({username: ev.target.value});
|
||||
},
|
||||
|
||||
onPasswordChanged: function(ev) {
|
||||
this.setState({password: ev.target.value});
|
||||
},
|
||||
|
||||
loginContent: function() {
|
||||
var loader = this.state.busy ? <div className="mx_Login_loader"><Loader /></div> : null;
|
||||
return (
|
||||
<div>
|
||||
<h2>Sign in</h2>
|
||||
{this.componentForStep(this.state.step)}
|
||||
<div className="mx_Login_error">
|
||||
{ loader }
|
||||
{this.state.errorText}
|
||||
</div>
|
||||
<a className="mx_Login_create" onClick={this.showRegister} href="#">Create a new account</a>
|
||||
<br/>
|
||||
<div className="mx_Login_links">
|
||||
<a href="https://medium.com/@Vector">blog</a> ·
|
||||
<a href="https://twitter.com/@VectorCo">twitter</a> ·
|
||||
<a href="https://github.com/vector-im/vector-web">github</a> ·
|
||||
<a href="https://matrix.org">powered by Matrix</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login">
|
||||
<div className="mx_Login_box">
|
||||
<div className="mx_Login_logo">
|
||||
<img src="img/logo.png" width="249" height="78" alt="vector"/>
|
||||
</div>
|
||||
{this.loginContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
192
src/skins/vector/views/templates/Register.js
Normal file
192
src/skins/vector/views/templates/Register.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
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 ComponentBroker = require("../../../../src/ComponentBroker");
|
||||
|
||||
var Loader = require("react-loader");
|
||||
|
||||
var RegisterController = require("../../../../src/controllers/templates/Register");
|
||||
|
||||
var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
|
||||
|
||||
module.exports = React.createClass({
|
||||
DEFAULT_HS_URL: 'https://matrix.org',
|
||||
DEFAULT_IS_URL: 'https://vector.im',
|
||||
|
||||
displayName: 'Register',
|
||||
mixins: [RegisterController],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
serverConfigVisible: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.customHsUrl = this.DEFAULT_HS_URL;
|
||||
this.customIsUrl = this.DEFAULT_IS_URL;
|
||||
},
|
||||
|
||||
getRegFormVals: function() {
|
||||
return {
|
||||
email: this.refs.email.getDOMNode().value.trim(),
|
||||
username: this.refs.username.getDOMNode().value.trim(),
|
||||
password: this.refs.password.getDOMNode().value.trim(),
|
||||
confirmPassword: this.refs.confirmPassword.getDOMNode().value.trim()
|
||||
};
|
||||
},
|
||||
|
||||
getHsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customHsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_HS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
getIsUrl: function() {
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customIsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_IS_URL;
|
||||
}
|
||||
},
|
||||
|
||||
onServerConfigVisibleChange: function(ev) {
|
||||
this.setState({
|
||||
serverConfigVisible: ev.target.checked
|
||||
});
|
||||
},
|
||||
|
||||
getUserIdSuffix: function() {
|
||||
return '';
|
||||
var actualHsUrl = document.createElement('a');
|
||||
actualHsUrl.href = this.getHsUrl();
|
||||
var defaultHsUrl = document.createElement('a');
|
||||
defaultHsUrl.href = this.DEFAULT_HS_URL;
|
||||
if (actualHsUrl.host == defaultHsUrl.host) {
|
||||
return ':matrix.org';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
onServerUrlChanged: function(newUrl) {
|
||||
this.customHsUrl = this.refs.serverConfig.getHsUrl();
|
||||
this.customIsUrl = this.refs.serverConfig.getIsUrl();
|
||||
this.forceUpdate();
|
||||
},
|
||||
|
||||
componentForStep: function(step) {
|
||||
switch (step) {
|
||||
case 'initial':
|
||||
var serverConfigStyle = {};
|
||||
serverConfigStyle.display = this.state.serverConfigVisible ? 'block' : 'none';
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={this.onInitialStageSubmit}>
|
||||
<input className="mx_Login_field" type="text" ref="email" placeholder="Email address" defaultValue={this.savedParams.email} /><br />
|
||||
<input className="mx_Login_field" type="text" ref="username" placeholder="User name" defaultValue={this.savedParams.username} />{this.getUserIdSuffix()}<br />
|
||||
<input className="mx_Login_field" type="password" ref="password" placeholder="Password" defaultValue={this.savedParams.password} /><br />
|
||||
<input className="mx_Login_field" type="password" ref="confirmPassword" placeholder="Confirm password" defaultValue={this.savedParams.confirmPassword} /><br />
|
||||
|
||||
<input className="mx_Login_checkbox" id="advanced" type="checkbox" value={this.state.serverConfigVisible} onChange={this.onServerConfigVisibleChange} />
|
||||
<label htmlFor="advanced">Use custom server options (advanced)</label>
|
||||
<div style={serverConfigStyle}>
|
||||
<ServerConfig ref="serverConfig"
|
||||
defaultHsUrl={this.customHsUrl} defaultIsUrl={this.customIsUrl}
|
||||
onHsUrlChanged={this.onServerUrlChanged} onIsUrlChanged={this.onServerUrlChanged} />
|
||||
</div>
|
||||
<br />
|
||||
<input className="mx_Login_submit" type="submit" value="Register" />
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
// XXX: clearly these should be separate organisms
|
||||
case 'stage_m.login.email.identity':
|
||||
return (
|
||||
<div>
|
||||
Please check your email to continue registration.
|
||||
</div>
|
||||
);
|
||||
case 'stage_m.login.recaptcha':
|
||||
return (
|
||||
<div ref="recaptchaContainer">
|
||||
This Home Server would like to make sure you are not a robot
|
||||
<div id="mx_recaptcha"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
registerContent: function() {
|
||||
if (this.state.busy) {
|
||||
return (
|
||||
<Loader />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<h2>Create an account</h2>
|
||||
{this.componentForStep(this.state.step)}
|
||||
<div className="mx_Login_error">{this.state.errorText}</div>
|
||||
<a className="mx_Login_create" onClick={this.showLogin} href="#">I already have an account</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
onBadFields: function(bad) {
|
||||
var keys = Object.keys(bad);
|
||||
var strings = [];
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
switch (bad[keys[i]]) {
|
||||
case this.FieldErrors.PasswordMismatch:
|
||||
strings.push("Passwords don't match");
|
||||
break;
|
||||
case this.FieldErrors.Missing:
|
||||
strings.push("Missing "+keys[i]);
|
||||
break;
|
||||
case this.FieldErrors.TooShort:
|
||||
strings.push(keys[i]+" is too short");
|
||||
break;
|
||||
case this.FieldErrors.InUse:
|
||||
strings.push(keys[i]+" is already taken");
|
||||
break;
|
||||
}
|
||||
}
|
||||
var errtxt = strings.join(', ');
|
||||
this.setState({
|
||||
errorText: errtxt
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_Login">
|
||||
<div className="mx_Login_box">
|
||||
<div className="mx_Login_logo">
|
||||
<img src="img/logo.png" width="249" height="78" alt="vector"/>
|
||||
</div>
|
||||
{this.registerContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue