Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4507117f89 | ||
|
|
cad48b62e4 | ||
|
|
5138dc9fd8 | ||
|
|
c12a77bc15 | ||
|
|
695b5d950c | ||
|
|
17b2d14ffc | ||
|
|
752f8363a7 | ||
|
|
a3a4ff569e | ||
|
|
948b862c31 | ||
|
|
27ab79fd38 | ||
|
|
8cbc8db1cb | ||
|
|
e32299a50c | ||
|
|
c843ee3157 | ||
|
|
490cbbd05f | ||
|
|
e4aa43944f | ||
|
|
827f891ae7 | ||
|
|
54c34ab8d5 | ||
|
|
3339fa2a39 | ||
|
|
d4a36f5081 | ||
|
|
19cb06d040 | ||
|
|
a5e0aa763b | ||
|
|
a1e3cf76e1 | ||
|
|
866bd55bc3 | ||
|
|
a6257a1148 | ||
|
|
92e187da64 | ||
|
|
f950b675bd | ||
|
|
aca4457a89 | ||
|
|
725b9a6619 | ||
|
|
d7a851a353 | ||
|
|
c6f95dfb3b | ||
|
|
4164688c24 | ||
|
|
cddfa62e27 | ||
|
|
a6e3b39f16 | ||
|
|
f8fb3a7fe1 | ||
|
|
50d18ac771 | ||
|
|
1e0c4d8797 | ||
|
|
05e479a76c | ||
|
|
fe9816abf5 | ||
|
|
29815b1d13 | ||
|
|
cb45db36c2 | ||
|
|
31915db6f6 | ||
|
|
eb01cb9cba | ||
|
|
2a8afd49fb | ||
|
|
9b85d88036 | ||
|
|
c2049e991b | ||
|
|
3224a4e49e | ||
|
|
cfc4b89225 | ||
|
|
8b1444c954 | ||
|
|
d4d2ef326e | ||
|
|
2a62fdb652 | ||
|
|
6215326f8e | ||
|
|
da7e9840f3 | ||
|
|
cc18458bec | ||
|
|
928915873b | ||
|
|
3b2d0a6c01 | ||
|
|
731d94eea4 |
78
CHANGELOG.md
Normal file
78
CHANGELOG.md
Normal file
@@ -0,0 +1,78 @@
|
||||
Changes in [0.4.1](https://github.com/vector-im/vector-web/releases/tag/v0.4.1) (2016-03-23)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.4.0...v0.4.1)
|
||||
* Update to matrix-react-sdk 0.3.1; see
|
||||
https://github.com/matrix-org/matrix-react-sdk/blob/v0.3.1/CHANGELOG.md
|
||||
(Disables debug logging)
|
||||
|
||||
Changes in [0.4.0](https://github.com/vector-im/vector-web/releases/tag/v0.4.0) (2016-03-23)
|
||||
============================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.3.0...v0.4.0)
|
||||
|
||||
* Update to matrix-react-sdk 0.3.0; see
|
||||
https://github.com/matrix-org/matrix-react-sdk/blob/master/CHANGELOG.md
|
||||
|
||||
Other changes
|
||||
* permalink button
|
||||
[\#1232](https://github.com/vector-im/vector-web/pull/1232)
|
||||
* make senderprofiles clickable
|
||||
[\#1191](https://github.com/vector-im/vector-web/pull/1191)
|
||||
* fix notif spam when logging in from a guest session by correctly logging out
|
||||
first.
|
||||
[\#1180](https://github.com/vector-im/vector-web/pull/1180)
|
||||
* use new start_login_from_guest dispatch for cancellable logins from guest
|
||||
accounts
|
||||
[\#1165](https://github.com/vector-im/vector-web/pull/1165)
|
||||
* Use then() chaining rather than manual callbacks
|
||||
[\#1171](https://github.com/vector-im/vector-web/pull/1171)
|
||||
* Remove trailing whitespace
|
||||
[\#1163](https://github.com/vector-im/vector-web/pull/1163)
|
||||
* Update the actions of default rules instead of overriding.
|
||||
[\#1037](https://github.com/vector-im/vector-web/pull/1037)
|
||||
* Update README to include `npm install` in react-sdk
|
||||
[\#1137](https://github.com/vector-im/vector-web/pull/1137)
|
||||
|
||||
Changes in vector v0.3.0 (2016-03-11)
|
||||
======================================
|
||||
* Lots of new bug fixes and updates
|
||||
|
||||
Changes in vector v0.2.0 (2016-02-24)
|
||||
======================================
|
||||
* Refactor of matrix-react-sdk and vector to remove separation between views and
|
||||
controllers
|
||||
* Temporarily break the layering abstraction between vector and matrix-react-sdk
|
||||
for expedience in developing vector.
|
||||
* Vast numbers of new features, including read receipts, read-up-to markers,
|
||||
updated look and feel, search, new room and user settings, and email invites.
|
||||
|
||||
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)
|
||||
======================================
|
||||
|
||||
* Support logging in with an email address
|
||||
* Use the Vector identity server
|
||||
* Fix a bug where the client was not stopped properly on logout
|
||||
* Fix bugs where field values would be forgotten if login or registration failed
|
||||
* Improve URL bar navigation
|
||||
* Add explanatory help text on advanced server options
|
||||
* Fix a bug which caused execptions on malformed VoIP invitations
|
||||
* Remove superfluous scrollbars on Firefox
|
||||
* Numerous CSS fixes
|
||||
* Improved accessibility
|
||||
* Support command-click / middle click to open image in a new tab
|
||||
* Improved room directory
|
||||
* Fix display of text with many combining unicode points
|
||||
|
||||
Changes in vector v0.1.0 (2015-08-10)
|
||||
======================================
|
||||
Initial release
|
||||
44
CHANGES.rst
44
CHANGES.rst
@@ -1,44 +0,0 @@
|
||||
Changes in vector v0.3.0 (2016-03-11)
|
||||
======================================
|
||||
* Lots of new bug fixes and updates
|
||||
|
||||
Changes in vector v0.2.0 (2016-02-24)
|
||||
======================================
|
||||
* Refactor of matrix-react-sdk and vector to remove separation between views and
|
||||
controllers
|
||||
* Temporarily break the layering abstraction between vector and matrix-react-sdk
|
||||
for expedience in developing vector.
|
||||
* Vast numbers of new features, including read receipts, read-up-to markers,
|
||||
updated look and feel, search, new room and user settings, and email invites.
|
||||
|
||||
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)
|
||||
======================================
|
||||
|
||||
* Support logging in with an email address
|
||||
* Use the Vector identity server
|
||||
* Fix a bug where the client was not stopped properly on logout
|
||||
* Fix bugs where field values would be forgotten if login or registration failed
|
||||
* Improve URL bar navigation
|
||||
* Add explanatory help text on advanced server options
|
||||
* Fix a bug which caused execptions on malformed VoIP invitations
|
||||
* Remove superfluous scrollbars on Firefox
|
||||
* Numerous CSS fixes
|
||||
* Improved accessibility
|
||||
* Support command-click / middle click to open image in a new tab
|
||||
* Improved room directory
|
||||
* Fix display of text with many combining unicode points
|
||||
|
||||
Changes in vector v0.1.0 (2015-08-10)
|
||||
======================================
|
||||
Initial release
|
||||
16
README.md
16
README.md
@@ -10,6 +10,9 @@ Getting started
|
||||
1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
|
||||
1. Switch to the vector directory: `cd vector-web`
|
||||
1. Install the prerequisites: `npm install`
|
||||
1. If you are using the `develop` branch of vector, you will probably need to
|
||||
rebuild one of the dependencies, due to https://github.com/npm/npm/issues/3055:
|
||||
`(cd node_modules/matrix-react-sdk && npm install)`
|
||||
1. Start the development builder and a testing server: `npm start`
|
||||
1. Wait a few seconds for the initial build to finish (the command won't
|
||||
terminate: it's running a web server for you).
|
||||
@@ -48,14 +51,13 @@ webserver to actually serve up the app, which is entirely static content.
|
||||
Development
|
||||
===========
|
||||
|
||||
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.
|
||||
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 can't be installed automatically due to https://github.com/npm/npm/issues/3055.
|
||||
To get the right dependencies, check out the `develop` branches of these libraries and
|
||||
then use `ln -s` to tell Vector about them:
|
||||
However, much of the functionality in Vector is actually in the
|
||||
`matrix-react-sdk` and `matrix-js-sdk` modules. It is possible to set these up
|
||||
in a way that makes it easy to track the `develop` branches in git and to make
|
||||
local changes without having to manually rebuild each time.
|
||||
|
||||
[Be aware that there may be problems with this process under npm version 3.]
|
||||
|
||||
|
||||
17
jenkins.sh
17
jenkins.sh
@@ -8,20 +8,23 @@ nvm use 4
|
||||
|
||||
set -x
|
||||
|
||||
# install the versions of js-sdk and react-sdk provided to us by jenkins
|
||||
npm install ./node_modules/matrix-js-sdk-*.tgz
|
||||
npm install ./node_modules/matrix-react-sdk-*.tgz
|
||||
|
||||
# install the other dependencies
|
||||
npm install
|
||||
|
||||
# we may be using a dev branch of react-sdk, in which case we need to build it
|
||||
(cd node_modules/matrix-react-sdk && npm run build)
|
||||
|
||||
# build our artifacts; dumps them in ./vector
|
||||
npm run build
|
||||
|
||||
# gzip up ./vector
|
||||
rm vector-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist
|
||||
|
||||
REACT_SHA=$(head -c 12 node_modules/matrix-react-sdk/git-revision.txt)
|
||||
JSSDK_SHA=$(head -c 12 node_modules/matrix-js-sdk/git-revision.txt)
|
||||
# node_modules deps from 'npm install' don't have a .git dir so can't
|
||||
# rev-parse; but they do set the commit in package.json under 'gitHead' which
|
||||
# we're grabbing here.
|
||||
REACT_SHA=$(grep 'gitHead' node_modules/matrix-react-sdk/package.json | cut -d \" -f 4 | head -c 12)
|
||||
JSSDK_SHA=$(grep 'gitHead' node_modules/matrix-js-sdk/package.json | cut -d \" -f 4 | head -c 12)
|
||||
|
||||
VECTOR_SHA=$(git rev-parse --short=12 HEAD) # use the ACTUAL SHA rather than assume develop
|
||||
|
||||
tar -zcvhf vector-$VECTOR_SHA-react-$REACT_SHA-js-$JSSDK_SHA.tar.gz vector #g[z]ip, [c]reate archive, [v]erbose, [f]ilename, [h]ard-dereference (do not archive symlinks)
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vector-web",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.1",
|
||||
"description": "Vector webapp",
|
||||
"author": "matrix.org",
|
||||
"repository": {
|
||||
@@ -33,19 +33,19 @@
|
||||
"extract-text-webpack-plugin": "^0.9.1",
|
||||
"filesize": "^3.1.2",
|
||||
"flux": "~2.0.3",
|
||||
"gemini-scrollbar": "^1.3.0",
|
||||
"gemini-scrollbar": "matrix-org/gemini-scrollbar#7dc736d",
|
||||
"gfm.css": "^1.1.1",
|
||||
"highlight.js": "^9.0.0",
|
||||
"linkifyjs": "^2.0.0-beta.4",
|
||||
"matrix-js-sdk": "^0.4.1",
|
||||
"matrix-react-sdk": "^0.2.0",
|
||||
"matrix-js-sdk": "^0.5.0",
|
||||
"matrix-react-sdk": "^0.3.1",
|
||||
"modernizr": "^3.1.0",
|
||||
"q": "^1.4.1",
|
||||
"react": "^0.14.2",
|
||||
"react-dnd": "^2.0.2",
|
||||
"react-dnd-html5-backend": "^2.0.0",
|
||||
"react-dom": "^0.14.2",
|
||||
"react-gemini-scrollbar": "^2.0.1",
|
||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#869a86b",
|
||||
"sanitize-html": "^1.11.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
12
release.sh
Executable file
12
release.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to perform a release of vector-web.
|
||||
#
|
||||
# Requires github-changelog-generator; to install, do
|
||||
# pip install git+https://github.com/matrix-org/github-changelog-generator.git
|
||||
|
||||
set -e
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
exec ./node_modules/matrix-js-sdk/release.sh -z "$@"
|
||||
@@ -40,7 +40,7 @@ var LeftPanel = React.createClass({
|
||||
|
||||
componentWillReceiveProps: function(newProps) {
|
||||
this._recheckCallElement(newProps.selectedRoom);
|
||||
},
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
@@ -95,7 +95,7 @@ var LeftPanel = React.createClass({
|
||||
}
|
||||
else {
|
||||
// Hide the collapse button until we work out how to display it in the new skin
|
||||
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
|
||||
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
|
||||
}
|
||||
|
||||
var callPreview;
|
||||
|
||||
@@ -38,7 +38,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
|
||||
}
|
||||
@@ -82,6 +82,9 @@ module.exports = React.createClass({
|
||||
|
||||
onAction: function(payload) {
|
||||
if (payload.action === "view_user") {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
if (payload.member) {
|
||||
this.setState({
|
||||
phase: this.Phase.MemberInfo,
|
||||
|
||||
@@ -47,7 +47,7 @@ module.exports = React.createClass({
|
||||
var self = this;
|
||||
MatrixClientPeg.get().publicRooms(function (err, data) {
|
||||
if (err) {
|
||||
self.setState({ loading: false });
|
||||
self.setState({ loading: false });
|
||||
console.error("Failed to get publicRooms: %s", JSON.stringify(err));
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
@@ -83,7 +83,7 @@ module.exports = React.createClass({
|
||||
avatarUrl: room.avatar_url,
|
||||
// XXX: This logic is duplicated from the JS SDK which
|
||||
// would normally decide what the name is.
|
||||
name: room.name || room.aliases[0],
|
||||
name: room.name || room.canonical_alias || (room.aliases ? room.aliases[0] : "Unnamed room"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -102,7 +102,9 @@ module.exports = React.createClass({
|
||||
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].toLowerCase().search(filter.toLowerCase()) >= 0 && a.num_joined_members > 0);
|
||||
return (((a.name && a.name.toLowerCase().search(filter.toLowerCase()) >= 0) ||
|
||||
(a.aliases && a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0)) &&
|
||||
a.num_joined_members > 0);
|
||||
}).sort(function(a,b) {
|
||||
return a.num_joined_members - b.num_joined_members;
|
||||
});
|
||||
@@ -110,7 +112,8 @@ module.exports = React.createClass({
|
||||
var self = this;
|
||||
var guestRead, guestJoin, perms;
|
||||
for (var i = 0; i < rooms.length; i++) {
|
||||
var name = rooms[i].name || rooms[i].aliases[0];
|
||||
var alias = rooms[i].canonical_alias || (rooms[i].aliases ? rooms[i].aliases[0] : "");
|
||||
var name = rooms[i].name || alias || "Unnamed room";
|
||||
guestRead = null;
|
||||
guestJoin = null;
|
||||
|
||||
@@ -124,7 +127,7 @@ module.exports = React.createClass({
|
||||
<div className="mx_RoomDirectory_perm">Guests can join</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
perms = null;
|
||||
if (guestRead || guestJoin) {
|
||||
perms = <div className="mx_RoomDirectory_perms">{guestRead} {guestJoin}</div>;
|
||||
@@ -148,7 +151,7 @@ module.exports = React.createClass({
|
||||
<div className="mx_RoomDirectory_topic"
|
||||
onClick={ function(e) { e.stopPropagation() } }
|
||||
dangerouslySetInnerHTML={{ __html: topic }}/>
|
||||
<div className="mx_RoomDirectory_alias">{ rooms[i].aliases[0] }</div>
|
||||
<div className="mx_RoomDirectory_alias">{ alias }</div>
|
||||
</td>
|
||||
<td className="mx_RoomDirectory_roomMemberCount">
|
||||
{ rooms[i].num_joined_members }
|
||||
@@ -169,7 +172,7 @@ module.exports = React.createClass({
|
||||
|
||||
render: function() {
|
||||
if (this.state.loading) {
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
return (
|
||||
<div className="mx_RoomDirectory">
|
||||
<Loader />
|
||||
|
||||
@@ -187,15 +187,15 @@ var RoomSubList = React.createClass({
|
||||
var rooms = this.state.sortedList;
|
||||
if (found.room) {
|
||||
rooms.splice(found.index, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn("Can't remove room " + room.roomId + " - can't find it");
|
||||
}
|
||||
this.setState({ sortedList: rooms });
|
||||
},
|
||||
|
||||
findRoomTile: function(room) {
|
||||
var index = this.state.sortedList.indexOf(room);
|
||||
findRoomTile: function(room) {
|
||||
var index = this.state.sortedList.indexOf(room);
|
||||
if (index >= 0) {
|
||||
// console.log("found: room: " + room.roomId + " with index " + index);
|
||||
}
|
||||
@@ -210,7 +210,7 @@ var RoomSubList = React.createClass({
|
||||
},
|
||||
|
||||
calcManualOrderTagData: function(room) {
|
||||
var index = this.state.sortedList.indexOf(room);
|
||||
var index = this.state.sortedList.indexOf(room);
|
||||
|
||||
// we sort rooms by the lexicographic ordering of the 'order' metadata on their tags.
|
||||
// for convenience, we calculate this for now a floating point number between 0.0 and 1.0.
|
||||
@@ -274,7 +274,7 @@ var RoomSubList = React.createClass({
|
||||
},
|
||||
|
||||
_getHeaderJsx: function() {
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
return (
|
||||
<h2 onClick={ this.onClick } className="mx_RoomSubList_label">
|
||||
{ this.props.collapsed ? '' : this.props.label }
|
||||
@@ -332,7 +332,7 @@ var RoomSubList = React.createClass({
|
||||
}
|
||||
else {
|
||||
subList = <TruncatedList className={ classes }>
|
||||
</TruncatedList>;
|
||||
</TruncatedList>;
|
||||
}
|
||||
|
||||
return connectDropTarget(
|
||||
@@ -356,7 +356,7 @@ var RoomSubList = React.createClass({
|
||||
|
||||
// Export the wrapped version, inlining the 'collect' functions
|
||||
// to more closely resemble the ES7
|
||||
module.exports =
|
||||
module.exports =
|
||||
DropTarget('RoomTile', roomListTarget, function(connect) {
|
||||
return {
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
|
||||
@@ -40,7 +40,7 @@ module.exports = React.createClass({
|
||||
this.props.onFinished();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_ViewSource">
|
||||
|
||||
@@ -21,6 +21,12 @@ var React = require('react');
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SenderProfile',
|
||||
|
||||
propTypes: {
|
||||
mxEvent: React.PropTypes.object.isRequired, // event whose sender we're showing
|
||||
aux: React.PropTypes.string, // stuff to go after the sender name, if anything
|
||||
onClick: React.PropTypes.func,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var mxEvent = this.props.mxEvent;
|
||||
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
@@ -30,7 +36,7 @@ module.exports = React.createClass({
|
||||
name = ''; // emote message must include the name so don't duplicate it
|
||||
}
|
||||
return (
|
||||
<span className="mx_SenderProfile">
|
||||
<span className="mx_SenderProfile" onClick={this.props.onClick}>
|
||||
{name} { this.props.aux }
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -62,12 +62,17 @@ module.exports = React.createClass({
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
onPermalinkClick: function() {
|
||||
if (this.props.onFinished) this.props.onFinished();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var eventStatus = this.props.mxEvent.status;
|
||||
var resendButton;
|
||||
var viewSourceButton;
|
||||
var redactButton;
|
||||
var cancelButton;
|
||||
var permalinkButton;
|
||||
|
||||
if (eventStatus === 'not_sent') {
|
||||
resendButton = (
|
||||
@@ -99,12 +104,22 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
|
||||
// XXX: this should be https://matrix.to.
|
||||
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
|
||||
permalinkButton = (
|
||||
<div className="mx_ContextualMenu_field">
|
||||
<a href={ "#/room/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
|
||||
onClick={ this.onPermalinkClick }>Permalink</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{resendButton}
|
||||
{redactButton}
|
||||
{cancelButton}
|
||||
{viewSourceButton}
|
||||
{permalinkButton}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ var roomTileSource = {
|
||||
// Return the data describing the dragged item
|
||||
var item = {
|
||||
room: props.room,
|
||||
originalList: props.roomSubList,
|
||||
originalList: props.roomSubList,
|
||||
originalIndex: props.roomSubList.findRoomTile(props.room).index,
|
||||
targetList: props.roomSubList, // at first target is same as original
|
||||
// lastTargetRoom: null,
|
||||
@@ -145,10 +145,10 @@ var roomTileTarget = {
|
||||
// shuffle the list to add our tile to that position.
|
||||
props.roomSubList.moveRoomTile(item.room, roomTile.index);
|
||||
}
|
||||
|
||||
|
||||
// stop us from flickering between our droptarget and the previous room.
|
||||
// whenever the cursor changes direction we have to reset the flicker-damping.
|
||||
/*
|
||||
/*
|
||||
var yDelta = off.y - item.lastYOffset;
|
||||
|
||||
if ((yDelta > 0 && item.lastYDelta < 0) ||
|
||||
@@ -168,7 +168,7 @@ var roomTileTarget = {
|
||||
|
||||
if (yDelta) item.lastYDelta = yDelta;
|
||||
item.lastYOffset = off.y;
|
||||
*/
|
||||
*/
|
||||
}
|
||||
else if (switchedTarget) {
|
||||
if (!props.roomSubList.findRoomTile(item.room).room) {
|
||||
@@ -183,7 +183,7 @@ var roomTileTarget = {
|
||||
|
||||
// Export the wrapped version, inlining the 'collect' functions
|
||||
// to more closely resemble the ES7
|
||||
module.exports =
|
||||
module.exports =
|
||||
DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
|
||||
return {
|
||||
// Call this function inside render()
|
||||
|
||||
@@ -34,7 +34,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
}
|
||||
else {
|
||||
tooltip.style.top = tooltip.parentElement.getBoundingClientRect().top + "px";
|
||||
tooltip.style.top = tooltip.parentElement.getBoundingClientRect().top + "px";
|
||||
tooltip.style.display = "block";
|
||||
}
|
||||
},
|
||||
|
||||
@@ -50,7 +50,7 @@ module.exports = React.createClass({
|
||||
onSearch: function() {
|
||||
this.props.onSearch(this.refs.search_term.value, this.state.scope);
|
||||
},
|
||||
|
||||
|
||||
render: function() {
|
||||
var searchButtonClasses = classNames({ mx_SearchBar_searchButton : true, mx_SearchBar_searching: this.props.searchInProgress });
|
||||
var thisRoomClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'Room' });
|
||||
|
||||
@@ -28,249 +28,195 @@ var Modal = require('matrix-react-sdk/lib/Modal');
|
||||
* @enum {string}
|
||||
*/
|
||||
var PushRuleVectorState = {
|
||||
/** The push rule is disabled */
|
||||
OFF: "off",
|
||||
/** The user will receive push notification for this rule */
|
||||
ON: "on",
|
||||
/** The user will receive push notification for this rule with sound and
|
||||
highlight if this is legitimate */
|
||||
LOUD: "loud",
|
||||
/** The push rule is disabled */
|
||||
OFF: "off"
|
||||
};
|
||||
|
||||
// Encodes a dictionary of {
|
||||
// "notify": true/false,
|
||||
// "sound": string or undefined,
|
||||
// "highlight: true/false,
|
||||
// }
|
||||
// to a list of push actions.
|
||||
function encodeActions(action) {
|
||||
var notify = action.notify;
|
||||
var sound = action.sound;
|
||||
var highlight = action.highlight;
|
||||
if (notify) {
|
||||
var actions = ["notify"];
|
||||
if (sound) {
|
||||
actions.push({"set_tweak": "sound", "value": sound});
|
||||
}
|
||||
if (highlight) {
|
||||
actions.push({"set_tweak": "highlight"});
|
||||
} else {
|
||||
actions.push({"set_tweak": "highlight", "value": false});
|
||||
}
|
||||
return actions;
|
||||
} else {
|
||||
return ["dont_notify"];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode a list of actions to a dictionary of {
|
||||
// "notify": true/false,
|
||||
// "sound": string or undefined,
|
||||
// "highlight: true/false,
|
||||
// }
|
||||
// If the actions couldn't be decoded then returns null.
|
||||
function decodeActions(actions) {
|
||||
var notify = false;
|
||||
var sound = null;
|
||||
var highlight = false;
|
||||
|
||||
for (var i = 0; i < actions.length; ++i) {
|
||||
var action = actions[i];
|
||||
if (action === "notify") {
|
||||
notify = true;
|
||||
} else if (action === "dont_notify") {
|
||||
notify = false;
|
||||
} else if (typeof action === 'object') {
|
||||
if (action.set_tweak === "sound") {
|
||||
sound = action.value
|
||||
} else if (action.set_tweak === "highlight") {
|
||||
highlight = action.value;
|
||||
} else {
|
||||
// We don't understand this kind of tweak, so give up.
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// We don't understand this kind of action, so give up.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (highlight === undefined) {
|
||||
// If a highlight tweak is missing a value then it defaults to true.
|
||||
highlight = true;
|
||||
}
|
||||
|
||||
var result = {notify: notify, highlight: highlight};
|
||||
if (sound !== null) {
|
||||
result.sound = sound;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var ACTION_NOTIFY = encodeActions({notify: true});
|
||||
var ACTION_NOTIFY_DEFAULT_SOUND = encodeActions({notify: true, sound: "default"});
|
||||
var ACTION_NOTIFY_RING_SOUND = encodeActions({notify: true, sound: "ring"});
|
||||
var ACTION_HIGHLIGHT_DEFAULT_SOUND = encodeActions({notify: true, sound: "default", highlight: true});
|
||||
var ACTION_DONT_NOTIFY = encodeActions({notify: false});
|
||||
var ACTION_DISABLED = null;
|
||||
|
||||
|
||||
/**
|
||||
* The descriptions of rules managed by the Vector UI.
|
||||
* Each rule is described so that if the server does not have it in its default
|
||||
* rules or if the user wants to use actions ('PushRuleVectorState') that are
|
||||
* different from the hs one, the code will create a new rule that will override
|
||||
* the hs one.
|
||||
*/
|
||||
var VectorPushRulesDefinitions = {
|
||||
|
||||
// Messages containing user's display name
|
||||
// Messages containing user's display name
|
||||
// (skip contains_user_name which is too geeky)
|
||||
"im.vector.rule.contains_display_name": {
|
||||
".m.rule.contains_display_name": {
|
||||
kind: "underride",
|
||||
hsDefaultRuleId: ".m.rule.contains_display_name",
|
||||
description: "Messages containing my name",
|
||||
conditions: [{
|
||||
"kind": "contains_display_name"
|
||||
}],
|
||||
vectorStateToActions: { // The actions for each vector state
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "default"
|
||||
},
|
||||
{
|
||||
"set_tweak":"highlight"
|
||||
}
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: { // If it exists, the hs default push rule enabled expected value for each vector state
|
||||
on: undefined, // ON (and its actions) does not corresponds to the default hs push rule, so NA
|
||||
loud: true, // LOUD corresponds to the default rule when its enabled value is true
|
||||
off: false // OFF corresponds to the default rule when its enabled value is false
|
||||
},
|
||||
vectorStateToActions: { // The actions for each vector state, or null to disable the rule.
|
||||
on: ACTION_NOTIFY,
|
||||
loud: ACTION_HIGHLIGHT_DEFAULT_SOUND,
|
||||
off: ACTION_DISABLED
|
||||
}
|
||||
},
|
||||
|
||||
// Messages just sent to the user in a 1:1 room
|
||||
"im.vector.rule.room_one_to_one": {
|
||||
".m.rule.room_one_to_one": {
|
||||
kind: "underride",
|
||||
hsDefaultRuleId: ".m.rule.room_one_to_one",
|
||||
description: "Messages in one-to-one chats",
|
||||
conditions: [{
|
||||
"is": "2",
|
||||
"kind": "room_member_count"
|
||||
}],
|
||||
vectorStateToActions: {
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "default"
|
||||
}
|
||||
],
|
||||
off: [
|
||||
"dont_notify"
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: undefined,
|
||||
loud: true,
|
||||
off: undefined
|
||||
on: ACTION_NOTIFY,
|
||||
loud: ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
off: ACTION_DONT_NOTIFY
|
||||
}
|
||||
},
|
||||
|
||||
// Messages just sent to a group chat room
|
||||
// 1:1 room messages are catched by the .m.rule.room_one_to_one rule if any defined
|
||||
// By opposition, all other room messages are from group chat rooms.
|
||||
"im.vector.rule.room_message": {
|
||||
".m.rule.message": {
|
||||
kind: "underride",
|
||||
description: "Messages in group chats",
|
||||
conditions: [{
|
||||
"pattern": "m.room.message",
|
||||
"kind": "event_match",
|
||||
"key": "type"
|
||||
}],
|
||||
hsDefaultRuleId: ".m.rule.message",
|
||||
vectorStateToActions: {
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "default"
|
||||
}
|
||||
],
|
||||
off: [
|
||||
"dont_notify"
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: true,
|
||||
loud: undefined,
|
||||
off: undefined
|
||||
on: ACTION_NOTIFY,
|
||||
loud: ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
off: ACTION_DONT_NOTIFY
|
||||
}
|
||||
},
|
||||
|
||||
// Invitation for the user
|
||||
"im.vector.rule.invite_for_me": {
|
||||
".m.rule.invite_for_me": {
|
||||
kind: "underride",
|
||||
hsDefaultRuleId: ".m.rule.invite_for_me",
|
||||
description: "When I'm invited to a room",
|
||||
conditions: [
|
||||
{
|
||||
"key": "type",
|
||||
"kind": "event_match",
|
||||
"pattern": "m.room.member"
|
||||
},
|
||||
{
|
||||
"key": "content.membership",
|
||||
"kind": "event_match",
|
||||
"pattern": "invite"
|
||||
},
|
||||
{
|
||||
"key": "state_key",
|
||||
"kind": "event_match",
|
||||
"pattern": "" // It is updated at runtime the user id
|
||||
}
|
||||
],
|
||||
vectorStateToActions: {
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: undefined,
|
||||
loud: true,
|
||||
off: false
|
||||
on: ACTION_NOTIFY,
|
||||
loud: ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
off: ACTION_DISABLED
|
||||
}
|
||||
},
|
||||
|
||||
// When people join or leave a room
|
||||
/*"im.vector.rule.member_event": {
|
||||
hsDefaultRuleId: ".m.rule.member_event",
|
||||
description: "When people join or leave a room",
|
||||
conditions: [{
|
||||
"pattern": "m.room.member",
|
||||
"kind": "event_match",
|
||||
"key": "type"
|
||||
}],
|
||||
vectorStateToActions: {
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: true,
|
||||
loud: undefined,
|
||||
off: false
|
||||
}
|
||||
},*/
|
||||
|
||||
// Incoming call
|
||||
"im.vector.rule.call": {
|
||||
".m.rule.call": {
|
||||
kind: "underride",
|
||||
hsDefaultRuleId: ".m.rule.call",
|
||||
description: "Call invitation",
|
||||
conditions: [{
|
||||
"pattern": "m.room.member",
|
||||
"kind": "event_match",
|
||||
"key": "type"
|
||||
}],
|
||||
vectorStateToActions: {
|
||||
on: [
|
||||
"notify"
|
||||
],
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "ring"
|
||||
}
|
||||
],
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: undefined,
|
||||
loud: true,
|
||||
off: false
|
||||
on: ACTION_NOTIFY,
|
||||
loud: ACTION_NOTIFY_RING_SOUND,
|
||||
off: ACTION_DISABLED
|
||||
}
|
||||
},
|
||||
|
||||
// Notifications from bots
|
||||
"im.vector.rule.notices": {
|
||||
".m.rule.suppress_notices": {
|
||||
kind: "override",
|
||||
hsDefaultRuleId: ".m.rule.suppress_notices",
|
||||
description: "Messages sent by bot",
|
||||
conditions: [{
|
||||
"kind": "event_match",
|
||||
"key": "content.msgtype",
|
||||
"pattern": "m.notice"
|
||||
}],
|
||||
vectorStateToActions: {
|
||||
on: undefined, // ON for vector UI means that the .m.rule.suppress_notices rule is disabled.
|
||||
loud: [
|
||||
"notify",
|
||||
{
|
||||
"set_tweak": "sound",
|
||||
"value": "ring"
|
||||
}
|
||||
],
|
||||
off: [
|
||||
"dont_notify"
|
||||
]
|
||||
},
|
||||
vectorStateToHsDefaultRuleEnabled: {
|
||||
on: false, // .m.rule.suppress_notices is a "negative" rule, we have to invert its enabled value for vector UI
|
||||
loud: undefined,
|
||||
off: true
|
||||
// .m.rule.suppress_notices is a "negative" rule, we have to invert its enabled value for vector UI
|
||||
on: ACTION_DISABLED,
|
||||
loud: ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
off: ACTION_DONT_NOTIFY,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rules that Vector used to set in order to override the actions of default rules.
|
||||
* These are used to port peoples existing overrides to match the current API.
|
||||
* These can be removed and forgotten once everyone has moved to the new client.
|
||||
*/
|
||||
var LEGACY_RULES = {
|
||||
"im.vector.rule.contains_display_name": ".m.rule.contains_display_name",
|
||||
"im.vector.rule.room_one_to_one": ".m.rule.room_one_to_one",
|
||||
"im.vector.rule.room_message": ".m.rule.message",
|
||||
"im.vector.rule.invite_for_me": ".m.rule.invite_for_me",
|
||||
"im.vector.rule.call": ".m.rule.call",
|
||||
"im.vector.rule.notices": ".m.rule.suppress_notices"
|
||||
};
|
||||
|
||||
function portLegacyActions(actions) {
|
||||
var decoded = decodeActions(actions);
|
||||
if (decoded !== null) {
|
||||
return encodeActions(decoded);
|
||||
} else {
|
||||
// We don't recognise one of the actions here, so we don't try to
|
||||
// canonicalise them.
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Notififications',
|
||||
|
||||
@@ -279,7 +225,7 @@ module.exports = React.createClass({
|
||||
DISPLAY: "DISPLAY", // The component is ready and display data
|
||||
ERROR: "ERROR" // There was an error
|
||||
},
|
||||
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
phase: this.phases.LOADING,
|
||||
@@ -293,14 +239,11 @@ module.exports = React.createClass({
|
||||
externalContentRules: [] // Keyword push rules that have been defined outside Vector UI
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
componentWillMount: function() {
|
||||
// Finalise the vector definitions
|
||||
VectorPushRulesDefinitions["im.vector.rule.invite_for_me"].conditions[2].pattern = MatrixClientPeg.get().credentials.userId;
|
||||
|
||||
this._refreshFromServer();
|
||||
},
|
||||
|
||||
|
||||
onEnableNotificationsChange: function(event) {
|
||||
var self = this;
|
||||
this.setState({
|
||||
@@ -311,15 +254,15 @@ module.exports = React.createClass({
|
||||
self._refreshFromServer();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
onEnableDesktopNotificationsChange: function(event) {
|
||||
UserSettingsStore.setEnableNotifications(event.target.checked);
|
||||
},
|
||||
|
||||
|
||||
onNotifStateButtonClicked: function(event) {
|
||||
var vectorRuleId = event.target.className.split("-")[0];
|
||||
var newPushRuleVectorState = event.target.className.split("-")[1];
|
||||
|
||||
|
||||
if ("_keywords" === vectorRuleId) {
|
||||
this._setKeywordsPushRuleVectorState(newPushRuleVectorState)
|
||||
}
|
||||
@@ -330,7 +273,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onKeywordsClicked: function(event) {
|
||||
var self = this;
|
||||
|
||||
@@ -371,13 +314,13 @@ module.exports = React.createClass({
|
||||
}
|
||||
return array;
|
||||
},[]);
|
||||
|
||||
|
||||
self._setKeywords(newKeywords);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
getRule: function(vectorRuleId) {
|
||||
for (var i in this.state.vectorPushRules) {
|
||||
var rule = this.state.vectorPushRules[i];
|
||||
@@ -386,24 +329,21 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_actionsFor: function(pushRuleVectorState) {
|
||||
if (pushRuleVectorState === PushRuleVectorState.ON) {
|
||||
return ['notify'];
|
||||
return ACTION_NOTIFY;
|
||||
}
|
||||
else if (pushRuleVectorState === PushRuleVectorState.LOUD) {
|
||||
return ['notify',
|
||||
{'set_tweak': 'sound', 'value': 'default'},
|
||||
{'set_tweak': 'highlight', 'value': 'true'}
|
||||
];;
|
||||
return ACTION_HIGHLIGHT_DEFAULT_SOUND;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Determine whether a content rule is in the PushRuleVectorState.ON category or in PushRuleVectorState.LOUD
|
||||
// regardless of its enabled state. Returns undefined if it does not match these categories.
|
||||
_contentRuleVectorStateKind: function(rule) {
|
||||
var stateKind;
|
||||
|
||||
|
||||
// Count tweaks to determine if it is a ON or LOUD rule
|
||||
var tweaks = 0;
|
||||
for (var j in rule.actions) {
|
||||
@@ -423,9 +363,9 @@ module.exports = React.createClass({
|
||||
}
|
||||
return stateKind;
|
||||
},
|
||||
|
||||
_setPushRuleVectorState: function(rule, newPushRuleVectorState) {
|
||||
if (rule && rule.vectorState !== newPushRuleVectorState) {
|
||||
|
||||
_setPushRuleVectorState: function(rule, newPushRuleVectorState) {
|
||||
if (rule && rule.vectorState !== newPushRuleVectorState) {
|
||||
|
||||
this.setState({
|
||||
phase: this.phases.LOADING
|
||||
@@ -437,36 +377,18 @@ module.exports = React.createClass({
|
||||
var ruleDefinition = VectorPushRulesDefinitions[rule.vectorRuleId];
|
||||
|
||||
if (rule.rule) {
|
||||
if (undefined !== ruleDefinition.vectorStateToHsDefaultRuleEnabled[newPushRuleVectorState] && rule.hsDefaultRule) {
|
||||
// The new state corresponds to the default hs rule
|
||||
// Enable or disable it according to the rule definition
|
||||
deferreds.push(cli.setPushRuleEnabled('global', rule.hsDefaultRule.kind, ruleDefinition.hsDefaultRuleId,
|
||||
ruleDefinition.vectorStateToHsDefaultRuleEnabled[newPushRuleVectorState]));
|
||||
var actions = ruleDefinition.vectorStateToActions[newPushRuleVectorState];
|
||||
|
||||
// Remove the vector rule if any
|
||||
if (!rule.isHSDefaultRule) {
|
||||
deferreds.push(cli.deletePushRule('global', rule.rule.kind, rule.rule.rule_id))
|
||||
}
|
||||
if (actions === ACTION_DISABLED) {
|
||||
// The new state corresponds to disabling the rule.
|
||||
deferreds.push(cli.setPushRuleEnabled('global', rule.rule.kind, rule.rule.rule_id, false));
|
||||
}
|
||||
else {
|
||||
// The new state (and its implied actions) does not correspond to a default hs rule
|
||||
// or the HS does not expose this default rule.
|
||||
if (rule.isHSDefaultRule) {
|
||||
// Create a new rule that will override the default one
|
||||
deferreds.push(this._addOverridingVectorPushRule(rule.vectorRuleId, newPushRuleVectorState));
|
||||
}
|
||||
else {
|
||||
// Change the actions of the existing overriding Vector rule
|
||||
deferreds.push(this._updatePushRuleActions(rule.rule, ruleDefinition.vectorStateToActions[newPushRuleVectorState]));
|
||||
}
|
||||
// The new state corresponds to enabling the rule and setting specific actions
|
||||
deferreds.push(this._updatePushRuleActions(rule.rule, actions, true));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is a Vector rule which does not exist yet server side
|
||||
// Create it
|
||||
deferreds.push(this._addOverridingVectorPushRule(rule.vectorRuleId, newPushRuleVectorState));
|
||||
}
|
||||
|
||||
|
||||
q.all(deferreds).done(function() {
|
||||
self._refreshFromServer();
|
||||
}, function(error) {
|
||||
@@ -479,14 +401,14 @@ module.exports = React.createClass({
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_setKeywordsPushRuleVectorState: function(newPushRuleVectorState) {
|
||||
// Is there really a change?
|
||||
if (this.state.vectorContentRules.vectorState === newPushRuleVectorState
|
||||
if (this.state.vectorContentRules.vectorState === newPushRuleVectorState
|
||||
|| this.state.vectorContentRules.rules.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var self = this;
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
@@ -547,7 +469,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
_setKeywords: function(newKeywords) {
|
||||
this.setState({
|
||||
phase: this.phases.LOADING
|
||||
@@ -595,9 +517,9 @@ module.exports = React.createClass({
|
||||
var pushRuleVectorStateKind = self.state.vectorContentRules.vectorState;
|
||||
if (pushRuleVectorStateKind === PushRuleVectorState.OFF) {
|
||||
// When the current global keywords rule is OFF, we need to look at
|
||||
// the flavor of rules in 'vectorContentRules' to apply the same actions
|
||||
// the flavor of rules in 'vectorContentRules' to apply the same actions
|
||||
// when creating the new rule.
|
||||
// Thus, this new rule will join the 'vectorContentRules' set.
|
||||
// Thus, this new rule will join the 'vectorContentRules' set.
|
||||
if (self.state.vectorContentRules.rules.length) {
|
||||
pushRuleVectorStateKind = self._contentRuleVectorStateKind(self.state.vectorContentRules.rules[0]);
|
||||
}
|
||||
@@ -636,38 +558,50 @@ module.exports = React.createClass({
|
||||
// Create a push rule but disabled
|
||||
_addDisabledPushRule: function(scope, kind, ruleId, body) {
|
||||
var cli = MatrixClientPeg.get();
|
||||
var deferred = q.defer();
|
||||
|
||||
cli.addPushRule(scope, kind, ruleId, body).done(function() {
|
||||
cli.setPushRuleEnabled(scope, kind, ruleId, false).done(function() {
|
||||
deferred.resolve();
|
||||
}, function(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
}, function(err) {
|
||||
deferred.reject(err);
|
||||
return cli.addPushRule(scope, kind, ruleId, body).then(function() {
|
||||
return cli.setPushRuleEnabled(scope, kind, ruleId, false);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
// Add a push rule server side according to the 'VectorPushRulesDefinitions' spec
|
||||
_addOverridingVectorPushRule: function(vectorRuleId, vectorState) {
|
||||
// Check if any legacy im.vector rules need to be ported to the new API
|
||||
// for overriding the actions of default rules.
|
||||
_portRulesToNewAPI: function(rulesets) {
|
||||
var self = this;
|
||||
var needsUpdate = [];
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
// Create the rule as predefined
|
||||
var ruleDefinition = VectorPushRulesDefinitions[vectorRuleId];
|
||||
var body = {
|
||||
conditions: ruleDefinition.conditions,
|
||||
actions: ruleDefinition.vectorStateToActions[vectorState]
|
||||
for (var kind in rulesets.global) {
|
||||
var ruleset = rulesets.global[kind];
|
||||
for (var i = 0; i < ruleset.length; ++i) {
|
||||
var rule = ruleset[i];
|
||||
if (rule.rule_id in LEGACY_RULES) {
|
||||
console.log("Porting legacy rule", rule);
|
||||
needsUpdate.push( function(kind, rule) {
|
||||
return cli.setPushRuleActions(
|
||||
'global', kind, LEGACY_RULES[rule.rule_id], portLegacyActions(rule.actions)
|
||||
).then( function() {
|
||||
return cli.deletePushRule('global', kind, rule.rule_id);
|
||||
})
|
||||
}(kind, rule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsUpdate.length > 0) {
|
||||
// If some of the rules need to be ported then wait for the porting
|
||||
// to happen and then fetch the rules again.
|
||||
return q.allSettled(needsUpdate).then( function() {
|
||||
return cli.getPushRules();
|
||||
});
|
||||
} else {
|
||||
// Otherwise return the rules that we already have.
|
||||
return rulesets;
|
||||
}
|
||||
|
||||
return MatrixClientPeg.get().addPushRule('global', ruleDefinition.kind, vectorRuleId, body);
|
||||
},
|
||||
|
||||
_refreshFromServer: function() {
|
||||
var self = this;
|
||||
MatrixClientPeg.get().getPushRules().done(function(rulesets) {
|
||||
var self = this;
|
||||
MatrixClientPeg.get().getPushRules().then(self._portRulesToNewAPI).done(function(rulesets) {
|
||||
MatrixClientPeg.get().pushRules = rulesets;
|
||||
|
||||
// Get homeserver default rules and triage them by categories
|
||||
@@ -690,8 +624,6 @@ module.exports = React.createClass({
|
||||
|
||||
// HS default rules
|
||||
var defaultRules = {master: [], vector: {}, others: []};
|
||||
// Push rules defined py Vector to override hs default rules
|
||||
var vectorOverridingRules = {};
|
||||
// Content/keyword rules
|
||||
var contentRules = {on: [], on_but_disabled:[], loud: [], loud_but_disabled: [], other: []};
|
||||
|
||||
@@ -700,30 +632,18 @@ module.exports = React.createClass({
|
||||
var r = rulesets.global[kind][i];
|
||||
var cat = rule_categories[r.rule_id];
|
||||
r.kind = kind;
|
||||
if (r.rule_id[0] === '.') {
|
||||
if (cat) {
|
||||
if (cat === 'vector') {
|
||||
// Remove disabled, useless actions
|
||||
r.actions = r.actions.reduce(function(array, action){
|
||||
if (action.value !== false) {
|
||||
array.push(action);
|
||||
}
|
||||
return array;
|
||||
},[]);
|
||||
|
||||
defaultRules.vector[r.rule_id] = r;
|
||||
}
|
||||
else {
|
||||
defaultRules[cat].push(r);
|
||||
}
|
||||
if (r.rule_id[0] === '.') {
|
||||
if (cat === 'vector') {
|
||||
defaultRules.vector[r.rule_id] = r;
|
||||
}
|
||||
else if (cat === 'master') {
|
||||
defaultRules.master.push(r);
|
||||
}
|
||||
else {
|
||||
defaultRules['others'].push(r);
|
||||
}
|
||||
}
|
||||
else if (r.rule_id.startsWith('im.vector')) {
|
||||
vectorOverridingRules[r.rule_id] = r;
|
||||
}
|
||||
else if (kind === 'content') {
|
||||
switch (self._contentRuleVectorStateKind(r)) {
|
||||
case PushRuleVectorState.ON:
|
||||
@@ -755,8 +675,8 @@ module.exports = React.createClass({
|
||||
// whereas Matrix has a push rule per keyword.
|
||||
// Vector can set the unique rule in ON, LOUD or OFF state.
|
||||
// Matrix has enabled/disabled plus a combination of (highlight, sound) tweaks.
|
||||
|
||||
// The code below determines which set of user's content push rules can be
|
||||
|
||||
// The code below determines which set of user's content push rules can be
|
||||
// displayed by the vector UI.
|
||||
// Push rules that does not fit, ie defined by another Matrix client, ends
|
||||
// in self.state.externalContentRules.
|
||||
@@ -767,14 +687,14 @@ module.exports = React.createClass({
|
||||
self.state.vectorContentRules = {
|
||||
vectorState: PushRuleVectorState.LOUD,
|
||||
rules: contentRules.loud
|
||||
}
|
||||
}
|
||||
self.state.externalContentRules = [].concat(contentRules.loud_but_disabled, contentRules.on, contentRules.on_but_disabled, contentRules.other);
|
||||
}
|
||||
else if (contentRules.loud_but_disabled.length) {
|
||||
self.state.vectorContentRules = {
|
||||
vectorState: PushRuleVectorState.OFF,
|
||||
rules: contentRules.loud_but_disabled
|
||||
}
|
||||
}
|
||||
self.state.externalContentRules = [].concat(contentRules.on, contentRules.on_but_disabled, contentRules.other);
|
||||
}
|
||||
else if (contentRules.on.length) {
|
||||
@@ -804,14 +724,14 @@ module.exports = React.createClass({
|
||||
self.state.vectorPushRules = [];
|
||||
|
||||
var vectorRuleIds = [
|
||||
'im.vector.rule.contains_display_name',
|
||||
'.m.rule.contains_display_name',
|
||||
'_keywords',
|
||||
'im.vector.rule.room_one_to_one',
|
||||
'im.vector.rule.room_message',
|
||||
'im.vector.rule.invite_for_me',
|
||||
'.m.rule.room_one_to_one',
|
||||
'.m.rule.message',
|
||||
'.m.rule.invite_for_me',
|
||||
//'im.vector.rule.member_event',
|
||||
'im.vector.rule.call',
|
||||
'im.vector.rule.notices'
|
||||
'.m.rule.call',
|
||||
'.m.rule.suppress_notices'
|
||||
];
|
||||
for (var i in vectorRuleIds) {
|
||||
var vectorRuleId = vectorRuleIds[i];
|
||||
@@ -828,13 +748,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
}
|
||||
else {
|
||||
var rule = vectorOverridingRules[vectorRuleId];
|
||||
var isHSDefaultRule = false;
|
||||
if (!rule) {
|
||||
// If the rule is not defined, look at the hs default one
|
||||
rule = defaultRules.vector[ruleDefinition.hsDefaultRuleId];
|
||||
isHSDefaultRule = true;
|
||||
}
|
||||
var rule = defaultRules.vector[vectorRuleId];
|
||||
|
||||
// Translate the rule actions and its enabled value into vector state
|
||||
var vectorState;
|
||||
@@ -843,9 +757,9 @@ module.exports = React.createClass({
|
||||
var state = PushRuleVectorState[stateKey];
|
||||
var vectorStateToActions = ruleDefinition.vectorStateToActions[state];
|
||||
|
||||
if (!vectorStateToActions) {
|
||||
if (vectorStateToActions === ACTION_DISABLED) {
|
||||
// No defined actions means that this vector state expects a disabled default hs rule
|
||||
if (isHSDefaultRule && rule.enabled === ruleDefinition.vectorStateToHsDefaultRuleEnabled[state]) {
|
||||
if (rule.enabled === false) {
|
||||
vectorState = state;
|
||||
break;
|
||||
}
|
||||
@@ -853,14 +767,8 @@ module.exports = React.createClass({
|
||||
else {
|
||||
// The actions must match to the ones expected by vector state
|
||||
if (JSON.stringify(rule.actions) === JSON.stringify(vectorStateToActions)) {
|
||||
if (isHSDefaultRule) {
|
||||
// In the case of a default hs push rule, the enabled value must also match
|
||||
if (rule.enabled === ruleDefinition.vectorStateToHsDefaultRuleEnabled[state]) {
|
||||
vectorState = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// And the rule must be enabled.
|
||||
if (rule.enabled === true) {
|
||||
vectorState = state;
|
||||
break;
|
||||
}
|
||||
@@ -869,8 +777,8 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
if (!vectorState) {
|
||||
console.error("Cannot translate rule actions into Vector rule state. Rule: " + rule);
|
||||
vectorState = PushRuleVectorState.OFF;
|
||||
console.error("Cannot translate rule actions into Vector rule state. Rule: " + rule);
|
||||
vectorState = PushRuleVectorState.OFF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -882,12 +790,10 @@ module.exports = React.createClass({
|
||||
"description" : ruleDefinition.description,
|
||||
"rule": rule,
|
||||
"vectorState": vectorState,
|
||||
"isHSDefaultRule": isHSDefaultRule,
|
||||
"hsDefaultRule": defaultRules.vector[ruleDefinition.hsDefaultRuleId]
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Build the rules not managed by Vector UI
|
||||
var otherRulesDescriptions = {
|
||||
'.m.rule.message': "Notify for all other messages/rooms",
|
||||
@@ -898,7 +804,7 @@ module.exports = React.createClass({
|
||||
for (var i in defaultRules.others) {
|
||||
var rule = defaultRules.others[i];
|
||||
var ruleDescription = otherRulesDescriptions[rule.rule_id];
|
||||
|
||||
|
||||
// Show enabled default rules that was modified by the user
|
||||
if (ruleDescription && rule.enabled && !rule.default) {
|
||||
rule.description = ruleDescription;
|
||||
@@ -911,41 +817,22 @@ module.exports = React.createClass({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_updatePushRuleActions: function(rule, actions, enabled) {
|
||||
// Workaround for SYN-590 : Push rule update fails
|
||||
// Remove the rule and recreate it with the new actions
|
||||
var cli = MatrixClientPeg.get();
|
||||
var deferred = q.defer();
|
||||
|
||||
cli.deletePushRule('global', rule.kind, rule.rule_id).done(function() {
|
||||
cli.addPushRule('global', rule.kind, rule.rule_id, {
|
||||
conditions: rule.conditions,
|
||||
actions: actions,
|
||||
pattern: rule.pattern
|
||||
}).done(function() {
|
||||
|
||||
// Then, if requested, enabled or disabled the rule
|
||||
if (undefined != enabled) {
|
||||
cli.setPushRuleEnabled('global', rule.kind, rule.rule_id, enabled).done(function() {
|
||||
deferred.resolve();
|
||||
}, function(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
deferred.resolve();
|
||||
}
|
||||
}, function(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
}, function(err) {
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
_updatePushRuleActions: function(rule, actions, enabled) {
|
||||
var cli = MatrixClientPeg.get();
|
||||
|
||||
return cli.setPushRuleActions(
|
||||
'global', rule.kind, rule.rule_id, actions
|
||||
).then( function() {
|
||||
// Then, if requested, enabled or disabled the rule
|
||||
if (undefined != enabled) {
|
||||
return cli.setPushRuleEnabled(
|
||||
'global', rule.kind, rule.rule_id, enabled
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
renderNotifRulesTableRow: function(title, className, pushRuleVectorState) {
|
||||
return (
|
||||
<tr key = {className}>
|
||||
@@ -953,6 +840,13 @@ module.exports = React.createClass({
|
||||
{title}
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<input className= {className + "-" + PushRuleVectorState.OFF}
|
||||
type="radio"
|
||||
checked={ pushRuleVectorState === PushRuleVectorState.OFF }
|
||||
onChange={ this.onNotifStateButtonClicked } />
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<input className= {className + "-" + PushRuleVectorState.ON}
|
||||
type="radio"
|
||||
@@ -966,17 +860,10 @@ module.exports = React.createClass({
|
||||
checked={ pushRuleVectorState === PushRuleVectorState.LOUD }
|
||||
onChange={ this.onNotifStateButtonClicked } />
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<input className= {className + "-" + PushRuleVectorState.OFF}
|
||||
type="radio"
|
||||
checked={ pushRuleVectorState === PushRuleVectorState.OFF }
|
||||
onChange={ this.onNotifStateButtonClicked } />
|
||||
</th>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
renderNotifRulesTableRows: function() {
|
||||
var rows = [];
|
||||
for (var i in this.state.vectorPushRules) {
|
||||
@@ -986,7 +873,7 @@ module.exports = React.createClass({
|
||||
return rows;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
render: function() {
|
||||
var self = this;
|
||||
|
||||
if (this.state.phase === this.phases.LOADING) {
|
||||
@@ -1010,7 +897,7 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
<div className="mx_UserNotifSettings_labelCell">
|
||||
<label htmlFor="enableNotifications">
|
||||
Enable notifications
|
||||
Enable notifications for this account
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1019,7 +906,7 @@ module.exports = React.createClass({
|
||||
|
||||
// When enabled, the master rule inhibits all existing rules
|
||||
// So do not show all notification settings
|
||||
if (this.state.masterPushRule.enabled) {
|
||||
if (this.state.masterPushRule && this.state.masterPushRule.enabled) {
|
||||
return (
|
||||
<div>
|
||||
{masterPushRuleDiv}
|
||||
@@ -1060,7 +947,7 @@ module.exports = React.createClass({
|
||||
{ externalRules }
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -1110,9 +997,9 @@ module.exports = React.createClass({
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="55%"></th>
|
||||
<th width="15%">Off</th>
|
||||
<th width="15%">On</th>
|
||||
<th width="15%">Loud</th>
|
||||
<th width="15%">Off</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -1124,7 +1011,7 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
|
||||
{ advancedSettings }
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,12 @@ input[type=text]:focus, textarea:focus {
|
||||
flexbox to adapt to the new size and cause the view to keep growing.
|
||||
*/
|
||||
.gm-scrollbar-container .gm-scroll-view {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* hack to avoid accidental click-throughs if you miss the narrow scrollbar */
|
||||
.gm-scrollbar.-vertical {
|
||||
border-left: 6px solid transparent;
|
||||
}
|
||||
|
||||
.mx_ContextualMenu_background {
|
||||
|
||||
@@ -18,7 +18,7 @@ limitations under the License.
|
||||
width: 960px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
color: #4a4a4a;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.mx_CreateRoom input,
|
||||
|
||||
@@ -31,7 +31,7 @@ limitations under the License.
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_placeholderIndicator {
|
||||
.mx_RoomStatusBar_placeholderIndicator {
|
||||
color: #4a4a4a;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_RoomStatusBar_scrollDownIndicator {
|
||||
.mx_RoomStatusBar_scrollDownIndicator {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ limitations under the License.
|
||||
.mx_RoomView_messageListWrapper {
|
||||
max-width: 960px;
|
||||
margin: auto;
|
||||
|
||||
|
||||
min-height: 100%;
|
||||
|
||||
display: -webkit-box;
|
||||
@@ -137,6 +137,11 @@ limitations under the License.
|
||||
-webkit-justify-content: flex-end;
|
||||
}
|
||||
|
||||
.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper {
|
||||
justify-content: flex-start;
|
||||
-webkit-justify-content: flex-start;
|
||||
}
|
||||
|
||||
.mx_RoomView_MessageList {
|
||||
width: 100%;
|
||||
list-style-type: none;
|
||||
@@ -260,4 +265,5 @@ hr.mx_RoomView_myReadMarker {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
opacity: 0.6;
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mx_UploadBar_uploadBytes {
|
||||
float: right;
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
margin-right: 30px;
|
||||
color: #76cfa6;
|
||||
|
||||
@@ -26,7 +26,7 @@ limitations under the License.
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_UserSettings .mx_RoomHeader {
|
||||
@@ -50,7 +50,7 @@ limitations under the License.
|
||||
-webkit-flex: 1 1 0;
|
||||
flex: 1 1 0;
|
||||
|
||||
overflow-y: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_UserSettings_spinner {
|
||||
|
||||
@@ -60,6 +60,14 @@ limitations under the License.
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.mx_Login_fieldLabel {
|
||||
margin-top: -10px;
|
||||
margin-left: 8px;
|
||||
margin-bottom: 14px;
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mx_Login_submit {
|
||||
margin-top: 35px;
|
||||
margin-bottom: 24px;
|
||||
@@ -77,7 +85,8 @@ limitations under the License.
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mx_Login_checkbox {
|
||||
.mx_Login_checkbox,
|
||||
.mx_Login_radio {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ limitations under the License.
|
||||
top: 0px;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
|
||||
.mx_EntityTile_name {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
|
||||
@@ -29,6 +29,7 @@ limitations under the License.
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_EventTile_continuation {
|
||||
@@ -42,6 +43,7 @@ limitations under the License.
|
||||
margin-bottom: 4px;
|
||||
display: block;
|
||||
overflow-y: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_EventTile .mx_MessageTimestamp {
|
||||
@@ -55,9 +57,16 @@ limitations under the License.
|
||||
margin-right: 95px;
|
||||
}
|
||||
|
||||
/* all the overflow-y: hidden; are to trap Zalgos -
|
||||
but they introduce an implicit overflow-x: auto.
|
||||
so make that explicitly hidden too to avoid random
|
||||
horizontal scrollbars occasionally appearing, like in
|
||||
https://github.com/vector-im/vector-web/issues/1154
|
||||
*/
|
||||
.mx_EventTile_content {
|
||||
display: block;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Various markdown overrides */
|
||||
@@ -70,6 +79,15 @@ limitations under the License.
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* have to use overlay rather than auto otherwise Linux and Windows
|
||||
Chrome gets very confused about vertical spacing:
|
||||
https://github.com/vector-im/vector-web/issues/754
|
||||
*/
|
||||
.mx_EventTile_content .markdown-body pre {
|
||||
overflow-x: overlay;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.mx_EventTile_content .markdown-body h1,
|
||||
.mx_EventTile_content .markdown-body h2,
|
||||
.mx_EventTile_content .markdown-body h3,
|
||||
@@ -90,10 +108,10 @@ limitations under the License.
|
||||
|
||||
/* end of overrides */
|
||||
|
||||
/* this is used for the tile for the event which is selected via the URL.
|
||||
* TODO: ultimately we probably want some transition on here.
|
||||
/* this is used for the tile for the event which is selected via the URL.
|
||||
* TODO: ultimately we probably want some transition on here.
|
||||
*/
|
||||
.mx_EventTile_selected {
|
||||
.mx_EventTile_selected {
|
||||
border-left: #76cfa6 5px solid;
|
||||
margin-left: 53px;
|
||||
padding-left: 7px;
|
||||
@@ -110,7 +128,7 @@ limitations under the License.
|
||||
|
||||
.mx_EventTile_searchHighlight a {
|
||||
background-color: #76cfa6;
|
||||
color: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mx_EventTile_sending {
|
||||
@@ -158,7 +176,7 @@ limitations under the License.
|
||||
.mx_EventTile_editButton {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.mx_EventTile:hover .mx_EventTile_editButton {
|
||||
|
||||
@@ -46,7 +46,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_MemberInfo_profileField {
|
||||
font-color: #999999;
|
||||
font-color: #999999;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
|
||||
@@ -30,6 +30,11 @@ limitations under the License.
|
||||
-webkit-flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_MemberList .mx_Spinner {
|
||||
flex: 0;
|
||||
-webkit-flex: 0;
|
||||
}
|
||||
|
||||
.mx_MemberList_chevron {
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
@@ -91,12 +96,12 @@ limitations under the License.
|
||||
padding-left: 3px;
|
||||
padding-right: 12px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* we have to have display: table in order for the horizontal wrapping to work */
|
||||
.mx_MemberList_wrapper {
|
||||
display: table;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ limitations under the License.
|
||||
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
|
||||
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
@@ -71,7 +71,7 @@ limitations under the License.
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
/*
|
||||
/*
|
||||
-webkit-flex: 0 0 90px;
|
||||
flex: 0 0 90px;
|
||||
*/
|
||||
@@ -203,12 +203,12 @@ limitations under the License.
|
||||
float: left;
|
||||
max-height: 42px;
|
||||
color: #454545;
|
||||
font-weight: 300;
|
||||
font-weight: 300;
|
||||
margin-left: 19px;
|
||||
margin-right: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_avatar {
|
||||
@@ -218,6 +218,10 @@ limitations under the License.
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_avatar .mx_BaseAvatar_image {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_avatarPicker_edit {
|
||||
position: absolute;
|
||||
margin-left: 16px;
|
||||
|
||||
@@ -23,7 +23,7 @@ limitations under the License.
|
||||
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
|
||||
|
||||
justify-content: center;
|
||||
-webkit-justify-content: center;
|
||||
|
||||
@@ -54,3 +54,15 @@ limitations under the License.
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_RoomPreviewBar_warning {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mx_RoomPreviewBar_warningIcon {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ limitations under the License.
|
||||
.mx_RoomSettings .mx_RoomSettings_alias {
|
||||
max-width: 400px;
|
||||
margin-bottom: 16px;
|
||||
/*
|
||||
/*
|
||||
commented out so margin applies
|
||||
display: table-cell; */
|
||||
}
|
||||
@@ -130,6 +130,13 @@ limitations under the License.
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_warning {
|
||||
color: #ff0064;
|
||||
font-weight: bold;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mx_RoomSettings_editable {
|
||||
border: 0px;
|
||||
border-bottom: 1px solid #c7c7c7;
|
||||
|
||||
@@ -39,7 +39,7 @@ limitations under the License.
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 16px;
|
||||
padding-right: 16px;
|
||||
color: rgba(69, 69, 69, 0.8);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ limitations under the License.
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_badge {
|
||||
.mx_RoomTile_badge {
|
||||
background-color: #76cfa6;
|
||||
color: #fff;
|
||||
border-radius: 26px;
|
||||
@@ -84,7 +84,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
.mx_RoomTile_badge {
|
||||
.mx_RoomTile_badge {
|
||||
background-color: #ff0064;
|
||||
border: 3px solid #fff;
|
||||
border-radius: 16px;
|
||||
@@ -103,7 +103,7 @@ limitations under the License.
|
||||
left: 0px;
|
||||
top: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RoomTile_unreadNotify .mx_RoomTile_badge {
|
||||
background-color: #454545;
|
||||
|
||||
@@ -51,13 +51,13 @@ limitations under the License.
|
||||
flex: 1;
|
||||
-webkit-flex: 1;
|
||||
|
||||
overflow-y: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_SearchableEntityList_list {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx_SearchableEntityList_list .mx_EntityTile_chevron {
|
||||
@@ -67,7 +67,7 @@ limitations under the License.
|
||||
.mx_SearchableEntityList_hrWrapper {
|
||||
width: 100%;
|
||||
flex: 0 0 auto;
|
||||
-webkit-flex: 0 0 auto;
|
||||
-webkit-flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.mx_SearchableEntityList hr {
|
||||
|
||||
@@ -22,22 +22,22 @@ limitations under the License.
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_scrollUp {
|
||||
.mx_TopUnreadMessagesBar_scrollUp {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_scrollUp img {
|
||||
.mx_TopUnreadMessagesBar_scrollUp img {
|
||||
padding-left: 10px;
|
||||
padding-right: 31px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_scrollUp span {
|
||||
.mx_TopUnreadMessagesBar_scrollUp span {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_TopUnreadMessagesBar_close {
|
||||
.mx_TopUnreadMessagesBar_close {
|
||||
float: right;
|
||||
padding-right: 14px;
|
||||
padding-top: 3px;
|
||||
|
||||
@@ -35,7 +35,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_LeftPanel_callView {
|
||||
|
||||
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_RoomList_scrollbar {
|
||||
@@ -48,7 +48,7 @@ limitations under the License.
|
||||
-webkit-flex: 1 1 0;
|
||||
flex: 1 1 0;
|
||||
|
||||
overflow-y: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_BottomLeftMenu {
|
||||
|
||||
@@ -49,7 +49,7 @@ limitations under the License.
|
||||
.mx_RightPanel_headerButton {
|
||||
cursor: pointer;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
vertical-align: middle;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
position: relative;
|
||||
@@ -72,7 +72,7 @@ limitations under the License.
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 28px;
|
||||
font-size: 12px;
|
||||
font-size: 12px;
|
||||
background-color: #76cfa6;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -26,21 +26,21 @@ limitations under the License.
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_list {
|
||||
-webkit-flex: 1;
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
@@ -59,7 +59,7 @@ limitations under the License.
|
||||
|
||||
.mx_RoomDirectory_tableWrapper {
|
||||
overflow-y: auto;
|
||||
-webkit-flex: 1 1 0;
|
||||
-webkit-flex: 1 1 0;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ limitations under the License.
|
||||
.mx_RoomDirectory_roomMemberCount {
|
||||
text-align: right;
|
||||
width: 100px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.mx_RoomDirectory_table tr {
|
||||
|
||||
@@ -52,7 +52,7 @@ limitations under the License.
|
||||
|
||||
.mx_SearchBar_searching img {
|
||||
animation: pulsate 0.5s ease-out;
|
||||
animation-iteration-count: infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.mx_SearchBar_button {
|
||||
@@ -77,7 +77,7 @@ limitations under the License.
|
||||
background-color: #fff;
|
||||
color: #76CFA6;
|
||||
border: #76CFA6 1px solid;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SearchBar_cancel {
|
||||
padding-left: 14px;
|
||||
|
||||
@@ -184,7 +184,7 @@ function loadApp() {
|
||||
}} />,
|
||||
document.getElementById('matrixchat')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadApp();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user