Compare commits
47 Commits
kegan/time
...
v0.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3db86b1f59 | ||
|
|
5c77395faa | ||
|
|
74afa710d1 | ||
|
|
e48e636c44 | ||
|
|
4118c05d15 | ||
|
|
cee37c4152 | ||
|
|
4175dcd102 | ||
|
|
35862e0c66 | ||
|
|
424d1b84db | ||
|
|
3423a493e7 | ||
|
|
731ad26be4 | ||
|
|
9dfd0bc3bb | ||
|
|
05dba9c2d4 | ||
|
|
ed52bc37b2 | ||
|
|
99e8a54a27 | ||
|
|
9455d02d50 | ||
|
|
c98f7f926a | ||
|
|
c91b642a8b | ||
|
|
ce33c8cdf6 | ||
|
|
58bac0fbdc | ||
|
|
9217ae8fbb | ||
|
|
e580cb809d | ||
|
|
5844fb4020 | ||
|
|
8257f325c4 | ||
|
|
379fed813e | ||
|
|
1188c4c69f | ||
|
|
88dd135b5a | ||
|
|
5392afdec4 | ||
|
|
e844b7aa21 | ||
|
|
d66427ddde | ||
|
|
f618585bd6 | ||
|
|
7c6fb36520 | ||
|
|
351a94b4a1 | ||
|
|
ad4e3418ff | ||
|
|
82affac438 | ||
|
|
08270b26ee | ||
|
|
4b645bcd66 | ||
|
|
1f3a6e408c | ||
|
|
3779ff7691 | ||
|
|
3d3680e42f | ||
|
|
af67df4c4a | ||
|
|
bf40011815 | ||
|
|
a9b093b7f5 | ||
|
|
5e7bd1e51f | ||
|
|
044c75270f | ||
|
|
209889210b | ||
|
|
93d81d27ba |
11
CHANGES.rst
11
CHANGES.rst
@@ -1,3 +1,14 @@
|
||||
Changes in vector v0.1.2 (2015-10-28)
|
||||
======================================
|
||||
* Support Room Avatars
|
||||
* Fullscreen video calls
|
||||
* Mute mic in VoIP calls
|
||||
* Fix bug with multiple desktop notifications
|
||||
* Context menu on messages
|
||||
* Better hover-over on member list
|
||||
* Support CAS auth
|
||||
* Many other bug fixes
|
||||
|
||||
Changes in vector v0.1.1 (2015-08-10)
|
||||
======================================
|
||||
|
||||
|
||||
25
README.md
25
README.md
@@ -22,14 +22,27 @@ into the `vector` directory and run your own server.
|
||||
|
||||
Development
|
||||
===========
|
||||
You can work on any of the source files within Vector with the setup above,
|
||||
and your changes will cause an instant rebuild. If you also need to make
|
||||
changes to the react sdk, you can:
|
||||
|
||||
1. Link the react sdk package into the example:
|
||||
For simple tweaks, you can work on any of the source files within Vector with the
|
||||
setup above, and your changes will cause an instant rebuild.
|
||||
|
||||
However, all serious development on Vector happens on the `develop` branch. This typically
|
||||
depends on the `develop` snapshot versions of `matrix-react-sdk` and `matrix-js-sdk`
|
||||
too, which isn't expressed in Vector's `package.json`. To do this, check out
|
||||
the `develop` branches of these libraries and then use `npm link` to tell Vector
|
||||
about them:
|
||||
|
||||
1. `git clone git@github.com:matrix-org/matrix-react-sdk.git`
|
||||
2. `cd matrix-react-sdk`
|
||||
3. `git checkout develop`
|
||||
4. `npm install`
|
||||
5. `npm start` (to start the dev rebuilder)
|
||||
6. `cd ../vector-web`
|
||||
7. Link the react sdk package into the example:
|
||||
`npm link path/to/your/react/sdk`
|
||||
2. Start the development rebuilder in your react SDK directory:
|
||||
`npm start`
|
||||
|
||||
Similarly, you may need to `npm link path/to/your/js/sdk` in your `matrix-react-sdk`
|
||||
directory.
|
||||
|
||||
If you add or remove any components from the Vector skin, you will need to rebuild
|
||||
the skin's index by running, `npm run reskindex`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vector-web",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.2",
|
||||
"description": "Vector webapp",
|
||||
"author": "matrix.org",
|
||||
"repository": {
|
||||
@@ -27,8 +27,8 @@
|
||||
"filesize": "^3.1.2",
|
||||
"flux": "~2.0.3",
|
||||
"linkifyjs": "^2.0.0-beta.4",
|
||||
"matrix-js-sdk": "^0.2.2",
|
||||
"matrix-react-sdk": "^0.0.1",
|
||||
"matrix-js-sdk": "^0.3.0",
|
||||
"matrix-react-sdk": "^0.0.2",
|
||||
"q": "^1.4.1",
|
||||
"react": "^0.13.3",
|
||||
"react-loader": "^1.4.0"
|
||||
|
||||
@@ -49,15 +49,25 @@ module.exports = {
|
||||
|
||||
var position = {
|
||||
top: props.top - 20,
|
||||
right: props.right + 8,
|
||||
};
|
||||
|
||||
var chevron = null;
|
||||
if (props.left) {
|
||||
chevron = <img className="mx_ContextualMenu_chevron_left" src="img/chevron-left.png" width="9" height="16" />
|
||||
position.left = props.left + 8;
|
||||
} else {
|
||||
chevron = <img className="mx_ContextualMenu_chevron_right" src="img/chevron-right.png" width="9" height="16" />
|
||||
position.right = props.right + 8;
|
||||
}
|
||||
|
||||
var className = 'mx_ContextualMenu_wrapper';
|
||||
|
||||
// FIXME: If a menu uses getDefaultProps it clobbers the onFinished
|
||||
// property set here so you can't close the menu from a button click!
|
||||
var menu = (
|
||||
<div className="mx_ContextualMenu_wrapper">
|
||||
<div className={className}>
|
||||
<div className="mx_ContextualMenu" style={position}>
|
||||
<img className="mx_ContextualMenu_chevron" src="img/chevron-right.png" width="9" height="16" />
|
||||
{chevron}
|
||||
<Element {...props} onFinished={closeMenu}/>
|
||||
</div>
|
||||
<div className="mx_ContextualMenu_background" onClick={closeMenu}></div>
|
||||
|
||||
@@ -90,6 +90,7 @@ module.exports = {
|
||||
else {
|
||||
this.getVideoView().getLocalVideoElement().style.display = "none";
|
||||
this.getVideoView().getRemoteVideoElement().style.display = "none";
|
||||
dis.dispatch({action: 'video_fullscreen', fullscreen: false});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,6 +33,8 @@ module.exports = {
|
||||
cli.on("Room", this.onRoom);
|
||||
cli.on("Room.timeline", this.onRoomTimeline);
|
||||
cli.on("Room.name", this.onRoomName);
|
||||
cli.on("RoomState.events", this.onRoomStateEvents);
|
||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||
|
||||
var rooms = this.getRoomList();
|
||||
this.setState({
|
||||
@@ -66,6 +68,7 @@ module.exports = {
|
||||
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
||||
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -110,6 +113,15 @@ module.exports = {
|
||||
this.refreshRoomList();
|
||||
},
|
||||
|
||||
onRoomStateEvents: function(ev, state) {
|
||||
setTimeout(this.refreshRoomList, 0);
|
||||
},
|
||||
|
||||
onRoomMemberName: function(ev, member) {
|
||||
setTimeout(this.refreshRoomList, 0);
|
||||
},
|
||||
|
||||
|
||||
refreshRoomList: function() {
|
||||
var rooms = this.getRoomList();
|
||||
this.setState({
|
||||
|
||||
@@ -63,6 +63,7 @@ module.exports = {
|
||||
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping);
|
||||
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -356,23 +357,20 @@ module.exports = {
|
||||
},
|
||||
|
||||
getEventTiles: function() {
|
||||
var tileTypes = {
|
||||
'm.room.message': sdk.getComponent('molecules.MessageTile'),
|
||||
'm.room.member' : sdk.getComponent('molecules.EventAsTextTile'),
|
||||
'm.call.invite' : sdk.getComponent('molecules.EventAsTextTile'),
|
||||
'm.call.answer' : sdk.getComponent('molecules.EventAsTextTile'),
|
||||
'm.call.hangup' : sdk.getComponent('molecules.EventAsTextTile'),
|
||||
'm.room.topic' : sdk.getComponent('molecules.EventAsTextTile'),
|
||||
};
|
||||
|
||||
var DateSeparator = sdk.getComponent('molecules.DateSeparator');
|
||||
|
||||
var ret = [];
|
||||
var count = 0;
|
||||
|
||||
var EventTile = sdk.getComponent('molecules.EventTile');
|
||||
|
||||
for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) {
|
||||
var mxEv = this.state.room.timeline[i];
|
||||
var TileType = tileTypes[mxEv.getType()];
|
||||
|
||||
if (!EventTile.supportsEventType(mxEv.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var continuation = false;
|
||||
var last = false;
|
||||
var dateSeparator = null;
|
||||
@@ -401,13 +399,12 @@ module.exports = {
|
||||
|
||||
if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline
|
||||
var ts1 = this.state.room.timeline[i].getTs();
|
||||
dateSeparator = <DateSeparator key={ts1} ts={ts1}/>;
|
||||
dateSeparator = <li key={ts1}><DateSeparator ts={ts1}/></li>;
|
||||
continuation = false;
|
||||
}
|
||||
|
||||
if (!TileType) continue;
|
||||
ret.unshift(
|
||||
<li key={mxEv.getId()}><TileType mxEvent={mxEv} continuation={continuation} last={last}/></li>
|
||||
<li key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li>
|
||||
);
|
||||
if (dateSeparator) {
|
||||
ret.unshift(dateSeparator);
|
||||
|
||||
@@ -67,18 +67,29 @@ a:visited {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron {
|
||||
.mx_ContextualMenu_chevron_right {
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
right: -21px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_chevron_left {
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
left: -21px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_field {
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_spinner {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mx_Dialog_background {
|
||||
position: fixed;
|
||||
|
||||
@@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_MessageTile {
|
||||
.mx_EventTile {
|
||||
max-width: 100%;
|
||||
clear: both;
|
||||
margin-top: 32px;
|
||||
margin-left: 56px;
|
||||
}
|
||||
|
||||
.mx_MessageTile_avatar {
|
||||
.mx_EventTile_avatar {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
margin-left: -64px;
|
||||
@@ -29,17 +29,17 @@ limitations under the License.
|
||||
float: left;
|
||||
}
|
||||
|
||||
.mx_MessageTile_avatar img {
|
||||
.mx_EventTile_avatar img {
|
||||
background-color: #dbdbdb;
|
||||
border-radius: 20px;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.mx_MessageTile_continuation {
|
||||
.mx_EventTile_continuation {
|
||||
margin-top: 8px ! important;
|
||||
}
|
||||
|
||||
.mx_MessageTile .mx_SenderProfile {
|
||||
.mx_EventTile .mx_SenderProfile {
|
||||
color: #454545;
|
||||
opacity: 0.5;
|
||||
font-size: 14px;
|
||||
@@ -47,35 +47,35 @@ limitations under the License.
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mx_MessageTile .mx_MessageTimestamp {
|
||||
.mx_EventTile .mx_MessageTimestamp {
|
||||
color: #454545;
|
||||
opacity: 0.5;
|
||||
font-size: 14px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mx_MessageTile_content {
|
||||
.mx_EventTile_content {
|
||||
padding-right: 100px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mx_MessageTile_notice .mx_MessageTile_content {
|
||||
.mx_EventTile_notice .mx_MessageTile_content {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_MessageTile_sending {
|
||||
.mx_EventTile_sending {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.mx_MessageTile_notSent {
|
||||
.mx_EventTile_notSent {
|
||||
color: #f11;
|
||||
}
|
||||
|
||||
.mx_MessageTile_highlight {
|
||||
.mx_EventTile_highlight {
|
||||
color: #FF0064;
|
||||
}
|
||||
|
||||
.mx_MessageTile_msgOption {
|
||||
.mx_EventTile_msgOption {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -83,29 +83,30 @@ limitations under the License.
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_MessageTile_last .mx_MessageTimestamp {
|
||||
.mx_EventTile_last .mx_MessageTimestamp {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mx_MessageTile:hover .mx_MessageTimestamp {
|
||||
.mx_EventTile:hover .mx_MessageTimestamp {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mx_MessageTile_editButton {
|
||||
.mx_EventTile_editButton {
|
||||
float: right;
|
||||
display: none;
|
||||
border: 0px;
|
||||
outline: none;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.mx_MessageTile:hover .mx_MessageTile_editButton {
|
||||
.mx_EventTile:hover .mx_EventTile_editButton {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_MessageTile.menu .mx_MessageTile_editButton {
|
||||
.mx_EventTile.menu .mx_EventTile_editButton {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_MessageTile.menu .mx_MessageTimestamp {
|
||||
.mx_EventTile.menu .mx_MessageTimestamp {
|
||||
display: inline-block;
|
||||
}
|
||||
BIN
src/skins/vector/img/50e2c2.png
Normal file
BIN
src/skins/vector/img/50e2c2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 B |
BIN
src/skins/vector/img/80cef4.png
Normal file
BIN
src/skins/vector/img/80cef4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 B |
BIN
src/skins/vector/img/f4c371.png
Normal file
BIN
src/skins/vector/img/f4c371.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 B |
BIN
src/skins/vector/img/spinner.gif
Normal file
BIN
src/skins/vector/img/spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -41,6 +41,7 @@ skin['molecules.ChangeDisplayName'] = require('./views/molecules/ChangeDisplayNa
|
||||
skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword');
|
||||
skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator');
|
||||
skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile');
|
||||
skin['molecules.EventTile'] = require('./views/molecules/EventTile');
|
||||
skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar');
|
||||
skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo');
|
||||
skin['molecules.MemberTile'] = require('./views/molecules/MemberTile');
|
||||
|
||||
@@ -18,11 +18,8 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var ImageViewController = require('../../../../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() {
|
||||
|
||||
@@ -18,14 +18,11 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var MessageTimestampController = require('matrix-react-sdk/lib/controllers/atoms/MessageTimestamp')
|
||||
|
||||
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageTimestamp',
|
||||
mixins: [MessageTimestampController],
|
||||
|
||||
formatDate: function(date) {
|
||||
// date.toLocaleTimeString is completely system dependent.
|
||||
@@ -45,7 +42,7 @@ module.exports = React.createClass({
|
||||
return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
|
||||
}
|
||||
else {
|
||||
return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date().getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
|
||||
return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes());
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -24,10 +24,31 @@ module.exports = React.createClass({
|
||||
displayName: 'RoomAvatar',
|
||||
mixins: [RoomAvatarController],
|
||||
|
||||
getUrlList: function() {
|
||||
return [
|
||||
this.roomAvatarUrl(),
|
||||
this.getOneToOneAvatar(),
|
||||
this.getFallbackAvatar()
|
||||
];
|
||||
},
|
||||
|
||||
getFallbackAvatar: function() {
|
||||
var images = [ '80cef4', '50e2c2', 'f4c371' ];
|
||||
var total = 0;
|
||||
for (var i = 0; i < this.props.room.roomId.length; ++i) {
|
||||
total += this.props.room.roomId.charCodeAt(i);
|
||||
}
|
||||
return 'img/' + images[total % images.length] + '.png';
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var style = {
|
||||
maxWidth: this.props.width,
|
||||
maxHeight: this.props.height,
|
||||
};
|
||||
return (
|
||||
<img className="mx_RoomAvatar" src={this.state.imageUrl} onError={this.onError}
|
||||
width={this.props.width} height={this.props.height}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,5 +16,19 @@ limitations under the License.
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
};
|
||||
var React = require('react');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Spinner',
|
||||
|
||||
render: function() {
|
||||
var w = this.props.w || 32;
|
||||
var h = this.props.h || 32;
|
||||
var imgClass = this.props.imgClassName || "";
|
||||
return (
|
||||
<div>
|
||||
<img src="img/spinner.gif" width={w} height={h} className={imgClass}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -18,11 +18,8 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var VideoFeedController = require('matrix-react-sdk/lib/controllers/atoms/voip/VideoFeed')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'VideoFeed',
|
||||
mixins: [VideoFeedController],
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var ChangeAvatarController = require('matrix-react-sdk/lib/controllers/molecules/ChangeAvatar')
|
||||
|
||||
var Loader = require("react-loader");
|
||||
@@ -28,6 +29,7 @@ module.exports = React.createClass({
|
||||
mixins: [ChangeAvatarController],
|
||||
|
||||
onFileSelected: function(ev) {
|
||||
this.avatarSet = true;
|
||||
this.setAvatarFromFile(ev.target.files[0]);
|
||||
},
|
||||
|
||||
@@ -38,13 +40,27 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var RoomAvatar = sdk.getComponent('atoms.RoomAvatar');
|
||||
var avatarImg;
|
||||
// Having just set an avatar we just display that since it will take a little
|
||||
// time to propagate through to the RoomAvatar.
|
||||
if (this.props.room && !this.avatarSet) {
|
||||
avatarImg = <RoomAvatar room={this.props.room} width='320' height='240' resizeMethod='scale' />;
|
||||
} else {
|
||||
var style = {
|
||||
maxWidth: 320,
|
||||
maxHeight: 240,
|
||||
};
|
||||
avatarImg = <img src={this.state.avatarUrl} style={style} />;
|
||||
}
|
||||
|
||||
switch (this.state.phase) {
|
||||
case this.Phases.Display:
|
||||
case this.Phases.Error:
|
||||
return (
|
||||
<div>
|
||||
<div className="mx_Dialog_content">
|
||||
<img src={this.state.avatarUrl}/>
|
||||
{avatarImg}
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
Upload new:
|
||||
|
||||
@@ -18,37 +18,24 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var EventAsTextTileController = require('matrix-react-sdk/lib/controllers/molecules/EventAsTextTile')
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EventAsTextTile',
|
||||
mixins: [EventAsTextTileController],
|
||||
|
||||
statics: {
|
||||
needsSenderProfile: function() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp');
|
||||
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
|
||||
|
||||
var text = TextForEvent.textForEvent(this.props.mxEvent);
|
||||
if (text == null || text.length == 0) return null;
|
||||
|
||||
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />;
|
||||
var avatar = this.props.mxEvent.sender ? <MemberAvatar member={this.props.mxEvent.sender} /> : null;
|
||||
var cssStyles = "mx_MessageTile mx_MessageTile_notice";
|
||||
if (this.props.last) {
|
||||
cssStyles += " mx_MessageTile_last";
|
||||
}
|
||||
return (
|
||||
<div className={cssStyles}>
|
||||
<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 className="mx_EventAsTextTile">
|
||||
{TextForEvent.textForEvent(this.props.mxEvent)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
131
src/skins/vector/views/molecules/EventTile.js
Normal file
131
src/skins/vector/views/molecules/EventTile.js
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
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 sdk = require('matrix-react-sdk')
|
||||
|
||||
var EventTileController = require('matrix-react-sdk/lib/controllers/molecules/EventTile')
|
||||
var ContextualMenu = require('../../../../ContextualMenu');
|
||||
|
||||
var eventTileTypes = {
|
||||
'm.room.message': 'molecules.MessageTile',
|
||||
'm.room.member' : 'molecules.EventAsTextTile',
|
||||
'm.call.invite' : 'molecules.EventAsTextTile',
|
||||
'm.call.answer' : 'molecules.EventAsTextTile',
|
||||
'm.call.hangup' : 'molecules.EventAsTextTile',
|
||||
'm.room.topic' : 'molecules.EventAsTextTile',
|
||||
};
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EventTile',
|
||||
mixins: [EventTileController],
|
||||
|
||||
statics: {
|
||||
supportsEventType: function(et) {
|
||||
return eventTileTypes[et] !== undefined;
|
||||
}
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {menu: false};
|
||||
},
|
||||
|
||||
onEditClicked: function(e) {
|
||||
var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu');
|
||||
var buttonRect = e.target.getBoundingClientRect()
|
||||
var x = buttonRect.right;
|
||||
var y = buttonRect.top + (e.target.height / 2);
|
||||
var self = this;
|
||||
ContextualMenu.createMenu(MessageContextMenu, {
|
||||
mxEvent: this.props.mxEvent,
|
||||
left: x,
|
||||
top: y,
|
||||
onFinished: function() {
|
||||
self.setState({menu: false});
|
||||
}
|
||||
});
|
||||
this.setState({menu: true});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp');
|
||||
var SenderProfile = sdk.getComponent('molecules.SenderProfile');
|
||||
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
|
||||
|
||||
var content = this.props.mxEvent.getContent();
|
||||
var msgtype = content.msgtype;
|
||||
|
||||
var EventTileType = sdk.getComponent(eventTileTypes[this.props.mxEvent.getType()]);
|
||||
// This shouldn't happen: the caller should check we support this type
|
||||
// before trying to instantiate us
|
||||
if (!EventTileType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var classes = classNames({
|
||||
mx_EventTile: true,
|
||||
mx_EventTile_sending: ['sending', 'queued'].indexOf(
|
||||
this.props.mxEvent.status
|
||||
) !== -1,
|
||||
mx_EventTile_notSent: this.props.mxEvent.status == 'not_sent',
|
||||
mx_EventTile_highlight: this.shouldHighlight(),
|
||||
mx_EventTile_continuation: this.props.continuation,
|
||||
mx_EventTile_last: this.props.last,
|
||||
menu: this.state.menu
|
||||
});
|
||||
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
|
||||
var editButton = (
|
||||
<input
|
||||
type="image" src="img/edit.png" alt="Edit"
|
||||
className="mx_EventTile_editButton" onClick={this.onEditClicked}
|
||||
/>
|
||||
);
|
||||
|
||||
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;
|
||||
if (!this.props.continuation) {
|
||||
if (this.props.mxEvent.sender) {
|
||||
avatar = (
|
||||
<div className="mx_EventTile_avatar">
|
||||
<MemberAvatar member={this.props.mxEvent.sender} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (EventTileType.needsSenderProfile()) {
|
||||
sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className={classes}>
|
||||
{ avatar }
|
||||
{ sender }
|
||||
<div>
|
||||
{ timestamp }
|
||||
{ editButton }
|
||||
<EventTileType mxEvent={this.props.mxEvent} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -19,15 +19,12 @@ limitations under the License.
|
||||
var React = require('react');
|
||||
var filesize = require('filesize');
|
||||
|
||||
var MImageTileController = require('matrix-react-sdk/lib/controllers/molecules/MImageTile')
|
||||
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
var sdk = require('matrix-react-sdk')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MImageTile',
|
||||
mixins: [MImageTileController],
|
||||
|
||||
thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
|
||||
if (!fullWidth || !fullHeight) {
|
||||
|
||||
@@ -18,14 +18,11 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var MRoomMemberTileController = require('matrix-react-sdk/lib/controllers/molecules/MRoomMemberTile')
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MRoomMemberTile',
|
||||
mixins: [MRoomMemberTileController],
|
||||
|
||||
getMemberEventText: function() {
|
||||
return TextForEvent.textForEvent(this.props.mxEvent);
|
||||
|
||||
@@ -20,11 +20,8 @@ var React = require('react');
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
|
||||
var MatrixToolbarController = require('matrix-react-sdk/lib/controllers/molecules/MatrixToolbar')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MatrixToolbar',
|
||||
mixins: [MatrixToolbarController],
|
||||
|
||||
hideToolbar: function() {
|
||||
var Notifier = sdk.getComponent('organisms.Notifier');
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var Loader = require("../atoms/Spinner");
|
||||
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var MemberInfoController = require('matrix-react-sdk/lib/controllers/molecules/MemberInfo')
|
||||
@@ -26,7 +27,7 @@ module.exports = React.createClass({
|
||||
mixins: [MemberInfoController],
|
||||
|
||||
render: function() {
|
||||
var interactButton, kickButton, banButton, muteButton, giveModButton;
|
||||
var interactButton, kickButton, banButton, muteButton, giveModButton, spinner;
|
||||
if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
|
||||
interactButton = <div className="mx_ContextualMenu_field" onClick={this.onLeaveClick}>Leave room</div>;
|
||||
}
|
||||
@@ -34,6 +35,10 @@ module.exports = React.createClass({
|
||||
interactButton = <div className="mx_ContextualMenu_field" onClick={this.onChatClick}>Start chat</div>;
|
||||
}
|
||||
|
||||
if (this.state.creatingRoom) {
|
||||
spinner = <Loader imgClassName="mx_ContextualMenu_spinner"/>;
|
||||
}
|
||||
|
||||
if (this.state.can.kick) {
|
||||
kickButton = <div className="mx_ContextualMenu_field" onClick={this.onKick}>
|
||||
Kick
|
||||
@@ -64,6 +69,7 @@ module.exports = React.createClass({
|
||||
{kickButton}
|
||||
{banButton}
|
||||
{giveModButton}
|
||||
{spinner}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,9 +52,27 @@ module.exports = React.createClass({
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
onRedactClick: function() {
|
||||
MatrixClientPeg.get().redactEvent(
|
||||
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
|
||||
).done(function() {
|
||||
// message should disappear by itself
|
||||
}, function(e) {
|
||||
var ErrorDialog = sdk.getComponent("organisms.ErrorDialog");
|
||||
// display error message stating you couldn't delete this.
|
||||
var code = e.errcode || e.statusCode;
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Error",
|
||||
description: "You cannot delete this message. (" + code + ")"
|
||||
});
|
||||
});
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var resendButton;
|
||||
var viewSourceButton;
|
||||
var redactButton;
|
||||
|
||||
if (this.props.mxEvent.status == 'not_sent') {
|
||||
resendButton = (
|
||||
@@ -63,6 +81,13 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
redactButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onRedactClick}>
|
||||
Delete
|
||||
</div>
|
||||
);
|
||||
}
|
||||
viewSourceButton = (
|
||||
<div className="mx_ContextualMenu_field" onClick={this.onViewSourceClick}>
|
||||
View Source
|
||||
@@ -72,6 +97,7 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
{resendButton}
|
||||
{redactButton}
|
||||
{viewSourceButton}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -17,39 +17,22 @@ limitations under the License.
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var classNames = require("classnames");
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
|
||||
var MessageTileController = require('matrix-react-sdk/lib/controllers/molecules/MessageTile')
|
||||
var ContextualMenu = require('../../../../ContextualMenu');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MessageTile',
|
||||
mixins: [MessageTileController],
|
||||
|
||||
onEditClicked: function(e) {
|
||||
var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu');
|
||||
var buttonRect = e.target.getBoundingClientRect()
|
||||
var x = window.innerWidth - buttonRect.left;
|
||||
var y = buttonRect.top + (e.target.height / 2);
|
||||
var self = this;
|
||||
ContextualMenu.createMenu(MessageContextMenu, {
|
||||
mxEvent: this.props.mxEvent,
|
||||
right: x,
|
||||
top: y,
|
||||
onFinished: function() {
|
||||
self.setState({menu: false});
|
||||
}
|
||||
});
|
||||
this.setState({menu: true});
|
||||
statics: {
|
||||
needsSenderProfile: function() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp');
|
||||
var SenderProfile = sdk.getComponent('molecules.SenderProfile');
|
||||
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
|
||||
|
||||
var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile');
|
||||
|
||||
var tileTypes = {
|
||||
@@ -66,56 +49,7 @@ module.exports = React.createClass({
|
||||
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,
|
||||
menu: this.state.menu
|
||||
});
|
||||
var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} />
|
||||
var editButton = (
|
||||
<input
|
||||
type="image" src="img/edit.png" alt="Edit"
|
||||
className="mx_MessageTile_editButton" onClick={this.onEditClicked}
|
||||
/>
|
||||
);
|
||||
|
||||
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 }
|
||||
{ sender }
|
||||
<div>
|
||||
{ timestamp }
|
||||
{ editButton }
|
||||
<TileType mxEvent={this.props.mxEvent} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <TileType mxEvent={this.props.mxEvent} />;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
onFullscreenClick: function() {
|
||||
dis.dispatch({action: 'video_fullscreen'}, true);
|
||||
dis.dispatch({action: 'video_fullscreen', fullscreen: true}, true);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -61,7 +61,7 @@ module.exports = React.createClass({
|
||||
var call_buttons;
|
||||
var zoom_button;
|
||||
if (this.state && this.state.call_state != 'ended') {
|
||||
var muteVideoButton;
|
||||
//var muteVideoButton;
|
||||
var activeCall = (
|
||||
CallHandler.getCallForRoom(this.props.room.roomId)
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
|
||||
var sdk = require('matrix-react-sdk');
|
||||
|
||||
var RoomSettingsController = require('matrix-react-sdk/lib/controllers/molecules/RoomSettings')
|
||||
|
||||
@@ -65,6 +66,8 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar');
|
||||
|
||||
var topic = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
||||
if (topic) topic = topic.getContent().topic;
|
||||
|
||||
@@ -76,6 +79,8 @@ module.exports = React.createClass({
|
||||
|
||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
|
||||
var events_levels = power_levels.events || {};
|
||||
|
||||
if (power_levels) {
|
||||
power_levels = power_levels.getContent();
|
||||
|
||||
@@ -91,8 +96,7 @@ module.exports = React.createClass({
|
||||
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_levels = power_levels.users || {};
|
||||
|
||||
var user_id = MatrixClientPeg.get().credentials.userId;
|
||||
|
||||
@@ -124,7 +128,21 @@ module.exports = React.createClass({
|
||||
var can_change_levels = false;
|
||||
}
|
||||
|
||||
var banned = this.props.room.getMembersWithMemership("ban");
|
||||
var room_avatar_level = parseInt(power_levels.state_default || 0);
|
||||
if (events_levels['m.room.avatar'] !== undefined) {
|
||||
room_avatar_level = events_levels['m.room.avatar'];
|
||||
}
|
||||
var can_set_room_avatar = current_user_level >= room_avatar_level;
|
||||
|
||||
var change_avatar;
|
||||
if (can_set_room_avatar) {
|
||||
change_avatar = <div>
|
||||
<h3>Room Icon</h3>
|
||||
<ChangeAvatar room={this.props.room} />
|
||||
</div>;
|
||||
}
|
||||
|
||||
var banned = this.props.room.getMembersWithMembership("ban");
|
||||
|
||||
return (
|
||||
<div className="mx_RoomSettings">
|
||||
@@ -207,6 +225,7 @@ module.exports = React.createClass({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{change_avatar}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,15 +19,12 @@ limitations under the License.
|
||||
var React = require('react');
|
||||
var classNames = require("classnames");
|
||||
|
||||
var SenderProfileController = require('matrix-react-sdk/lib/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;
|
||||
|
||||
@@ -18,11 +18,8 @@ limitations under the License.
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var UnknownMessageTileController = require('matrix-react-sdk/lib/controllers/molecules/UnknownMessageTile')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UnknownMessageTile',
|
||||
mixins: [UnknownMessageTileController],
|
||||
|
||||
render: function() {
|
||||
var content = this.props.mxEvent.getContent();
|
||||
|
||||
@@ -31,24 +31,28 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
// NB: This block MUST have a "key" so React doesn't clobber the elements
|
||||
// between in-call / not-in-call.
|
||||
var audioBlock = (
|
||||
<audio ref="ringAudio" key="voip_ring_audio" loop>
|
||||
<source src="media/ring.ogg" type="audio/ogg" />
|
||||
<source src="media/ring.mp3" type="audio/mpeg" />
|
||||
</audio>
|
||||
);
|
||||
|
||||
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>
|
||||
{audioBlock}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name;
|
||||
return (
|
||||
<div className="mx_IncomingCallBox">
|
||||
{audioBlock}
|
||||
<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>
|
||||
|
||||
@@ -20,11 +20,9 @@ var React = require('react');
|
||||
|
||||
var sdk = require('matrix-react-sdk')
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher')
|
||||
var VideoViewController = require('matrix-react-sdk/lib/controllers/molecules/voip/VideoView')
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'VideoView',
|
||||
mixins: [VideoViewController],
|
||||
|
||||
componentWillMount: function() {
|
||||
dis.register(this.onAction);
|
||||
@@ -53,8 +51,26 @@ module.exports = React.createClass({
|
||||
return;
|
||||
}
|
||||
var element = this.container.getDOMNode();
|
||||
var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullscreen;
|
||||
requestMethod.call(element);
|
||||
if (payload.fullscreen) {
|
||||
var requestMethod = (
|
||||
element.requestFullScreen ||
|
||||
element.webkitRequestFullScreen ||
|
||||
element.mozRequestFullScreen ||
|
||||
element.msRequestFullscreen
|
||||
);
|
||||
requestMethod.call(element);
|
||||
}
|
||||
else {
|
||||
var exitMethod = (
|
||||
document.exitFullscreen ||
|
||||
document.mozCancelFullScreen ||
|
||||
document.webkitExitFullscreen ||
|
||||
document.msExitFullscreen
|
||||
);
|
||||
if (exitMethod) {
|
||||
exitMethod.call(document);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -58,15 +58,16 @@ var NotifierView = {
|
||||
if (ev.getContent().body) msg = ev.getContent().body;
|
||||
}
|
||||
|
||||
var avatarUrl = Avatar.avatarUrlForMember(
|
||||
var avatarUrl = ev.sender ? Avatar.avatarUrlForMember(
|
||||
ev.sender, 40, 40, 'crop'
|
||||
);
|
||||
) : null;
|
||||
|
||||
var notification = new global.Notification(
|
||||
title,
|
||||
{
|
||||
"body": msg,
|
||||
"icon": avatarUrl
|
||||
"icon": avatarUrl,
|
||||
"tag": "vector"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -149,6 +149,11 @@ module.exports = React.createClass({
|
||||
var innerProgressStyle = {
|
||||
width: ((this.state.upload.uploadedBytes / this.state.upload.totalBytes) * 100) + '%'
|
||||
};
|
||||
var uploadedSize = filesize(this.state.upload.uploadedBytes);
|
||||
var totalSize = filesize(this.state.upload.totalBytes);
|
||||
if (uploadedSize.replace(/^.* /,'') === totalSize.replace(/^.* /,'')) {
|
||||
uploadedSize = uploadedSize.replace(/ .*/, '');
|
||||
}
|
||||
statusBar = (
|
||||
<div className="mx_RoomView_uploadBar">
|
||||
<div className="mx_RoomView_uploadProgressOuter">
|
||||
@@ -157,7 +162,7 @@ module.exports = React.createClass({
|
||||
<img className="mx_RoomView_uploadIcon" src="img/fileicon.png" width="40" height="40"/>
|
||||
<img className="mx_RoomView_uploadCancel" src="img/cancel.png" width="40" height="40"/>
|
||||
<div className="mx_RoomView_uploadBytes">
|
||||
{filesize(this.state.upload.uploadedBytes).replace(/ .*/, '')} / {filesize(this.state.upload.totalBytes)}
|
||||
{ uploadedSize } / { totalSize }
|
||||
</div>
|
||||
<div className="mx_RoomView_uploadFilename">Uploading {this.state.upload.fileName}</div>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,8 @@ var MatrixChatController = require('matrix-react-sdk/lib/controllers/pages/Matri
|
||||
var Loader = require("react-loader");
|
||||
|
||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||
|
||||
var Matrix = require("matrix-js-sdk");
|
||||
var ContextualMenu = require("../../../../ContextualMenu");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MatrixChat',
|
||||
@@ -46,6 +47,22 @@ module.exports = React.createClass({
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
},
|
||||
|
||||
onAliasClick: function(event, alias) {
|
||||
event.preventDefault();
|
||||
dis.dispatch({action: 'view_room_alias', room_alias: alias});
|
||||
},
|
||||
|
||||
onUserClick: function(event, userId) {
|
||||
event.preventDefault();
|
||||
var MemberInfo = sdk.getComponent('molecules.MemberInfo');
|
||||
var member = new Matrix.RoomMember(null, userId);
|
||||
ContextualMenu.createMenu(MemberInfo, {
|
||||
member: member,
|
||||
right: window.innerWidth - event.pageX,
|
||||
top: event.pageY
|
||||
});
|
||||
},
|
||||
|
||||
handleResize: function(e) {
|
||||
var hideLhsThreshold = 1000;
|
||||
var showLhsThreshold = 1000;
|
||||
|
||||
@@ -25,10 +25,9 @@ var Loader = require("react-loader");
|
||||
|
||||
var RegisterController = require('../../../../controllers/templates/Register')
|
||||
|
||||
module.exports = React.createClass({
|
||||
DEFAULT_HS_URL: 'https://matrix.org',
|
||||
DEFAULT_IS_URL: 'https://vector.im',
|
||||
var config = require('../../../../../config.json');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Register',
|
||||
mixins: [RegisterController],
|
||||
|
||||
@@ -39,8 +38,8 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.customHsUrl = this.DEFAULT_HS_URL;
|
||||
this.customIsUrl = this.DEFAULT_IS_URL;
|
||||
this.customHsUrl = config.default_hs_url;
|
||||
this.customIsUrl = config.default_is_url;
|
||||
},
|
||||
|
||||
getRegFormVals: function() {
|
||||
@@ -56,7 +55,7 @@ module.exports = React.createClass({
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customHsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_HS_URL;
|
||||
return config.default_hs_url;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -64,7 +63,7 @@ module.exports = React.createClass({
|
||||
if (this.state.serverConfigVisible) {
|
||||
return this.customIsUrl;
|
||||
} else {
|
||||
return this.DEFAULT_IS_URL;
|
||||
return config.default_is_url;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -173,6 +172,12 @@ module.exports = React.createClass({
|
||||
case this.FieldErrors.InUse:
|
||||
strings.push(keys[i]+" is already taken");
|
||||
break;
|
||||
case this.FieldErrors.Length:
|
||||
strings.push(keys[i] + " is not long enough.");
|
||||
break;
|
||||
default:
|
||||
console.error("Unhandled FieldError: %s", bad[keys[i]]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
var errtxt = strings.join(', ');
|
||||
|
||||
@@ -20,7 +20,8 @@ module.exports = {
|
||||
// removed which gives a tree with matrix-react-sdk and vector
|
||||
// trees smashed together, but this fixes everything being under
|
||||
// various levels of '.' and '..'
|
||||
return info.resourcePath.replace(/^[\/\.]*/, '');
|
||||
// Also, sometimes the resource path is absolute.
|
||||
return path.relative(process.cwd(), info.resourcePath).replace(/^[\/\.]*/, '');
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
|
||||
Reference in New Issue
Block a user