mirror of
https://github.com/element-hq/element-web
synced 2024-11-25 02:35:48 +03:00
merge conflict
This commit is contained in:
commit
765174a600
15 changed files with 611 additions and 163 deletions
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var ContentRepo = require("matrix-js-sdk").ContentRepo;
|
||||||
var MatrixClientPeg = require('./MatrixClientPeg');
|
var MatrixClientPeg = require('./MatrixClientPeg');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -37,6 +37,17 @@ module.exports = {
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
avatarUrlForUser: function(user, width, height, resizeMethod) {
|
||||||
|
var url = ContentRepo.getHttpUriForMxc(
|
||||||
|
MatrixClientPeg.get().getHomeserverUrl(), user.avatarUrl,
|
||||||
|
width, height, resizeMethod
|
||||||
|
);
|
||||||
|
if (!url || url.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
defaultAvatarUrlForString: function(s) {
|
defaultAvatarUrlForString: function(s) {
|
||||||
var images = [ '76cfa6', '50e2c2', 'f4c371' ];
|
var images = [ '76cfa6', '50e2c2', 'f4c371' ];
|
||||||
var total = 0;
|
var total = 0;
|
||||||
|
|
107
src/Entities.js
Normal file
107
src/Entities.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var React = require('react');
|
||||||
|
var sdk = require('./index');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts various data models to Entity objects.
|
||||||
|
*
|
||||||
|
* Entity objects provide an interface for UI components to use to display
|
||||||
|
* members in a data-agnostic way. This means they don't need to care if the
|
||||||
|
* underlying data model is a RoomMember, User or 3PID data structure, it just
|
||||||
|
* cares about rendering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Entity {
|
||||||
|
constructor(model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
getJsx() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(queryString) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemberEntity extends Entity {
|
||||||
|
getJsx() {
|
||||||
|
var MemberTile = sdk.getComponent("rooms.MemberTile");
|
||||||
|
return (
|
||||||
|
<MemberTile key={this.model.userId} member={this.model} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(queryString) {
|
||||||
|
return this.model.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserEntity extends Entity {
|
||||||
|
|
||||||
|
constructor(model, showInviteButton, inviteFn) {
|
||||||
|
super(model);
|
||||||
|
this.showInviteButton = Boolean(showInviteButton);
|
||||||
|
this.inviteFn = inviteFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
if (this.inviteFn) {
|
||||||
|
this.inviteFn(this.model.userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getJsx() {
|
||||||
|
var UserTile = sdk.getComponent("rooms.UserTile");
|
||||||
|
return (
|
||||||
|
<UserTile key={this.model.userId} user={this.model}
|
||||||
|
showInviteButton={this.showInviteButton} onClick={this.onClick.bind(this)} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
matches(queryString) {
|
||||||
|
var name = this.model.displayName || this.model.userId;
|
||||||
|
return name.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* @param {RoomMember[]} members
|
||||||
|
* @return {Entity[]}
|
||||||
|
*/
|
||||||
|
fromRoomMembers: function(members) {
|
||||||
|
return members.map(function(m) {
|
||||||
|
return new MemberEntity(m);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {User[]} users
|
||||||
|
* @param {boolean} showInviteButton
|
||||||
|
* @param {Function} inviteFn Called with the user ID.
|
||||||
|
* @return {Entity[]}
|
||||||
|
*/
|
||||||
|
fromUsers: function(users, showInviteButton, inviteFn) {
|
||||||
|
return users.map(function(u) {
|
||||||
|
return new UserEntity(u, showInviteButton, inviteFn);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
|
@ -23,6 +23,9 @@ limitations under the License.
|
||||||
|
|
||||||
module.exports.components = {};
|
module.exports.components = {};
|
||||||
module.exports.components['structures.CreateRoom'] = require('./components/structures/CreateRoom');
|
module.exports.components['structures.CreateRoom'] = require('./components/structures/CreateRoom');
|
||||||
|
module.exports.components['structures.login.Login'] = require('./components/structures/login/Login');
|
||||||
|
module.exports.components['structures.login.PostRegistration'] = require('./components/structures/login/PostRegistration');
|
||||||
|
module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration');
|
||||||
module.exports.components['structures.MatrixChat'] = require('./components/structures/MatrixChat');
|
module.exports.components['structures.MatrixChat'] = require('./components/structures/MatrixChat');
|
||||||
module.exports.components['structures.RoomView'] = require('./components/structures/RoomView');
|
module.exports.components['structures.RoomView'] = require('./components/structures/RoomView');
|
||||||
module.exports.components['structures.ScrollPanel'] = require('./components/structures/ScrollPanel');
|
module.exports.components['structures.ScrollPanel'] = require('./components/structures/ScrollPanel');
|
||||||
|
@ -41,6 +44,7 @@ module.exports.components['views.create_room.RoomAlias'] = require('./components
|
||||||
module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog');
|
module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog');
|
||||||
module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt');
|
module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt');
|
||||||
module.exports.components['views.dialogs.QuestionDialog'] = require('./components/views/dialogs/QuestionDialog');
|
module.exports.components['views.dialogs.QuestionDialog'] = require('./components/views/dialogs/QuestionDialog');
|
||||||
|
module.exports.components['views.dialogs.TextInputDialog'] = require('./components/views/dialogs/TextInputDialog');
|
||||||
module.exports.components['views.elements.EditableText'] = require('./components/views/elements/EditableText');
|
module.exports.components['views.elements.EditableText'] = require('./components/views/elements/EditableText');
|
||||||
module.exports.components['views.elements.PowerSelector'] = require('./components/views/elements/PowerSelector');
|
module.exports.components['views.elements.PowerSelector'] = require('./components/views/elements/PowerSelector');
|
||||||
module.exports.components['views.elements.ProgressBar'] = require('./components/views/elements/ProgressBar');
|
module.exports.components['views.elements.ProgressBar'] = require('./components/views/elements/ProgressBar');
|
||||||
|
@ -54,13 +58,14 @@ module.exports.components['views.login.LoginHeader'] = require('./components/vie
|
||||||
module.exports.components['views.login.PasswordLogin'] = require('./components/views/login/PasswordLogin');
|
module.exports.components['views.login.PasswordLogin'] = require('./components/views/login/PasswordLogin');
|
||||||
module.exports.components['views.login.RegistrationForm'] = require('./components/views/login/RegistrationForm');
|
module.exports.components['views.login.RegistrationForm'] = require('./components/views/login/RegistrationForm');
|
||||||
module.exports.components['views.login.ServerConfig'] = require('./components/views/login/ServerConfig');
|
module.exports.components['views.login.ServerConfig'] = require('./components/views/login/ServerConfig');
|
||||||
|
module.exports.components['views.messages.MessageEvent'] = require('./components/views/messages/MessageEvent');
|
||||||
module.exports.components['views.messages.MFileBody'] = require('./components/views/messages/MFileBody');
|
module.exports.components['views.messages.MFileBody'] = require('./components/views/messages/MFileBody');
|
||||||
module.exports.components['views.messages.MImageBody'] = require('./components/views/messages/MImageBody');
|
module.exports.components['views.messages.MImageBody'] = require('./components/views/messages/MImageBody');
|
||||||
module.exports.components['views.messages.MVideoBody'] = require('./components/views/messages/MVideoBody');
|
module.exports.components['views.messages.MVideoBody'] = require('./components/views/messages/MVideoBody');
|
||||||
module.exports.components['views.messages.MessageEvent'] = require('./components/views/messages/MessageEvent');
|
|
||||||
module.exports.components['views.messages.TextualBody'] = require('./components/views/messages/TextualBody');
|
module.exports.components['views.messages.TextualBody'] = require('./components/views/messages/TextualBody');
|
||||||
module.exports.components['views.messages.TextualEvent'] = require('./components/views/messages/TextualEvent');
|
module.exports.components['views.messages.TextualEvent'] = require('./components/views/messages/TextualEvent');
|
||||||
module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody');
|
module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody');
|
||||||
|
module.exports.components['views.rooms.EntityTile'] = require('./components/views/rooms/EntityTile');
|
||||||
module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile');
|
module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile');
|
||||||
module.exports.components['views.rooms.MemberInfo'] = require('./components/views/rooms/MemberInfo');
|
module.exports.components['views.rooms.MemberInfo'] = require('./components/views/rooms/MemberInfo');
|
||||||
module.exports.components['views.rooms.MemberList'] = require('./components/views/rooms/MemberList');
|
module.exports.components['views.rooms.MemberList'] = require('./components/views/rooms/MemberList');
|
||||||
|
@ -72,8 +77,10 @@ module.exports.components['views.rooms.RoomList'] = require('./components/views/
|
||||||
module.exports.components['views.rooms.RoomPreviewBar'] = require('./components/views/rooms/RoomPreviewBar');
|
module.exports.components['views.rooms.RoomPreviewBar'] = require('./components/views/rooms/RoomPreviewBar');
|
||||||
module.exports.components['views.rooms.RoomSettings'] = require('./components/views/rooms/RoomSettings');
|
module.exports.components['views.rooms.RoomSettings'] = require('./components/views/rooms/RoomSettings');
|
||||||
module.exports.components['views.rooms.RoomTile'] = require('./components/views/rooms/RoomTile');
|
module.exports.components['views.rooms.RoomTile'] = require('./components/views/rooms/RoomTile');
|
||||||
|
module.exports.components['views.rooms.SearchableEntityList'] = require('./components/views/rooms/SearchableEntityList');
|
||||||
module.exports.components['views.rooms.SearchResultTile'] = require('./components/views/rooms/SearchResultTile');
|
module.exports.components['views.rooms.SearchResultTile'] = require('./components/views/rooms/SearchResultTile');
|
||||||
module.exports.components['views.rooms.TabCompleteBar'] = require('./components/views/rooms/TabCompleteBar');
|
module.exports.components['views.rooms.TabCompleteBar'] = require('./components/views/rooms/TabCompleteBar');
|
||||||
|
module.exports.components['views.rooms.UserTile'] = require('./components/views/rooms/UserTile');
|
||||||
module.exports.components['views.settings.ChangeAvatar'] = require('./components/views/settings/ChangeAvatar');
|
module.exports.components['views.settings.ChangeAvatar'] = require('./components/views/settings/ChangeAvatar');
|
||||||
module.exports.components['views.settings.ChangeDisplayName'] = require('./components/views/settings/ChangeDisplayName');
|
module.exports.components['views.settings.ChangeDisplayName'] = require('./components/views/settings/ChangeDisplayName');
|
||||||
module.exports.components['views.settings.ChangePassword'] = require('./components/views/settings/ChangePassword');
|
module.exports.components['views.settings.ChangePassword'] = require('./components/views/settings/ChangePassword');
|
||||||
|
|
|
@ -119,7 +119,7 @@ module.exports = React.createClass({
|
||||||
console.log("Attempting to peek into room %s", this.props.roomId);
|
console.log("Attempting to peek into room %s", this.props.roomId);
|
||||||
MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => {
|
MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
autoPeekDone: true;
|
autoPeekDone: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// we don't need to do anything - JS SDK will emit Room events
|
// we don't need to do anything - JS SDK will emit Room events
|
||||||
|
@ -129,20 +129,6 @@ module.exports = React.createClass({
|
||||||
if (!peekedRoom) {
|
if (!peekedRoom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var guestAccessEvent = peekedRoom.currentState.getStateEvents("m.room.guest_access", "");
|
|
||||||
if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") {
|
|
||||||
this.setState({
|
|
||||||
guestsCanJoin: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var historyVisibility = peekedRoom.currentState.getStateEvents("m.room.history_visibility", "");
|
|
||||||
if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") {
|
|
||||||
this.setState({
|
|
||||||
canPeek: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
console.error("Failed to peek into room: %s", err);
|
console.error("Failed to peek into room: %s", err);
|
||||||
});
|
});
|
||||||
|
@ -298,6 +284,20 @@ module.exports = React.createClass({
|
||||||
this.setState({
|
this.setState({
|
||||||
room: room
|
room: room
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", "");
|
||||||
|
if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") {
|
||||||
|
this.setState({
|
||||||
|
guestsCanJoin: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var historyVisibility = room.currentState.getStateEvents("m.room.history_visibility", "");
|
||||||
|
if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") {
|
||||||
|
this.setState({
|
||||||
|
canPeek: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -960,7 +960,6 @@ module.exports = React.createClass({
|
||||||
this.state.room.roomId, "m.room.history_visibility", {
|
this.state.room.roomId, "m.room.history_visibility", {
|
||||||
history_visibility: newVals.history_visibility,
|
history_visibility: newVals.history_visibility,
|
||||||
}, ""
|
}, ""
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +984,13 @@ module.exports = React.createClass({
|
||||||
deferreds.push(visibilityDeferred);
|
deferreds.push(visibilityDeferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setRoomMutePushRule will do nothing if there is no change
|
||||||
|
deferreds.push(
|
||||||
|
MatrixClientPeg.get().setRoomMutePushRule(
|
||||||
|
"global", this.state.room.roomId, newVals.are_notifications_muted
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (newVals.power_levels) {
|
if (newVals.power_levels) {
|
||||||
deferreds.push(
|
deferreds.push(
|
||||||
MatrixClientPeg.get().sendStateEvent(
|
MatrixClientPeg.get().sendStateEvent(
|
||||||
|
@ -1179,6 +1185,7 @@ module.exports = React.createClass({
|
||||||
topic: this.refs.header.getTopic(),
|
topic: this.refs.header.getTopic(),
|
||||||
join_rule: this.refs.room_settings.getJoinRules(),
|
join_rule: this.refs.room_settings.getJoinRules(),
|
||||||
history_visibility: this.refs.room_settings.getHistoryVisibility(),
|
history_visibility: this.refs.room_settings.getHistoryVisibility(),
|
||||||
|
are_notifications_muted: this.refs.room_settings.areNotificationsMuted(),
|
||||||
power_levels: this.refs.room_settings.getPowerLevels(),
|
power_levels: this.refs.room_settings.getPowerLevels(),
|
||||||
alias_operations: this.refs.room_settings.getAliasOperations(),
|
alias_operations: this.refs.room_settings.getAliasOperations(),
|
||||||
tag_operations: this.refs.room_settings.getTagOperations(),
|
tag_operations: this.refs.room_settings.getTagOperations(),
|
||||||
|
@ -1426,6 +1433,7 @@ module.exports = React.createClass({
|
||||||
if (!this.state.room) {
|
if (!this.state.room) {
|
||||||
if (this.props.roomId) {
|
if (this.props.roomId) {
|
||||||
if (this.props.autoPeek && !this.state.autoPeekDone) {
|
if (this.props.autoPeek && !this.state.autoPeekDone) {
|
||||||
|
var Loader = sdk.getComponent("elements.Spinner");
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomView">
|
<div className="mx_RoomView">
|
||||||
<Loader />
|
<Loader />
|
||||||
|
|
|
@ -152,10 +152,6 @@ module.exports = React.createClass({
|
||||||
this.logoutModal.closeDialog();
|
this.logoutModal.closeDialog();
|
||||||
},
|
},
|
||||||
|
|
||||||
onEnableNotificationsChange: function(event) {
|
|
||||||
UserSettingsStore.setEnableNotifications(event.target.checked);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
switch (this.state.phase) {
|
switch (this.state.phase) {
|
||||||
case "UserSettings.LOADING":
|
case "UserSettings.LOADING":
|
||||||
|
@ -173,6 +169,7 @@ module.exports = React.createClass({
|
||||||
var ChangeDisplayName = sdk.getComponent("views.settings.ChangeDisplayName");
|
var ChangeDisplayName = sdk.getComponent("views.settings.ChangeDisplayName");
|
||||||
var ChangePassword = sdk.getComponent("views.settings.ChangePassword");
|
var ChangePassword = sdk.getComponent("views.settings.ChangePassword");
|
||||||
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
||||||
|
var Notifications = sdk.getComponent("settings.Notifications");
|
||||||
var avatarUrl = (
|
var avatarUrl = (
|
||||||
this.state.avatarUrl ? MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl) : null
|
this.state.avatarUrl ? MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl) : null
|
||||||
);
|
);
|
||||||
|
@ -263,22 +260,7 @@ module.exports = React.createClass({
|
||||||
<h2>Notifications</h2>
|
<h2>Notifications</h2>
|
||||||
|
|
||||||
<div className="mx_UserSettings_section">
|
<div className="mx_UserSettings_section">
|
||||||
<div className="mx_UserSettings_notifTable">
|
<Notifications/>
|
||||||
<div className="mx_UserSettings_notifTableRow">
|
|
||||||
<div className="mx_UserSettings_notifInputCell">
|
|
||||||
<input id="enableNotifications"
|
|
||||||
ref="enableNotifications"
|
|
||||||
type="checkbox"
|
|
||||||
checked={ UserSettingsStore.getEnableNotifications() }
|
|
||||||
onChange={ this.onEnableNotificationsChange } />
|
|
||||||
</div>
|
|
||||||
<div className="mx_UserSettings_notifLabelCell">
|
|
||||||
<label htmlFor="enableNotifications">
|
|
||||||
Enable desktop notifications
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Advanced</h2>
|
<h2>Advanced</h2>
|
||||||
|
|
|
@ -48,7 +48,7 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="mx_ErrorDialog">
|
<div className="mx_ErrorDialog">
|
||||||
<div className="mx_ErrorDialogTitle">
|
<div className="mx_Dialog_title">
|
||||||
{this.props.title}
|
{this.props.title}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
|
|
|
@ -46,7 +46,7 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="mx_QuestionDialog">
|
<div className="mx_QuestionDialog">
|
||||||
<div className="mx_QuestionDialogTitle">
|
<div className="mx_Dialog_title">
|
||||||
{this.props.title}
|
{this.props.title}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
|
|
94
src/components/views/dialogs/TextInputDialog.js
Normal file
94
src/components/views/dialogs/TextInputDialog.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var React = require("react");
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'TextInputDialog',
|
||||||
|
propTypes: {
|
||||||
|
title: React.PropTypes.string,
|
||||||
|
description: React.PropTypes.string,
|
||||||
|
value: React.PropTypes.string,
|
||||||
|
button: React.PropTypes.string,
|
||||||
|
focus: React.PropTypes.bool,
|
||||||
|
onFinished: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
title: "",
|
||||||
|
value: "",
|
||||||
|
description: "",
|
||||||
|
button: "OK",
|
||||||
|
focus: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
if (this.props.focus) {
|
||||||
|
// Set the cursor at the end of the text input
|
||||||
|
this.refs.textinput.value = this.props.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onOk: function() {
|
||||||
|
this.props.onFinished(true, this.refs.textinput.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
onCancel: function() {
|
||||||
|
this.props.onFinished(false);
|
||||||
|
},
|
||||||
|
|
||||||
|
onKeyDown: function(e) {
|
||||||
|
if (e.keyCode === 27) { // escape
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}
|
||||||
|
else if (e.keyCode === 13) { // enter
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onFinished(true, this.refs.textinput.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div className="mx_TextInputDialog">
|
||||||
|
<div className="mx_Dialog_title">
|
||||||
|
{this.props.title}
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<div className="mx_TextInputDialog_label">
|
||||||
|
<label htmlFor="textinput"> {this.props.description} </label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="textinput" ref="textinput" className="mx_TextInputDialog_input" defaultValue={this.props.value} autoFocus={this.props.focus} size="64" onKeyDown={this.onKeyDown}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button onClick={this.onOk}>
|
||||||
|
{this.props.button}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button onClick={this.onCancel}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
|
@ -22,7 +22,7 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="mx_ErrorDialog">
|
<div className="mx_ErrorDialog">
|
||||||
<div className="mx_ErrorDialogTitle">
|
<div className="mx_Dialog_title">
|
||||||
Custom Server Options
|
Custom Server Options
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
|
|
139
src/components/views/rooms/EntityTile.js
Normal file
139
src/components/views/rooms/EntityTile.js
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
|
var sdk = require('../../../index');
|
||||||
|
|
||||||
|
|
||||||
|
var PRESENCE_CLASS = {
|
||||||
|
"offline": "mx_EntityTile_offline",
|
||||||
|
"online": "mx_EntityTile_online",
|
||||||
|
"unavailable": "mx_EntityTile_unavailable"
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'EntityTile',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
name: React.PropTypes.string,
|
||||||
|
title: React.PropTypes.string,
|
||||||
|
avatarJsx: React.PropTypes.any, // <BaseAvatar />
|
||||||
|
presenceState: React.PropTypes.string,
|
||||||
|
presenceActiveAgo: React.PropTypes.number,
|
||||||
|
showInviteButton: React.PropTypes.bool,
|
||||||
|
shouldComponentUpdate: React.PropTypes.func,
|
||||||
|
onClick: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
shouldComponentUpdate: function(nextProps, nextState) { return false; },
|
||||||
|
onClick: function() {},
|
||||||
|
presenceState: "offline",
|
||||||
|
presenceActiveAgo: -1,
|
||||||
|
showInviteButton: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
hover: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldComponentUpdate: function(nextProps, nextState) {
|
||||||
|
if (this.state.hover !== nextState.hover) return true;
|
||||||
|
return this.props.shouldComponentUpdate(nextProps, nextState);
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseEnter: function(e) {
|
||||||
|
this.setState({ 'hover': true });
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseLeave: function(e) {
|
||||||
|
this.setState({ 'hover': false });
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var presenceClass = PRESENCE_CLASS[this.props.presenceState];
|
||||||
|
var mainClassName = "mx_EntityTile ";
|
||||||
|
mainClassName += presenceClass;
|
||||||
|
if (this.state.hover) {
|
||||||
|
mainClassName += " mx_EntityTile_hover";
|
||||||
|
}
|
||||||
|
|
||||||
|
var nameEl;
|
||||||
|
if (this.state.hover) {
|
||||||
|
var PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
|
||||||
|
nameEl = (
|
||||||
|
<div className="mx_EntityTile_details">
|
||||||
|
<img className="mx_EntityTile_chevron" src="img/member_chevron.png" width="8" height="12"/>
|
||||||
|
<div className="mx_EntityTile_name_hover">{ this.props.name }</div>
|
||||||
|
<PresenceLabel activeAgo={this.props.presenceActiveAgo}
|
||||||
|
presenceState={this.props.presenceState} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nameEl = (
|
||||||
|
<div className="mx_EntityTile_name">
|
||||||
|
{ this.props.name }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var inviteButton;
|
||||||
|
if (this.props.showInviteButton) {
|
||||||
|
inviteButton = (
|
||||||
|
<div className="mx_EntityTile_invite">
|
||||||
|
<img src="img/plus.svg" width="16" height="16" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var power;
|
||||||
|
var powerLevel = this.props.powerLevel;
|
||||||
|
if (powerLevel >= 50 && powerLevel < 99) {
|
||||||
|
power = <img src="img/mod.svg" className="mx_EntityTile_power" width="16" height="17" alt="Mod"/>;
|
||||||
|
}
|
||||||
|
if (powerLevel >= 99) {
|
||||||
|
power = <img src="img/admin.svg" className="mx_EntityTile_power" width="16" height="17" alt="Admin"/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||||
|
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
|
||||||
|
var av = this.props.avatarJsx || <BaseAvatar name={name} width={36} height={36} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={mainClassName} title={ this.props.title }
|
||||||
|
onClick={ this.props.onClick } onMouseEnter={ this.mouseEnter }
|
||||||
|
onMouseLeave={ this.mouseLeave }>
|
||||||
|
<div className="mx_EntityTile_avatar">
|
||||||
|
{av}
|
||||||
|
</div>
|
||||||
|
{ nameEl }
|
||||||
|
{ power }
|
||||||
|
{ inviteButton }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
|
@ -19,6 +19,7 @@ var Matrix = require("matrix-js-sdk");
|
||||||
var q = require('q');
|
var q = require('q');
|
||||||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
var Modal = require("../../../Modal");
|
var Modal = require("../../../Modal");
|
||||||
|
var Entities = require("../../../Entities");
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
var GeminiScrollbar = require('react-gemini-scrollbar');
|
var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||||
|
|
||||||
|
@ -284,6 +285,8 @@ module.exports = React.createClass({
|
||||||
// we shouldn't add them if the 3pid invite state key (token) is in the
|
// we shouldn't add them if the 3pid invite state key (token) is in the
|
||||||
// member invite (content.third_party_invite.signed.token)
|
// member invite (content.third_party_invite.signed.token)
|
||||||
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
|
var EntityTile = sdk.getComponent("rooms.EntityTile");
|
||||||
|
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
|
||||||
if (room) {
|
if (room) {
|
||||||
room.currentState.getStateEvents("m.room.third_party_invite").forEach(
|
room.currentState.getStateEvents("m.room.third_party_invite").forEach(
|
||||||
function(e) {
|
function(e) {
|
||||||
|
@ -293,9 +296,12 @@ module.exports = React.createClass({
|
||||||
if (memberEvent) {
|
if (memberEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var avatarJsx = (
|
||||||
|
<BaseAvatar name={e.getContent().display_name} width={36} height={36} />
|
||||||
|
);
|
||||||
memberList.push(
|
memberList.push(
|
||||||
<MemberTile key={e.getStateKey()} ref={e.getStateKey()}
|
<EntityTile key={e.getStateKey()} ref={e.getStateKey()}
|
||||||
customDisplayName={e.getContent().display_name} />
|
name={e.getContent().display_name} avatarJsx={avatarJsx} />
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -304,11 +310,6 @@ module.exports = React.createClass({
|
||||||
return memberList;
|
return memberList;
|
||||||
},
|
},
|
||||||
|
|
||||||
onPopulateInvite: function(e) {
|
|
||||||
this.onInvite(this.refs.invite.value);
|
|
||||||
e.preventDefault();
|
|
||||||
},
|
|
||||||
|
|
||||||
inviteTile: function() {
|
inviteTile: function() {
|
||||||
if (this.state.inviting) {
|
if (this.state.inviting) {
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
var Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
@ -316,10 +317,25 @@ module.exports = React.createClass({
|
||||||
<Loader />
|
<Loader />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: Cache this calculation
|
||||||
|
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
|
var allUsers = MatrixClientPeg.get().getUsers();
|
||||||
|
// only add Users if they are not joined
|
||||||
|
allUsers = allUsers.filter(function(u) {
|
||||||
|
return !room.hasMembershipState(u.userId, "join");
|
||||||
|
});
|
||||||
|
var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.onPopulateInvite}>
|
<SearchableEntityList searchPlaceholderText={"Invite / Search"}
|
||||||
<input className="mx_MemberList_invite" ref="invite" id="mx_MemberList_invite" placeholder="Invite user (email)"/>
|
onSubmit={this.onInvite}
|
||||||
</form>
|
entities={
|
||||||
|
Entities.fromRoomMembers(
|
||||||
|
room.getJoinedMembers()
|
||||||
|
).concat(
|
||||||
|
Entities.fromUsers(allUsers, true, this.onInvite)
|
||||||
|
)
|
||||||
|
} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,9 +27,7 @@ module.exports = React.createClass({
|
||||||
displayName: 'MemberTile',
|
displayName: 'MemberTile',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
member: React.PropTypes.any, // RoomMember
|
member: React.PropTypes.any.isRequired, // RoomMember
|
||||||
onFinished: React.PropTypes.func,
|
|
||||||
customDisplayName: React.PropTypes.string // for 3pid invites
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -37,13 +35,11 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldComponentUpdate: function(nextProps, nextState) {
|
shouldComponentUpdate: function(nextProps, nextState) {
|
||||||
if (this.state.hover !== nextState.hover) return true;
|
|
||||||
if (!this.props.member) { return false; } // e.g. 3pid members
|
|
||||||
if (
|
if (
|
||||||
this.member_last_modified_time === undefined ||
|
this.member_last_modified_time === undefined ||
|
||||||
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
|
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
|
||||||
) {
|
) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
nextProps.member.user &&
|
nextProps.member.user &&
|
||||||
|
@ -55,17 +51,7 @@ module.exports = React.createClass({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
mouseEnter: function(e) {
|
|
||||||
this.setState({ 'hover': true });
|
|
||||||
},
|
|
||||||
|
|
||||||
mouseLeave: function(e) {
|
|
||||||
this.setState({ 'hover': false });
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function(e) {
|
onClick: function(e) {
|
||||||
if (!this.props.member) { return; } // e.g. 3pid members
|
|
||||||
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_user',
|
action: 'view_user',
|
||||||
member: this.props.member,
|
member: this.props.member,
|
||||||
|
@ -73,53 +59,27 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_getDisplayName: function() {
|
_getDisplayName: function() {
|
||||||
if (this.props.customDisplayName) {
|
|
||||||
return this.props.customDisplayName;
|
|
||||||
}
|
|
||||||
return this.props.member.name;
|
return this.props.member.name;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPowerLabel: function() {
|
getPowerLabel: function() {
|
||||||
if (!this.props.member) {
|
return this.props.member.userId + " (power " + this.props.member.powerLevel + ")";
|
||||||
return this._getDisplayName();
|
|
||||||
}
|
|
||||||
var label = this.props.member.userId + " (power " + this.props.member.powerLevel + ")";
|
|
||||||
return label;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||||
|
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
var EntityTile = sdk.getComponent('rooms.EntityTile');
|
||||||
|
|
||||||
var member = this.props.member;
|
var member = this.props.member;
|
||||||
var isMyUser = false;
|
|
||||||
var name = this._getDisplayName();
|
var name = this._getDisplayName();
|
||||||
var active = -1;
|
var active = -1;
|
||||||
var presenceClass = "mx_MemberTile_offline";
|
var presenceState = member.user ? member.user.presence : null;
|
||||||
|
|
||||||
if (member) {
|
var av = (
|
||||||
if (member.user) {
|
<MemberAvatar member={member} width={36} height={36} />
|
||||||
this.user_last_modified_time = member.user.getLastModifiedTime();
|
|
||||||
|
|
||||||
// FIXME: make presence data update whenever User.presence changes...
|
|
||||||
active = (
|
|
||||||
(Date.now() - (member.user.lastPresenceTs - member.user.lastActiveAgo)) || -1
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (member.user.presence === "online") {
|
|
||||||
presenceClass = "mx_MemberTile_online";
|
|
||||||
}
|
|
||||||
else if (member.user.presence === "unavailable") {
|
|
||||||
presenceClass = "mx_MemberTile_unavailable";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.member_last_modified_time = member.getLastModifiedTime();
|
|
||||||
isMyUser = MatrixClientPeg.get().credentials.userId == member.userId;
|
|
||||||
|
|
||||||
// if (this.props.member && this.props.member.powerLevelNorm > 0) {
|
|
||||||
// var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
|
|
||||||
// power = <img src={ img } className="mx_MemberTile_power" width="44" height="44" alt=""/>;
|
|
||||||
// }
|
|
||||||
|
|
||||||
var power;
|
var power;
|
||||||
if (this.props.member) {
|
|
||||||
var powerLevel = this.props.member.powerLevel;
|
var powerLevel = this.props.member.powerLevel;
|
||||||
if (powerLevel >= 50 && powerLevel < 99) {
|
if (powerLevel >= 50 && powerLevel < 99) {
|
||||||
power = <img src="img/mod.svg" className="mx_MemberTile_power" width="16" height="17" alt="Mod"/>;
|
power = <img src="img/mod.svg" className="mx_MemberTile_power" width="16" height="17" alt="Mod"/>;
|
||||||
|
@ -127,61 +87,22 @@ module.exports = React.createClass({
|
||||||
if (powerLevel >= 99) {
|
if (powerLevel >= 99) {
|
||||||
power = <img src="img/admin.svg" className="mx_MemberTile_power" width="16" height="17" alt="Admin"/>;
|
power = <img src="img/admin.svg" className="mx_MemberTile_power" width="16" height="17" alt="Admin"/>;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mainClassName = "mx_MemberTile ";
|
if (member.user) {
|
||||||
mainClassName += presenceClass;
|
this.user_last_modified_time = member.user.getLastModifiedTime();
|
||||||
if (this.state.hover) {
|
|
||||||
mainClassName += " mx_MemberTile_hover";
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameEl;
|
// FIXME: make presence data update whenever User.presence changes...
|
||||||
if (this.state.hover && this.props.member) {
|
active = (
|
||||||
var presenceState = (member && member.user) ? member.user.presence : null;
|
(Date.now() - (member.user.lastPresenceTs - member.user.lastActiveAgo)) || -1
|
||||||
var PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
|
|
||||||
nameEl = (
|
|
||||||
<div className="mx_MemberTile_details">
|
|
||||||
<img className="mx_MemberTile_chevron" src="img/member_chevron.png" width="8" height="12"/>
|
|
||||||
<div className="mx_MemberTile_userId">{ name }</div>
|
|
||||||
<PresenceLabel activeAgo={active}
|
|
||||||
presenceState={presenceState} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nameEl = (
|
|
||||||
<div className="mx_MemberTile_name">
|
|
||||||
{ name }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
|
||||||
|
|
||||||
var av;
|
|
||||||
if (member) {
|
|
||||||
av = (
|
|
||||||
<MemberAvatar member={this.props.member} width={36} height={36} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
av = (
|
|
||||||
<BaseAvatar name={name} width={36} height={36} />
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
this.member_last_modified_time = member.getLastModifiedTime();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={mainClassName} title={ this.getPowerLabel() }
|
<EntityTile {...this.props} presenceActiveAgo={active} presenceState={presenceState}
|
||||||
onClick={ this.onClick } onMouseEnter={ this.mouseEnter }
|
avatarJsx={av} title={this.getPowerLabel()} onClick={this.onClick}
|
||||||
onMouseLeave={ this.mouseLeave }>
|
shouldComponentUpdate={this.shouldComponentUpdate.bind(this)}
|
||||||
<div className="mx_MemberTile_avatar">
|
name={name} powerLevel={this.props.member.powerLevel} />
|
||||||
{ av }
|
|
||||||
{ power }
|
|
||||||
</div>
|
|
||||||
{ nameEl }
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -128,6 +128,10 @@ module.exports = React.createClass({
|
||||||
return this.refs.share_history.checked ? "shared" : "invited";
|
return this.refs.share_history.checked ? "shared" : "invited";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
areNotificationsMuted: function() {
|
||||||
|
return this.refs.are_notifications_muted.checked;
|
||||||
|
},
|
||||||
|
|
||||||
getPowerLevels: function() {
|
getPowerLevels: function() {
|
||||||
if (!this.state.power_levels_changed) return undefined;
|
if (!this.state.power_levels_changed) return undefined;
|
||||||
|
|
||||||
|
@ -387,10 +391,19 @@ module.exports = React.createClass({
|
||||||
guest_access = guest_access.getContent().guest_access;
|
guest_access = guest_access.getContent().guest_access;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var are_notifications_muted;
|
||||||
|
var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId);
|
||||||
|
if (roomPushRule) {
|
||||||
|
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
||||||
|
are_notifications_muted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var events_levels = (power_levels ? power_levels.events : {}) || {};
|
var events_levels = (power_levels ? power_levels.events : {}) || {};
|
||||||
|
|
||||||
var user_id = MatrixClientPeg.get().credentials.userId;
|
var user_id = MatrixClientPeg.get().credentials.userId;
|
||||||
|
|
||||||
|
|
||||||
if (power_levels) {
|
if (power_levels) {
|
||||||
power_levels = power_levels.getContent();
|
power_levels = power_levels.getContent();
|
||||||
|
|
||||||
|
@ -675,6 +688,11 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
{ aliases_section }
|
{ aliases_section }
|
||||||
|
|
||||||
|
<h3>Notifications</h3>
|
||||||
|
<div className="mx_RoomSettings_settings">
|
||||||
|
<label><input type="checkbox" ref="are_notifications_muted" defaultChecked={are_notifications_muted}/> Mute notifications for this room</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3>Permissions</h3>
|
<h3>Permissions</h3>
|
||||||
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
|
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
|
||||||
<div className="mx_RoomSettings_powerLevel">
|
<div className="mx_RoomSettings_powerLevel">
|
||||||
|
|
89
src/components/views/rooms/SearchableEntityList.js
Normal file
89
src/components/views/rooms/SearchableEntityList.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
var React = require('react');
|
||||||
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
|
var Modal = require("../../../Modal");
|
||||||
|
var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||||
|
|
||||||
|
// A list capable of displaying entities which conform to the SearchableEntity
|
||||||
|
// interface which is an object containing getJsx(): Jsx and matches(query: string): boolean
|
||||||
|
var SearchableEntityList = React.createClass({
|
||||||
|
displayName: 'SearchableEntityList',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
searchPlaceholderText: React.PropTypes.string,
|
||||||
|
emptyQueryShowsAll: React.PropTypes.bool,
|
||||||
|
onSubmit: React.PropTypes.func, // fn(inputText)
|
||||||
|
entities: React.PropTypes.array
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
searchPlaceholderText: "Search",
|
||||||
|
entities: [],
|
||||||
|
emptyQueryShowsAll: false,
|
||||||
|
onSubmit: function() {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
query: "",
|
||||||
|
results: this.getSearchResults("")
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onQueryChanged: function(ev) {
|
||||||
|
var q = ev.target.value;
|
||||||
|
this.setState({
|
||||||
|
query: q,
|
||||||
|
results: this.getSearchResults(q)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onQuerySubmit: function(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.props.onSubmit(this.state.query);
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchResults: function(query) {
|
||||||
|
if (!query || query.length === 0) {
|
||||||
|
return this.props.emptyQueryShowsAll ? this.props.entities : []
|
||||||
|
}
|
||||||
|
return this.props.entities.filter(function(e) {
|
||||||
|
return e.matches(query);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={this.onQuerySubmit}>
|
||||||
|
<input className="mx_SearchableEntityList_query" type="text"
|
||||||
|
onChange={this.onQueryChanged} value={this.state.query}
|
||||||
|
placeholder={this.props.searchPlaceholderText} />
|
||||||
|
</form>
|
||||||
|
<div className="mx_SearchableEntityList_list">
|
||||||
|
{this.state.results.map((entity) => {
|
||||||
|
return entity.getJsx();
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = SearchableEntityList;
|
56
src/components/views/rooms/UserTile.js
Normal file
56
src/components/views/rooms/UserTile.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
var Avatar = require("../../../Avatar");
|
||||||
|
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
|
var sdk = require('../../../index');
|
||||||
|
var dis = require('../../../dispatcher');
|
||||||
|
var Modal = require("../../../Modal");
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'UserTile',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
user: React.PropTypes.any.isRequired // User
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var EntityTile = sdk.getComponent("rooms.EntityTile");
|
||||||
|
var user = this.props.user;
|
||||||
|
var name = user.displayName || user.userId;
|
||||||
|
var active = -1;
|
||||||
|
|
||||||
|
// FIXME: make presence data update whenever User.presence changes...
|
||||||
|
active = (
|
||||||
|
(Date.now() - (user.lastPresenceTs - user.lastActiveAgo)) || -1
|
||||||
|
);
|
||||||
|
|
||||||
|
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
var avatarJsx = (
|
||||||
|
<BaseAvatar width={36} height={36} name={name} idName={user.userId}
|
||||||
|
url={ Avatar.avatarUrlForUser(user, 36, 36, "crop") } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EntityTile {...this.props} presenceState={user.presence} presenceActiveAgo={active}
|
||||||
|
name={name} title={user.userId} avatarJsx={avatarJsx} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in a new issue