diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 9b772b8e42..febafacc22 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1038,195 +1038,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; @@ -1324,22 +1135,38 @@ 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) => { + console.log("Settings saved."); + 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"), + }); + // still editing room settings + } + else { + this.setState({ + editingRoomSettings: false + }); + } + }).finally(() => { + this.setState({ + uploadingRoomSettings: false, + editingRoomSettings: false + }); }); }, @@ -1730,7 +1557,7 @@ module.exports = React.createClass({ var aux = null; if (this.state.editingRoomSettings) { - aux = ; + aux = ; } else if (this.state.uploadingRoomSettings) { aux = ; @@ -1899,7 +1726,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 diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index 0dd00852fa..033fdcd8b5 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -114,7 +114,7 @@ module.exports = React.createClass({ } } - return q.allSettled(promises); + return promises; }, aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index b716b2e9df..27fc6af961 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -21,7 +21,7 @@ var Tinter = require('../../../Tinter'); var sdk = require('../../../index'); var Modal = require('../../../Modal'); -var room_colors = [ +var ROOM_COLORS = [ // magic room default values courtesy of Ribot ["#76cfa6", "#eaf5f0"], ["#81bddb", "#eaf1f4"], @@ -53,8 +53,8 @@ module.exports = React.createClass({ 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]; + 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) { @@ -64,8 +64,8 @@ module.exports = React.createClass({ } 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 ]; + room_color_index = ROOM_COLORS.length; + ROOM_COLORS[room_color_index] = [ color_scheme.primary_color, color_scheme.secondary_color ]; } } else { @@ -77,14 +77,84 @@ module.exports = React.createClass({ tags[tagName] = {}; }); + var are_notifications_muted = false; + var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId); + if (roomPushRule) { + if (0 <= roomPushRule.actions.indexOf("dont_notify")) { + are_notifications_muted = 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: are_notifications_muted }; }, + + 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)); + if (this.state.name !== originalState.name) { + promises.push(MatrixClientPeg.get().setRoomName(roomId, this.state.name)); + } + if (this.state.topic !== originalState.topic) { // TODO: 0-length strings? + promises.push(MatrixClientPeg.get().setRoomTopic(roomId, this.state.topic)); + } + // TODO: + // this.state.join_rule + // this.state.history_visibility + // this.state.guest_access + // setRoomMutePushRule + // power levels + // tags + // color scheme + + // submit diffs + + return q.allSettled(promises); + }, saveAliases: function() { if (!this.refs.alias_settings) { return q(); } @@ -116,7 +186,7 @@ module.exports = React.createClass({ }, areNotificationsMuted: function() { - return this.refs.are_notifications_muted.checked; + return this.state.are_notifications_muted; }, getPowerLevels: function() { @@ -178,20 +248,36 @@ module.exports = React.createClass({ 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], + primary_color: ROOM_COLORS[this.state.color_scheme_index][0], + secondary_color: ROOM_COLORS[this.state.color_scheme_index][1], }; }, onColorSchemeChanged: function(index) { // preview what the user just changed the scheme to. - Tinter.tint(room_colors[index][0], room_colors[index][1]); + Tinter.tint(ROOM_COLORS[index][0], ROOM_COLORS[index][1]); this.setState({ color_scheme_changed: true, color_scheme_index: index, }); }, + + _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; + }, + + _onToggle: function(keyName, ev) { + console.log("Checkbox toggle: %s %s", keyName, ev.target.checked); + var state = {}; + state[keyName] = ev.target.checked; + this.setState(state); + }, onTagChange: function(tagName, event) { if (event.target.checked) { @@ -223,8 +309,7 @@ module.exports = React.createClass({ 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; @@ -235,14 +320,6 @@ module.exports = React.createClass({ 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; @@ -315,7 +392,7 @@ module.exports = React.createClass({

Room Colour

- {room_colors.map(function(room_color, i) { + {ROOM_COLORS.map(function(room_color, i) { var selected; if (i === self.state.color_scheme_index) { selected = @@ -418,12 +495,30 @@ module.exports = React.createClass({ { tags_section }
- - - - - - + + + + + +