diff --git a/src/component-index.js b/src/component-index.js index d5cd6da090..a0c2433dc3 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -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'); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 425852f07f..eb38cba953 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -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 = ; + aux = ; } else if (this.state.uploadingRoomSettings) { aux = ; @@ -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 diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index 0dd00852fa..e6cd16fd16 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -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 diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js new file mode 100644 index 0000000000..bf931b6c05 --- /dev/null +++ b/src/components/views/room_settings/ColorSettings.js @@ -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 ( +
+ {ROOM_COLORS.map((room_color, i) => { + var selected; + if (i === this.state.index) { + selected = ( +
+ ./ +
+ ); + } + var boundClick = this._onColorSchemeChanged.bind(this, i) + return ( +
+ { selected } +
+
+ ); + })} +
+ ); + } +}); diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index b716b2e9df..10af37ebf0 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -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 = -
-

Room Colour

-
- {room_colors.map(function(room_color, i) { - var selected; - if (i === self.state.color_scheme_index) { - selected = -
- ./ -
- } - var boundClick = self.onColorSchemeChanged.bind(self, i) - return ( -
- { selected } -
-
- ); - })} -
-
; - - var user_levels_section; + var userLevelsSection; if (Object.keys(user_levels).length) { - user_levels_section = + userLevelsSection =

Privileged Users

    @@ -354,13 +351,13 @@ module.exports = React.createClass({
; } else { - user_levels_section =
No users have specific privileges in this room.
+ userLevelsSection =
No users have specific privileges in this room.
} var banned = this.props.room.getMembersWithMembership("ban"); - var banned_users_section; + var bannedUsersSection; if (banned.length) { - banned_users_section = + bannedUsersSection =

Banned users

    @@ -375,10 +372,13 @@ module.exports = React.createClass({
; } - var create_event = this.props.room.currentState.getStateEvents('m.room.create', ''); - var unfederatable_section; - if (create_event.getContent()["m.federate"] === false) { - unfederatable_section =
Ths room is not accessible by remote Matrix servers.
+ var unfederatableSection; + if (this._yankValueFromEvent("m.room.create", "m.federate") === false) { + unfederatableSection = ( +
+ Ths room is not accessible by remote Matrix servers. +
+ ); } // TODO: support editing custom events_levels @@ -395,43 +395,89 @@ module.exports = React.createClass({ } }); - var tags_section = + var tagsSection =
Tagged as: - { can_set_tag ? + { canSetTag ? tags.map(function(tag, i) { return (); }) : tags.map(function(tag) { return tag.label; }).join(", ") }
+ // 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 (
- { tags_section } + { tagsSection }
- - - - - - + + + +
+

Who can read history?

+ + + + +
+
- { room_colors_section } +
+

Room Colour

+ +
@@ -476,12 +522,12 @@ module.exports = React.createClass({ ); })} - { unfederatable_section } + { unfederatableSection }
- { user_levels_section } + { userLevelsSection } - { banned_users_section } + { bannedUsersSection }

Advanced