mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 21:24:59 +08:00
Merge pull request #141 from matrix-org/kegan/room-settings-refactor
Refactor room settings
This commit is contained in:
commit
4ce41f7f6c
@ -65,6 +65,7 @@ module.exports.components['views.messages.TextualBody'] = require('./components/
|
||||
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.room_settings.AliasSettings'] = require('./components/views/room_settings/AliasSettings');
|
||||
module.exports.components['views.room_settings.ColorSettings'] = require('./components/views/room_settings/ColorSettings');
|
||||
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.MemberInfo'] = require('./components/views/rooms/MemberInfo');
|
||||
|
@ -1116,195 +1116,6 @@ module.exports = React.createClass({
|
||||
return ret;
|
||||
},
|
||||
|
||||
uploadNewState: function(newVals) {
|
||||
var old_name = this.state.room.name;
|
||||
|
||||
var old_topic = this.state.room.currentState.getStateEvents('m.room.topic', '');
|
||||
if (old_topic) {
|
||||
old_topic = old_topic.getContent().topic;
|
||||
} else {
|
||||
old_topic = "";
|
||||
}
|
||||
|
||||
var old_join_rule = this.state.room.currentState.getStateEvents('m.room.join_rules', '');
|
||||
if (old_join_rule) {
|
||||
old_join_rule = old_join_rule.getContent().join_rule;
|
||||
} else {
|
||||
old_join_rule = "invite";
|
||||
}
|
||||
|
||||
var old_history_visibility = this.state.room.currentState.getStateEvents('m.room.history_visibility', '');
|
||||
if (old_history_visibility) {
|
||||
old_history_visibility = old_history_visibility.getContent().history_visibility;
|
||||
} else {
|
||||
old_history_visibility = "shared";
|
||||
}
|
||||
|
||||
var old_guest_read = (old_history_visibility === "world_readable");
|
||||
|
||||
var old_guest_join = this.state.room.currentState.getStateEvents('m.room.guest_access', '');
|
||||
if (old_guest_join) {
|
||||
old_guest_join = (old_guest_join.getContent().guest_access === "can_join");
|
||||
}
|
||||
else {
|
||||
old_guest_join = false;
|
||||
}
|
||||
|
||||
var deferreds = [];
|
||||
|
||||
if (old_name != newVals.name && newVals.name != undefined) {
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().setRoomName(this.state.room.roomId, newVals.name)
|
||||
);
|
||||
}
|
||||
|
||||
if (old_topic != newVals.topic && newVals.topic != undefined) {
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, newVals.topic)
|
||||
);
|
||||
}
|
||||
|
||||
if (old_join_rule != newVals.join_rule && newVals.join_rule != undefined) {
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().sendStateEvent(
|
||||
this.state.room.roomId, "m.room.join_rules", {
|
||||
join_rule: newVals.join_rule,
|
||||
}, ""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// XXX: EVIL HACK: for now, don't let Vector clobber 'joined' visibility to 'invited'
|
||||
// just because it doesn't know about 'joined' yet. In future we should fix it
|
||||
// properly - https://github.com/vector-im/vector-web/issues/731
|
||||
if (old_history_visibility === "joined") {
|
||||
old_history_visibility = "invited";
|
||||
}
|
||||
|
||||
var visibilityDeferred;
|
||||
if (old_history_visibility != newVals.history_visibility &&
|
||||
newVals.history_visibility != undefined) {
|
||||
visibilityDeferred =
|
||||
MatrixClientPeg.get().sendStateEvent(
|
||||
this.state.room.roomId, "m.room.history_visibility", {
|
||||
history_visibility: newVals.history_visibility,
|
||||
}, ""
|
||||
);
|
||||
}
|
||||
|
||||
if (old_guest_read != newVals.guest_read ||
|
||||
old_guest_join != newVals.guest_join)
|
||||
{
|
||||
var guestDeferred =
|
||||
MatrixClientPeg.get().setGuestAccess(this.state.room.roomId, {
|
||||
allowRead: newVals.guest_read,
|
||||
allowJoin: newVals.guest_join
|
||||
});
|
||||
|
||||
if (visibilityDeferred) {
|
||||
visibilityDeferred = visibilityDeferred.then(guestDeferred);
|
||||
}
|
||||
else {
|
||||
visibilityDeferred = guestDeferred;
|
||||
}
|
||||
}
|
||||
|
||||
if (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) {
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().sendStateEvent(
|
||||
this.state.room.roomId, "m.room.power_levels", newVals.power_levels, ""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (newVals.tag_operations) {
|
||||
var oplist = [];
|
||||
for (var i = 0; i < newVals.tag_operations.length; i++) {
|
||||
var tag_operation = newVals.tag_operations[i];
|
||||
switch (tag_operation.type) {
|
||||
case 'put':
|
||||
oplist.push(
|
||||
MatrixClientPeg.get().setRoomTag(
|
||||
this.props.roomId, tag_operation.tag, {}
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'delete':
|
||||
oplist.push(
|
||||
MatrixClientPeg.get().deleteRoomTag(
|
||||
this.props.roomId, tag_operation.tag
|
||||
)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown tag operation, ignoring: " + tag_operation.type);
|
||||
}
|
||||
}
|
||||
|
||||
if (oplist.length) {
|
||||
var deferred = oplist[0];
|
||||
oplist.splice(1).forEach(function (f) {
|
||||
deferred = deferred.then(f);
|
||||
});
|
||||
deferreds.push(deferred);
|
||||
}
|
||||
}
|
||||
|
||||
if (newVals.color_scheme) {
|
||||
deferreds.push(
|
||||
MatrixClientPeg.get().setRoomAccountData(
|
||||
this.state.room.roomId, "org.matrix.room.color_scheme", newVals.color_scheme
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
deferreds.push(this.refs.room_settings.saveAliases());
|
||||
|
||||
if (deferreds.length) {
|
||||
var self = this;
|
||||
q.allSettled(deferreds).then(
|
||||
function(results) {
|
||||
var fails = results.filter(function(result) { return result.state !== "fulfilled" });
|
||||
if (fails.length) {
|
||||
fails.forEach(function(result) {
|
||||
console.error(result.reason);
|
||||
});
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to set state",
|
||||
description: fails.map(function(result) { return result.reason }).join("\n"),
|
||||
});
|
||||
self.refs.room_settings.resetState();
|
||||
}
|
||||
else {
|
||||
self.setState({
|
||||
editingRoomSettings: false
|
||||
});
|
||||
}
|
||||
}).finally(function() {
|
||||
self.setState({
|
||||
uploadingRoomSettings: false,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
editingRoomSettings: false,
|
||||
uploadingRoomSettings: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_collectEventNode: function(eventId, node) {
|
||||
if (this.eventNodes == undefined) this.eventNodes = {};
|
||||
this.eventNodes[eventId] = node;
|
||||
@ -1409,23 +1220,39 @@ module.exports = React.createClass({
|
||||
this.showSettings(true);
|
||||
},
|
||||
|
||||
onSaveClick: function() {
|
||||
onSettingsSaveClick: function() {
|
||||
this.setState({
|
||||
uploadingRoomSettings: true,
|
||||
});
|
||||
|
||||
this.uploadNewState({
|
||||
name: this.refs.header.getRoomName(),
|
||||
topic: this.refs.header.getTopic(),
|
||||
join_rule: this.refs.room_settings.getJoinRules(),
|
||||
history_visibility: this.refs.room_settings.getHistoryVisibility(),
|
||||
are_notifications_muted: this.refs.room_settings.areNotificationsMuted(),
|
||||
power_levels: this.refs.room_settings.getPowerLevels(),
|
||||
tag_operations: this.refs.room_settings.getTagOperations(),
|
||||
guest_join: this.refs.room_settings.canGuestsJoin(),
|
||||
guest_read: this.refs.room_settings.canGuestsRead(),
|
||||
color_scheme: this.refs.room_settings.getColorScheme(),
|
||||
});
|
||||
|
||||
this.refs.room_settings.setName(this.refs.header.getRoomName());
|
||||
this.refs.room_settings.setTopic(this.refs.header.getTopic());
|
||||
|
||||
this.refs.room_settings.save().then((results) => {
|
||||
var fails = results.filter(function(result) { return result.state !== "fulfilled" });
|
||||
console.log("Settings saved with %s errors", fails.length);
|
||||
if (fails.length) {
|
||||
fails.forEach(function(result) {
|
||||
console.error(result.reason);
|
||||
});
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: "Failed to save settings",
|
||||
description: fails.map(function(result) { return result.reason }).join("\n"),
|
||||
});
|
||||
// still editing room settings
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
editingRoomSettings: false
|
||||
});
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setState({
|
||||
uploadingRoomSettings: false,
|
||||
editingRoomSettings: false
|
||||
});
|
||||
}).done();
|
||||
},
|
||||
|
||||
onCancelClick: function() {
|
||||
@ -1828,7 +1655,7 @@ module.exports = React.createClass({
|
||||
|
||||
var aux = null;
|
||||
if (this.state.editingRoomSettings) {
|
||||
aux = <RoomSettings ref="room_settings" onSaveClick={this.onSaveClick} onCancelClick={this.onCancelClick} room={this.state.room} />;
|
||||
aux = <RoomSettings ref="room_settings" onSaveClick={this.onSettingsSaveClick} onCancelClick={this.onCancelClick} room={this.state.room} />;
|
||||
}
|
||||
else if (this.state.uploadingRoomSettings) {
|
||||
aux = <Loader/>;
|
||||
@ -1997,7 +1824,7 @@ module.exports = React.createClass({
|
||||
editing={this.state.editingRoomSettings}
|
||||
onSearchClick={this.onSearchClick}
|
||||
onSettingsClick={this.onSettingsClick}
|
||||
onSaveClick={this.onSaveClick}
|
||||
onSaveClick={this.onSettingsSaveClick}
|
||||
onCancelClick={this.onCancelClick}
|
||||
onForgetClick={
|
||||
(myMember && myMember.membership === "leave") ? this.onForgetClick : null
|
||||
|
@ -68,7 +68,6 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
saveSettings: function() {
|
||||
console.log("AliasSettings.saveSettings room=%s", this.props.roomId);
|
||||
var promises = [];
|
||||
|
||||
// save new canonical alias
|
||||
@ -76,8 +75,8 @@ module.exports = React.createClass({
|
||||
if (this.props.canonicalAliasEvent) {
|
||||
oldCanonicalAlias = this.props.canonicalAliasEvent.getContent().alias;
|
||||
}
|
||||
console.log("canon old=%s new=%s", oldCanonicalAlias, this.state.canonicalAlias);
|
||||
if (oldCanonicalAlias !== this.state.canonicalAlias) {
|
||||
console.log("AliasSettings: Updating canonical alias");
|
||||
promises.push(
|
||||
MatrixClientPeg.get().sendStateEvent(
|
||||
this.props.roomId, "m.room.canonical_alias", {
|
||||
@ -114,7 +113,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
return q.allSettled(promises);
|
||||
return promises;
|
||||
},
|
||||
|
||||
aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events
|
||||
|
139
src/components/views/room_settings/ColorSettings.js
Normal file
139
src/components/views/room_settings/ColorSettings.js
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright 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 q = require("q");
|
||||
var React = require('react');
|
||||
|
||||
var Tinter = require('../../../Tinter');
|
||||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||
|
||||
var ROOM_COLORS = [
|
||||
// magic room default values courtesy of Ribot
|
||||
["#76cfa6", "#eaf5f0"],
|
||||
["#81bddb", "#eaf1f4"],
|
||||
["#bd79cb", "#f3eaf5"],
|
||||
["#c65d94", "#f5eaef"],
|
||||
["#e55e5e", "#f5eaea"],
|
||||
["#eca46f", "#f5eeea"],
|
||||
["#dad658", "#f5f4ea"],
|
||||
["#80c553", "#eef5ea"],
|
||||
["#bb814e", "#eee8e3"],
|
||||
["#595959", "#ececec"],
|
||||
];
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ColorSettings',
|
||||
|
||||
propTypes: {
|
||||
room: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var data = {
|
||||
index: 0,
|
||||
primary_color: ROOM_COLORS[0].primary_color,
|
||||
secondary_color: ROOM_COLORS[0].secondary_color,
|
||||
hasChanged: false
|
||||
};
|
||||
var event = this.props.room.getAccountData("org.matrix.room.color_scheme");
|
||||
if (!event) {
|
||||
return data;
|
||||
}
|
||||
var scheme = event.getContent();
|
||||
data.primary_color = scheme.primary_color;
|
||||
data.secondary_color = scheme.secondary_color;
|
||||
data.index = this._getColorIndex(data);
|
||||
|
||||
if (data.index === -1) {
|
||||
// append the unrecognised colours to our palette
|
||||
data.index = ROOM_COLORS.length;
|
||||
ROOM_COLORS.push([
|
||||
scheme.primary_color, scheme.secondary_color
|
||||
]);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
saveSettings: function() { // : Promise
|
||||
if (!this.state.hasChanged) {
|
||||
return q(); // They didn't explicitly give a color to save.
|
||||
}
|
||||
var originalState = this.getInitialState();
|
||||
if (originalState.primary_color !== this.state.primary_color ||
|
||||
originalState.secondary_color !== this.state.secondary_color) {
|
||||
console.log("ColorSettings: Saving new color");
|
||||
return MatrixClientPeg.get().setRoomAccountData(
|
||||
this.props.room.roomId, "org.matrix.room.color_scheme", {
|
||||
primary_color: this.state.primary_color,
|
||||
secondary_color: this.state.secondary_color
|
||||
}
|
||||
);
|
||||
}
|
||||
return q(); // no color diff
|
||||
},
|
||||
|
||||
_getColorIndex: function(scheme) {
|
||||
if (!scheme || !scheme.primary_color || !scheme.secondary_color) {
|
||||
return -1;
|
||||
}
|
||||
// XXX: we should validate these values
|
||||
for (var i = 0; i < ROOM_COLORS.length; i++) {
|
||||
var room_color = ROOM_COLORS[i];
|
||||
if (room_color[0] === String(scheme.primary_color).toLowerCase() &&
|
||||
room_color[1] === String(scheme.secondary_color).toLowerCase()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
_onColorSchemeChanged: function(index) {
|
||||
// preview what the user just changed the scheme to.
|
||||
Tinter.tint(ROOM_COLORS[index][0], ROOM_COLORS[index][1]);
|
||||
this.setState({
|
||||
index: index,
|
||||
primary_color: ROOM_COLORS[index][0],
|
||||
secondary_color: ROOM_COLORS[index][1],
|
||||
hasChanged: true
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="mx_RoomSettings_roomColors">
|
||||
{ROOM_COLORS.map((room_color, i) => {
|
||||
var selected;
|
||||
if (i === this.state.index) {
|
||||
selected = (
|
||||
<div className="mx_RoomSettings_roomColor_selected">
|
||||
<img src="img/tick.svg" width="17" height="14" alt="./"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
var boundClick = this._onColorSchemeChanged.bind(this, i)
|
||||
return (
|
||||
<div className="mx_RoomSettings_roomColor"
|
||||
key={ "room_color_" + i }
|
||||
style={{ backgroundColor: room_color[1] }}
|
||||
onClick={ boundClick }>
|
||||
{ selected }
|
||||
<div className="mx_RoomSettings_roomColorPrimary" style={{ backgroundColor: room_color[0] }}></div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
@ -17,23 +17,9 @@ limitations under the License.
|
||||
var q = require("q");
|
||||
var React = require('react');
|
||||
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||
var Tinter = require('../../../Tinter');
|
||||
var sdk = require('../../../index');
|
||||
var Modal = require('../../../Modal');
|
||||
|
||||
var room_colors = [
|
||||
// magic room default values courtesy of Ribot
|
||||
["#76cfa6", "#eaf5f0"],
|
||||
["#81bddb", "#eaf1f4"],
|
||||
["#bd79cb", "#f3eaf5"],
|
||||
["#c65d94", "#f5eaef"],
|
||||
["#e55e5e", "#f5eaea"],
|
||||
["#eca46f", "#f5eeea"],
|
||||
["#dad658", "#f5f4ea"],
|
||||
["#80c553", "#eef5ea"],
|
||||
["#bb814e", "#eee8e3"],
|
||||
["#595959", "#ececec"],
|
||||
];
|
||||
var ObjectUtils = require("../../../ObjectUtils");
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomSettings',
|
||||
@ -45,87 +31,171 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
// work out the initial color index
|
||||
var room_color_index = undefined;
|
||||
var color_scheme_event = this.props.room.getAccountData("org.matrix.room.color_scheme");
|
||||
if (color_scheme_event) {
|
||||
var color_scheme = color_scheme_event.getContent();
|
||||
if (color_scheme.primary_color) color_scheme.primary_color = color_scheme.primary_color.toLowerCase();
|
||||
if (color_scheme.secondary_color) color_scheme.secondary_color = color_scheme.secondary_color.toLowerCase();
|
||||
// XXX: we should validate these values
|
||||
for (var i = 0; i < room_colors.length; i++) {
|
||||
var room_color = room_colors[i];
|
||||
if (room_color[0] === color_scheme.primary_color &&
|
||||
room_color[1] === color_scheme.secondary_color)
|
||||
{
|
||||
room_color_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (room_color_index === undefined) {
|
||||
// append the unrecognised colours to our palette
|
||||
room_color_index = room_colors.length;
|
||||
room_colors[room_color_index] = [ color_scheme.primary_color, color_scheme.secondary_color ];
|
||||
}
|
||||
}
|
||||
else {
|
||||
room_color_index = 0;
|
||||
}
|
||||
|
||||
var tags = {};
|
||||
Object.keys(this.props.room.tags).forEach(function(tagName) {
|
||||
tags[tagName] = {};
|
||||
});
|
||||
|
||||
var areNotifsMuted = false;
|
||||
var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId);
|
||||
if (roomPushRule) {
|
||||
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
||||
areNotifsMuted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: this._yankValueFromEvent("m.room.name", "name"),
|
||||
topic: this._yankValueFromEvent("m.room.topic", "topic"),
|
||||
join_rule: this._yankValueFromEvent("m.room.join_rules", "join_rule"),
|
||||
history_visibility: this._yankValueFromEvent("m.room.history_visibility", "history_visibility"),
|
||||
guest_access: this._yankValueFromEvent("m.room.guest_access", "guest_access"),
|
||||
power_levels_changed: false,
|
||||
color_scheme_changed: false,
|
||||
color_scheme_index: room_color_index,
|
||||
tags_changed: false,
|
||||
tags: tags,
|
||||
areNotifsMuted: areNotifsMuted
|
||||
};
|
||||
},
|
||||
|
||||
setName: function(name) {
|
||||
this.setState({
|
||||
name: name
|
||||
});
|
||||
},
|
||||
|
||||
setTopic: function(topic) {
|
||||
this.setState({
|
||||
topic: topic
|
||||
});
|
||||
},
|
||||
|
||||
save: function() {
|
||||
var stateWasSetDefer = q.defer();
|
||||
// the caller may have JUST called setState on stuff, so we need to re-render before saving
|
||||
// else we won't use the latest values of things.
|
||||
// We can be a bit cheeky here and set a loading flag, and listen for the callback on that
|
||||
// to know when things have been set.
|
||||
this.setState({ _loading: true}, () => {
|
||||
stateWasSetDefer.resolve();
|
||||
this.setState({ _loading: false});
|
||||
});
|
||||
|
||||
return stateWasSetDefer.promise.then(() => {
|
||||
return this._save();
|
||||
});
|
||||
},
|
||||
|
||||
_save: function() {
|
||||
const roomId = this.props.room.roomId;
|
||||
var promises = this.saveAliases(); // returns Promise[]
|
||||
var originalState = this.getInitialState();
|
||||
|
||||
// diff between original state and this.state to work out what has been changed
|
||||
console.log("Original: %s", JSON.stringify(originalState));
|
||||
console.log("New: %s", JSON.stringify(this.state));
|
||||
|
||||
// name and topic
|
||||
if (this._hasDiff(this.state.name, originalState.name)) {
|
||||
promises.push(MatrixClientPeg.get().setRoomName(roomId, this.state.name));
|
||||
}
|
||||
if (this._hasDiff(this.state.topic, originalState.topic)) {
|
||||
promises.push(MatrixClientPeg.get().setRoomTopic(roomId, this.state.topic));
|
||||
}
|
||||
|
||||
if (this.state.history_visibility !== originalState.history_visibility) {
|
||||
promises.push(MatrixClientPeg.get().sendStateEvent(
|
||||
roomId, "m.room.history_visibility",
|
||||
{ history_visibility: this.state.history_visibility },
|
||||
""
|
||||
));
|
||||
}
|
||||
|
||||
if (this.state.join_rule !== originalState.join_rule) {
|
||||
promises.push(MatrixClientPeg.get().sendStateEvent(
|
||||
roomId, "m.room.join_rules",
|
||||
{ join_rule: this.state.join_rule },
|
||||
""
|
||||
));
|
||||
}
|
||||
|
||||
if (this.state.guest_access !== originalState.guest_access) {
|
||||
promises.push(MatrixClientPeg.get().sendStateEvent(
|
||||
roomId, "m.room.guest_access",
|
||||
{ guest_access: this.state.guest_access },
|
||||
""
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
if (this.state.areNotifsMuted !== originalState.areNotifsMuted) {
|
||||
promises.push(MatrixClientPeg.get().setRoomMutePushRule(
|
||||
"global", roomId, this.state.areNotifsMuted
|
||||
));
|
||||
}
|
||||
|
||||
// power levels
|
||||
var powerLevels = this._getPowerLevels();
|
||||
if (powerLevels) {
|
||||
promises.push(MatrixClientPeg.get().sendStateEvent(
|
||||
roomId, "m.room.power_levels", powerLevels, ""
|
||||
));
|
||||
}
|
||||
|
||||
// tags
|
||||
if (this.state.tags_changed) {
|
||||
var tagDiffs = ObjectUtils.getKeyValueArrayDiffs(originalState.tags, this.state.tags);
|
||||
// [ {place: add, key: "m.favourite", val: "yep"} ]
|
||||
tagDiffs.forEach(function(diff) {
|
||||
switch (diff.place) {
|
||||
case "add":
|
||||
promises.push(
|
||||
MatrixClientPeg.get().setRoomTag(roomId, diff.key, {})
|
||||
);
|
||||
break;
|
||||
case "del":
|
||||
promises.push(
|
||||
MatrixClientPeg.get().deleteRoomTag(roomId, diff.key)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown tag operation: %s", diff.place);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log("Performing %s operations", promises.length);
|
||||
|
||||
// color scheme
|
||||
promises.push(this.saveColor());
|
||||
|
||||
return q.allSettled(promises);
|
||||
},
|
||||
|
||||
saveAliases: function() {
|
||||
if (!this.refs.alias_settings) { return q(); }
|
||||
if (!this.refs.alias_settings) { return [q()]; }
|
||||
return this.refs.alias_settings.saveSettings();
|
||||
},
|
||||
|
||||
resetState: function() {
|
||||
this.setState(this.getInitialState());
|
||||
saveColor: function() {
|
||||
if (!this.refs.color_settings) { return q(); }
|
||||
return this.refs.color_settings.saveSettings();
|
||||
},
|
||||
|
||||
canGuestsJoin: function() {
|
||||
return this.refs.guests_join.checked;
|
||||
_hasDiff: function(strA, strB) {
|
||||
// treat undefined as an empty string because other components may blindly
|
||||
// call setName("") when there has been no diff made to the name!
|
||||
strA = strA || "";
|
||||
strB = strB || "";
|
||||
return strA !== strB;
|
||||
},
|
||||
|
||||
canGuestsRead: function() {
|
||||
return this.refs.guests_read.checked;
|
||||
},
|
||||
|
||||
getTopic: function() {
|
||||
return this.refs.topic ? this.refs.topic.value : "";
|
||||
},
|
||||
|
||||
getJoinRules: function() {
|
||||
return this.refs.is_private.checked ? "invite" : "public";
|
||||
},
|
||||
|
||||
getHistoryVisibility: function() {
|
||||
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;
|
||||
|
||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
power_levels = power_levels.getContent();
|
||||
var powerLevels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
powerLevels = powerLevels ? powerLevels.getContent() : {};
|
||||
|
||||
var new_power_levels = {
|
||||
var newPowerLevels = {
|
||||
ban: parseInt(this.refs.ban.getValue()),
|
||||
kick: parseInt(this.refs.kick.getValue()),
|
||||
redact: parseInt(this.refs.redact.getValue()),
|
||||
@ -133,39 +203,11 @@ module.exports = React.createClass({
|
||||
events_default: parseInt(this.refs.events_default.getValue()),
|
||||
state_default: parseInt(this.refs.state_default.getValue()),
|
||||
users_default: parseInt(this.refs.users_default.getValue()),
|
||||
users: power_levels.users,
|
||||
events: power_levels.events,
|
||||
users: powerLevels.users,
|
||||
events: powerLevels.events,
|
||||
};
|
||||
|
||||
return new_power_levels;
|
||||
},
|
||||
|
||||
getTagOperations: function() {
|
||||
if (!this.state.tags_changed) return undefined;
|
||||
|
||||
var ops = [];
|
||||
|
||||
var delta = {};
|
||||
Object.keys(this.props.room.tags).forEach(function(oldTag) {
|
||||
delta[oldTag] = delta[oldTag] || 0;
|
||||
delta[oldTag]--;
|
||||
});
|
||||
Object.keys(this.state.tags).forEach(function(newTag) {
|
||||
delta[newTag] = delta[newTag] || 0;
|
||||
delta[newTag]++;
|
||||
});
|
||||
Object.keys(delta).forEach(function(tag) {
|
||||
if (delta[tag] == 1) {
|
||||
ops.push({ type: "put", tag: tag });
|
||||
} else if (delta[tag] == -1) {
|
||||
ops.push({ type: "delete", tag: tag });
|
||||
} else {
|
||||
console.error("Calculated tag delta of " + delta[tag] +
|
||||
" - this should never happen!");
|
||||
}
|
||||
});
|
||||
|
||||
return ops;
|
||||
return newPowerLevels;
|
||||
},
|
||||
|
||||
onPowerLevelsChanged: function() {
|
||||
@ -173,27 +215,30 @@ module.exports = React.createClass({
|
||||
power_levels_changed: true
|
||||
});
|
||||
},
|
||||
|
||||
getColorScheme: function() {
|
||||
if (!this.state.color_scheme_changed) return undefined;
|
||||
|
||||
return {
|
||||
primary_color: room_colors[this.state.color_scheme_index][0],
|
||||
secondary_color: room_colors[this.state.color_scheme_index][1],
|
||||
};
|
||||
|
||||
_yankValueFromEvent: function(stateEventType, keyName, defaultValue) {
|
||||
// E.g.("m.room.name","name") would yank the "name" content key from "m.room.name"
|
||||
var event = this.props.room.currentState.getStateEvents(stateEventType, '');
|
||||
if (!event) {
|
||||
return defaultValue;
|
||||
}
|
||||
return event.getContent()[keyName] || defaultValue;
|
||||
},
|
||||
|
||||
onColorSchemeChanged: function(index) {
|
||||
// preview what the user just changed the scheme to.
|
||||
Tinter.tint(room_colors[index][0], room_colors[index][1]);
|
||||
|
||||
_onHistoryRadioToggle: function(ev) {
|
||||
this.setState({
|
||||
color_scheme_changed: true,
|
||||
color_scheme_index: index,
|
||||
history_visibility: ev.target.value
|
||||
});
|
||||
},
|
||||
|
||||
_onToggle: function(keyName, checkedValue, uncheckedValue, ev) {
|
||||
console.log("Checkbox toggle: %s %s", keyName, ev.target.checked);
|
||||
var state = {};
|
||||
state[keyName] = ev.target.checked ? checkedValue : uncheckedValue;
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
onTagChange: function(tagName, event) {
|
||||
_onTagChange: function(tagName, event) {
|
||||
if (event.target.checked) {
|
||||
if (tagName === 'm.favourite') {
|
||||
delete this.state.tags['m.lowpriority'];
|
||||
@ -202,13 +247,12 @@ module.exports = React.createClass({
|
||||
delete this.state.tags['m.favourite'];
|
||||
}
|
||||
|
||||
this.state.tags[tagName] = this.state.tags[tagName] || {};
|
||||
this.state.tags[tagName] = this.state.tags[tagName] || ["yep"];
|
||||
}
|
||||
else {
|
||||
delete this.state.tags[tagName];
|
||||
}
|
||||
|
||||
// XXX: hacky say to deep-edit state
|
||||
this.setState({
|
||||
tags: this.state.tags,
|
||||
tags_changed: true
|
||||
@ -220,34 +264,14 @@ module.exports = React.createClass({
|
||||
// (or turning them into informative stuff)
|
||||
|
||||
var AliasSettings = sdk.getComponent("room_settings.AliasSettings");
|
||||
var ColorSettings = sdk.getComponent("room_settings.ColorSettings");
|
||||
var EditableText = sdk.getComponent('elements.EditableText');
|
||||
var PowerSelector = sdk.getComponent('elements.PowerSelector');
|
||||
|
||||
var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', '');
|
||||
if (join_rule) join_rule = join_rule.getContent().join_rule;
|
||||
|
||||
var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', '');
|
||||
if (history_visibility) history_visibility = history_visibility.getContent().history_visibility;
|
||||
|
||||
var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', '');
|
||||
var guest_access = this.props.room.currentState.getStateEvents('m.room.guest_access', '');
|
||||
if (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 user_id = MatrixClientPeg.get().credentials.userId;
|
||||
|
||||
|
||||
if (power_levels) {
|
||||
power_levels = power_levels.getContent();
|
||||
|
||||
@ -305,41 +329,14 @@ module.exports = React.createClass({
|
||||
if (events_levels['m.room.canonical_alias'] !== undefined) {
|
||||
canonical_alias_level = events_levels['m.room.canonical_alias'];
|
||||
}
|
||||
var can_set_canonical_alias = current_user_level >= canonical_alias_level;
|
||||
|
||||
var can_set_tag = true;
|
||||
var canSetCanonicalAlias = current_user_level >= canonical_alias_level;
|
||||
var canSetTag = true;
|
||||
|
||||
var self = this;
|
||||
|
||||
var room_colors_section =
|
||||
<div>
|
||||
<h3>Room Colour</h3>
|
||||
<div className="mx_RoomSettings_roomColors">
|
||||
{room_colors.map(function(room_color, i) {
|
||||
var selected;
|
||||
if (i === self.state.color_scheme_index) {
|
||||
selected =
|
||||
<div className="mx_RoomSettings_roomColor_selected">
|
||||
<img src="img/tick.svg" width="17" height="14" alt="./"/>
|
||||
</div>
|
||||
}
|
||||
var boundClick = self.onColorSchemeChanged.bind(self, i)
|
||||
return (
|
||||
<div className="mx_RoomSettings_roomColor"
|
||||
key={ "room_color_" + i }
|
||||
style={{ backgroundColor: room_color[1] }}
|
||||
onClick={ boundClick }>
|
||||
{ selected }
|
||||
<div className="mx_RoomSettings_roomColorPrimary" style={{ backgroundColor: room_color[0] }}></div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
var user_levels_section;
|
||||
var userLevelsSection;
|
||||
if (Object.keys(user_levels).length) {
|
||||
user_levels_section =
|
||||
userLevelsSection =
|
||||
<div>
|
||||
<h3>Privileged Users</h3>
|
||||
<ul className="mx_RoomSettings_userLevels">
|
||||
@ -354,13 +351,13 @@ module.exports = React.createClass({
|
||||
</div>;
|
||||
}
|
||||
else {
|
||||
user_levels_section = <div>No users have specific privileges in this room.</div>
|
||||
userLevelsSection = <div>No users have specific privileges in this room.</div>
|
||||
}
|
||||
|
||||
var banned = this.props.room.getMembersWithMembership("ban");
|
||||
var banned_users_section;
|
||||
var bannedUsersSection;
|
||||
if (banned.length) {
|
||||
banned_users_section =
|
||||
bannedUsersSection =
|
||||
<div>
|
||||
<h3>Banned users</h3>
|
||||
<ul className="mx_RoomSettings_banned">
|
||||
@ -375,10 +372,13 @@ module.exports = React.createClass({
|
||||
</div>;
|
||||
}
|
||||
|
||||
var create_event = this.props.room.currentState.getStateEvents('m.room.create', '');
|
||||
var unfederatable_section;
|
||||
if (create_event.getContent()["m.federate"] === false) {
|
||||
unfederatable_section = <div className="mx_RoomSettings_powerLevel">Ths room is not accessible by remote Matrix servers.</div>
|
||||
var unfederatableSection;
|
||||
if (this._yankValueFromEvent("m.room.create", "m.federate") === false) {
|
||||
unfederatableSection = (
|
||||
<div className="mx_RoomSettings_powerLevel">
|
||||
Ths room is not accessible by remote Matrix servers.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: support editing custom events_levels
|
||||
@ -395,43 +395,89 @@ module.exports = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
var tags_section =
|
||||
var tagsSection =
|
||||
<div className="mx_RoomSettings_tags">
|
||||
Tagged as:
|
||||
{ can_set_tag ?
|
||||
{ canSetTag ?
|
||||
tags.map(function(tag, i) {
|
||||
return (<label key={ i }>
|
||||
<input type="checkbox"
|
||||
ref={ tag.ref }
|
||||
checked={ tag.name in self.state.tags }
|
||||
onChange={ self.onTagChange.bind(self, tag.name) }/>
|
||||
onChange={ self._onTagChange.bind(self, tag.name) }/>
|
||||
{ tag.label }
|
||||
</label>);
|
||||
}) : tags.map(function(tag) { return tag.label; }).join(", ")
|
||||
}
|
||||
</div>
|
||||
|
||||
// If there is no history_visibility, it is assumed to be 'shared'.
|
||||
// http://matrix.org/docs/spec/r0.0.0/client_server.html#id31
|
||||
var historyVisibility = this.state.history_visibility || "shared";
|
||||
|
||||
// FIXME: disable guests_read if the user hasn't turned on shared history
|
||||
return (
|
||||
<div className="mx_RoomSettings">
|
||||
|
||||
{ tags_section }
|
||||
{ tagsSection }
|
||||
|
||||
<div className="mx_RoomSettings_toggles">
|
||||
<label><input type="checkbox" ref="are_notifications_muted" defaultChecked={are_notifications_muted}/> Mute notifications for this room</label>
|
||||
<label><input type="checkbox" ref="is_private" defaultChecked={join_rule != "public"}/> Make this room private</label>
|
||||
<label><input type="checkbox" ref="share_history" defaultChecked={history_visibility === "shared" || history_visibility === "world_readable"}/> Share message history with new participants</label>
|
||||
<label><input type="checkbox" ref="guests_join" defaultChecked={guest_access === "can_join"}/> Let guests join this room</label>
|
||||
<label><input type="checkbox" ref="guests_read" defaultChecked={history_visibility === "world_readable"}/> Let users read message history without joining</label>
|
||||
<label className="mx_RoomSettings_encrypt"><input type="checkbox" /> Encrypt room</label>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this._onToggle.bind(this, "areNotifsMuted", true, false)} defaultChecked={this.state.areNotifsMuted}/>
|
||||
Mute notifications for this room
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this._onToggle.bind(this, "join_rule", "invite", "public")}
|
||||
defaultChecked={this.state.join_rule !== "public"}/>
|
||||
Make this room private
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this._onToggle.bind(this, "guest_access", "can_join", "forbidden")}
|
||||
defaultChecked={this.state.guest_access === "can_join"}/>
|
||||
Let guests join this room
|
||||
</label>
|
||||
<div className="mx_RoomSettings_settings">
|
||||
<h3>Who can read history?</h3>
|
||||
<label htmlFor="hvis_wr">
|
||||
<input type="radio" id="hvis_wr" name="historyVis" value="world_readable"
|
||||
defaultChecked={historyVisibility === "world_readable"}
|
||||
onChange={this._onHistoryRadioToggle} />
|
||||
Anyone
|
||||
</label>
|
||||
<label htmlFor="hvis_sh">
|
||||
<input type="radio" id="hvis_sh" name="historyVis" value="shared"
|
||||
defaultChecked={historyVisibility === "shared"}
|
||||
onChange={this._onHistoryRadioToggle} />
|
||||
Members only (since the room began)
|
||||
</label>
|
||||
<label htmlFor="hvis_inv">
|
||||
<input type="radio" id="hvis_inv" name="historyVis" value="invited"
|
||||
defaultChecked={historyVisibility === "invited"}
|
||||
onChange={this._onHistoryRadioToggle} />
|
||||
Members only (since they were invited)
|
||||
</label>
|
||||
<label htmlFor="hvis_joi">
|
||||
<input type="radio" id="hvis_joi" name="historyVis" value="joined"
|
||||
defaultChecked={historyVisibility === "joined"}
|
||||
onChange={this._onHistoryRadioToggle} />
|
||||
Members only (since they joined)
|
||||
</label>
|
||||
</div>
|
||||
<label className="mx_RoomSettings_encrypt">
|
||||
<input type="checkbox" />
|
||||
Encrypt room
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
{ room_colors_section }
|
||||
<div>
|
||||
<h3>Room Colour</h3>
|
||||
<ColorSettings ref="color_settings" room={this.props.room} />
|
||||
</div>
|
||||
|
||||
<AliasSettings ref="alias_settings"
|
||||
roomId={this.props.room.roomId}
|
||||
canSetCanonicalAlias={can_set_canonical_alias}
|
||||
canSetCanonicalAlias={canSetCanonicalAlias}
|
||||
canSetAliases={can_set_room_aliases}
|
||||
canonicalAliasEvent={this.props.room.currentState.getStateEvents('m.room.canonical_alias', '')}
|
||||
aliasEvents={this.props.room.currentState.getStateEvents('m.room.aliases')} />
|
||||
@ -476,12 +522,12 @@ module.exports = React.createClass({
|
||||
);
|
||||
})}
|
||||
|
||||
{ unfederatable_section }
|
||||
{ unfederatableSection }
|
||||
</div>
|
||||
|
||||
{ user_levels_section }
|
||||
{ userLevelsSection }
|
||||
|
||||
{ banned_users_section }
|
||||
{ bannedUsersSection }
|
||||
|
||||
<h3>Advanced</h3>
|
||||
<div className="mx_RoomSettings_settings">
|
||||
|
Loading…
Reference in New Issue
Block a user