Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2017-11-14 14:05:54 +00:00
commit c1d70f28d7
5 changed files with 77 additions and 50 deletions

View file

@ -15,19 +15,20 @@ limitations under the License.
*/ */
import { _t } from './languageHandler'; import { _t } from './languageHandler';
export function levelRoleMap() { export function levelRoleMap(usersDefault) {
return { return {
undefined: _t('Default'), undefined: _t('Default'),
0: _t('User'), 0: _t('Restricted'),
[usersDefault]: _t('Default'),
50: _t('Moderator'), 50: _t('Moderator'),
100: _t('Admin'), 100: _t('Admin'),
}; };
} }
export function textualPowerLevel(level, userDefault) { export function textualPowerLevel(level, usersDefault) {
const LEVEL_ROLE_MAP = this.levelRoleMap(); const LEVEL_ROLE_MAP = this.levelRoleMap(usersDefault);
if (LEVEL_ROLE_MAP[level]) { if (LEVEL_ROLE_MAP[level]) {
return LEVEL_ROLE_MAP[level] + (level !== undefined ? ` (${level})` : ` (${userDefault})`); return LEVEL_ROLE_MAP[level] + (level !== undefined ? ` (${level})` : ` (${usersDefault})`);
} else { } else {
return level; return level;
} }

View file

@ -25,6 +25,11 @@ module.exports = React.createClass({
propTypes: { propTypes: {
value: React.PropTypes.number.isRequired, value: React.PropTypes.number.isRequired,
// The maximum value that can be set with the power selector
maxValue: React.PropTypes.number.isRequired,
// Default user power level for the room
usersDefault: React.PropTypes.number.isRequired,
// if true, the <select/> should be a 'controlled' form element and updated by React // if true, the <select/> should be a 'controlled' form element and updated by React
// to reflect the current value, rather than left freeform. // to reflect the current value, rather than left freeform.
@ -41,63 +46,83 @@ module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
levelRoleMap: {}, levelRoleMap: {},
// List of power levels to show in the drop-down
options: [],
};
},
getDefaultProps: function() {
return {
maxValue: Infinity,
usersDefault: 0,
}; };
}, },
componentWillMount: function() { componentWillMount: function() {
this._initStateFromProps(this.props);
},
componentWillReceiveProps: function(newProps) {
this._initStateFromProps(newProps);
},
_initStateFromProps: function(newProps) {
// This needs to be done now because levelRoleMap has translated strings // This needs to be done now because levelRoleMap has translated strings
const levelRoleMap = Roles.levelRoleMap(); const levelRoleMap = Roles.levelRoleMap(newProps.usersDefault);
const options = Object.keys(levelRoleMap).filter((l) => {
return l === undefined || l <= newProps.maxValue;
});
this.setState({ this.setState({
levelRoleMap, levelRoleMap,
custom: levelRoleMap[this.props.value] === undefined, options,
custom: levelRoleMap[newProps.value] === undefined,
}); });
}, },
onSelectChange: function(event) { onSelectChange: function(event) {
this.setState({ custom: event.target.value === "SELECT_VALUE_CUSTOM" }); this.setState({ custom: event.target.value === "SELECT_VALUE_CUSTOM" });
if (event.target.value !== "SELECT_VALUE_CUSTOM") { if (event.target.value !== "SELECT_VALUE_CUSTOM") {
this.props.onChange(this.getValue()); this.props.onChange(event.target.value);
} }
}, },
onCustomBlur: function(event) { onCustomBlur: function(event) {
this.props.onChange(this.getValue()); this.props.onChange(parseInt(this.refs.custom.value));
}, },
onCustomKeyDown: function(event) { onCustomKeyDown: function(event) {
if (event.key == "Enter") { if (event.key == "Enter") {
this.props.onChange(this.getValue()); this.props.onChange(parseInt(this.refs.custom.value));
} }
}, },
getValue: function() {
let value;
if (this.refs.select) {
value = this.refs.select.value;
if (this.refs.custom) {
if (value === undefined) value = parseInt( this.refs.custom.value );
}
}
return value;
},
render: function() { render: function() {
let customPicker; let customPicker;
if (this.state.custom) { if (this.state.custom) {
let input;
if (this.props.disabled) { if (this.props.disabled) {
input = <span>{ this.props.value }</span>; customPicker = <span>{ _t(
"Custom of %(powerLevel)s",
{ powerLevel: this.props.value },
) }</span>;
} else { } else {
input = <input ref="custom" type="text" size="3" defaultValue={this.props.value} onBlur={this.onCustomBlur} onKeyDown={this.onCustomKeyDown} />; customPicker = <span> = <input
ref="custom"
type="text"
size="3"
defaultValue={this.props.value}
onBlur={this.onCustomBlur}
onKeyDown={this.onCustomKeyDown}
/>
</span>;
} }
customPicker = <span> of { input }</span>;
} }
let selectValue; let selectValue;
if (this.state.custom) { if (this.state.custom) {
selectValue = "SELECT_VALUE_CUSTOM"; selectValue = "SELECT_VALUE_CUSTOM";
} else { } else {
selectValue = this.state.levelRoleMap[selectValue] ? selectValue = this.state.levelRoleMap[this.props.value] ?
this.props.value : "SELECT_VALUE_CUSTOM"; this.props.value : "SELECT_VALUE_CUSTOM";
} }
let select; let select;
@ -105,13 +130,10 @@ module.exports = React.createClass({
select = <span>{ this.state.levelRoleMap[selectValue] }</span>; select = <span>{ this.state.levelRoleMap[selectValue] }</span>;
} else { } else {
// Each level must have a definition in this.state.levelRoleMap // Each level must have a definition in this.state.levelRoleMap
const levels = [0, 50, 100]; let options = this.state.options.map((level) => {
let options = levels.map((level) => {
return { return {
value: level, value: level,
// Give a userDefault (users_default in the power event) of 0 but text: Roles.textualPowerLevel(level, this.props.usersDefault),
// because level !== undefined, this should never be used.
text: Roles.textualPowerLevel(level, 0),
}; };
}); });
options.push({ value: "SELECT_VALUE_CUSTOM", text: _t("Custom level") }); options.push({ value: "SELECT_VALUE_CUSTOM", text: _t("Custom level") });

View file

@ -494,7 +494,6 @@ module.exports = withMatrixClient(React.createClass({
const defaultPerms = { const defaultPerms = {
can: {}, can: {},
muted: false, muted: false,
modifyLevel: false,
}; };
const room = this.props.matrixClient.getRoom(member.roomId); const room = this.props.matrixClient.getRoom(member.roomId);
if (!room) return defaultPerms; if (!room) return defaultPerms;
@ -516,13 +515,15 @@ module.exports = withMatrixClient(React.createClass({
}, },
_calculateCanPermissions: function(me, them, powerLevels) { _calculateCanPermissions: function(me, them, powerLevels) {
const isMe = me.userId === them.userId;
const can = { const can = {
kick: false, kick: false,
ban: false, ban: false,
mute: false, mute: false,
modifyLevel: false, modifyLevel: false,
modifyLevelMax: 0,
}; };
const canAffectUser = them.powerLevel < me.powerLevel; const canAffectUser = them.powerLevel < me.powerLevel || isMe;
if (!canAffectUser) { if (!canAffectUser) {
//console.log("Cannot affect user: %s >= %s", them.powerLevel, me.powerLevel); //console.log("Cannot affect user: %s >= %s", them.powerLevel, me.powerLevel);
return can; return can;
@ -531,16 +532,13 @@ module.exports = withMatrixClient(React.createClass({
(powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) || (powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) ||
powerLevels.state_default powerLevels.state_default
); );
const levelToSend = (
(powerLevels.events ? powerLevels.events["m.room.message"] : null) ||
powerLevels.events_default
);
can.kick = me.powerLevel >= powerLevels.kick; can.kick = me.powerLevel >= powerLevels.kick;
can.ban = me.powerLevel >= powerLevels.ban; can.ban = me.powerLevel >= powerLevels.ban;
can.mute = me.powerLevel >= editPowerLevel; can.mute = me.powerLevel >= editPowerLevel;
can.toggleMod = me.powerLevel > them.powerLevel && them.powerLevel >= levelToSend; can.modifyLevel = me.powerLevel >= editPowerLevel && (isMe || me.powerLevel > them.powerLevel);
can.modifyLevel = me.powerLevel > them.powerLevel && me.powerLevel >= editPowerLevel; can.modifyLevelMax = me.powerLevel;
return can; return can;
}, },
@ -832,8 +830,11 @@ module.exports = withMatrixClient(React.createClass({
presenceCurrentlyActive = this.props.member.user.currentlyActive; presenceCurrentlyActive = this.props.member.user.currentlyActive;
} }
let roomMemberDetails = null; const room = this.props.matrixClient.getRoom(this.props.member.roomId);
const poweLevelEvent = room ? room.currentState.getStateEvents("m.room.power_levels", "") : null;
const powerLevelUsersDefault = poweLevelEvent.getContent().users_default;
let roomMemberDetails = null;
if (this.props.member.roomId) { // is in room if (this.props.member.roomId) { // is in room
const PowerSelector = sdk.getComponent('elements.PowerSelector'); const PowerSelector = sdk.getComponent('elements.PowerSelector');
const PresenceLabel = sdk.getComponent('rooms.PresenceLabel'); const PresenceLabel = sdk.getComponent('rooms.PresenceLabel');
@ -842,7 +843,9 @@ module.exports = withMatrixClient(React.createClass({
{ _t("Level:") } <b> { _t("Level:") } <b>
<PowerSelector controlled={true} <PowerSelector controlled={true}
value={parseInt(this.props.member.powerLevel)} value={parseInt(this.props.member.powerLevel)}
maxValue={this.state.can.modifyLevelMax}
disabled={!this.state.can.modifyLevel} disabled={!this.state.can.modifyLevel}
usersDefault={powerLevelUsersDefault}
onChange={this.onPowerChange} /> onChange={this.onPowerChange} />
</b> </b>
</div> </div>

View file

@ -910,31 +910,31 @@ module.exports = React.createClass({
<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">
<span className="mx_RoomSettings_powerLevelKey">{ _t('The default role for new room members is') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('The default role for new room members is') } </span>
<PowerSelector ref="users_default" value={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < default_user_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="users_default" value={default_user_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < default_user_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To send messages, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To send messages, you must be a') } </span>
<PowerSelector ref="events_default" value={send_level} controlled={false} disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="events_default" value={send_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To invite users into the room, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To invite users into the room, you must be a') } </span>
<PowerSelector ref="invite" value={invite_level} controlled={false} disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="invite" value={invite_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To configure the room, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To configure the room, you must be a') } </span>
<PowerSelector ref="state_default" value={state_level} controlled={false} disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="state_default" value={state_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To kick users, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To kick users, you must be a') } </span>
<PowerSelector ref="kick" value={kick_level} controlled={false} disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="kick" value={kick_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To ban users, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To ban users, you must be a') } </span>
<PowerSelector ref="ban" value={ban_level} controlled={false} disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="ban" value={ban_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
<div className="mx_RoomSettings_powerLevel"> <div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">{ _t('To remove other users\' messages, you must be a') } </span> <span className="mx_RoomSettings_powerLevelKey">{ _t('To remove other users\' messages, you must be a') } </span>
<PowerSelector ref="redact" value={redact_level} controlled={false} disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged} /> <PowerSelector ref="redact" value={redact_level} usersDefault={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged} />
</div> </div>
{ Object.keys(events_levels).map(function(event_type, i) { { Object.keys(events_levels).map(function(event_type, i) {
@ -944,7 +944,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_RoomSettings_powerLevel" key={event_type}> <div className="mx_RoomSettings_powerLevel" key={event_type}>
<span className="mx_RoomSettings_powerLevelKey">{ label } </span> <span className="mx_RoomSettings_powerLevelKey">{ label } </span>
<PowerSelector ref={"event_levels_"+event_type} value={events_levels[event_type]} onChange={self.onPowerLevelsChanged} <PowerSelector ref={"event_levels_"+event_type} value={events_levels[event_type]} usersDefault={default_user_level} onChange={self.onPowerLevelsChanged}
controlled={false} disabled={!can_change_levels || current_user_level < events_levels[event_type]} /> controlled={false} disabled={!can_change_levels || current_user_level < events_levels[event_type]} />
</div> </div>
); );

View file

@ -63,7 +63,7 @@
"This email address was not found": "This email address was not found", "This email address was not found": "This email address was not found",
"Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Your email address does not appear to be associated with a Matrix ID on this Homeserver.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Your email address does not appear to be associated with a Matrix ID on this Homeserver.",
"Default": "Default", "Default": "Default",
"User": "User", "Restricted": "Restricted",
"Moderator": "Moderator", "Moderator": "Moderator",
"Admin": "Admin", "Admin": "Admin",
"Start a chat": "Start a chat", "Start a chat": "Start a chat",
@ -150,7 +150,6 @@
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s", "%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s", "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s", "%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
"Communities": "Communities",
"Message Pinning": "Message Pinning", "Message Pinning": "Message Pinning",
"%(displayName)s is typing": "%(displayName)s is typing", "%(displayName)s is typing": "%(displayName)s is typing",
"%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing", "%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
@ -525,6 +524,7 @@
"Unverify": "Unverify", "Unverify": "Unverify",
"Verify...": "Verify...", "Verify...": "Verify...",
"No results": "No results", "No results": "No results",
"Communities": "Communities",
"Home": "Home", "Home": "Home",
"Integrations Error": "Integrations Error", "Integrations Error": "Integrations Error",
"Could not connect to the integration server": "Could not connect to the integration server", "Could not connect to the integration server": "Could not connect to the integration server",
@ -581,6 +581,7 @@
"%(items)s and %(count)s others|other": "%(items)s and %(count)s others", "%(items)s and %(count)s others|other": "%(items)s and %(count)s others",
"%(items)s and %(count)s others|one": "%(items)s and one other", "%(items)s and %(count)s others|one": "%(items)s and one other",
"%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s", "%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s",
"Custom of %(powerLevel)s": "Custom of %(powerLevel)s",
"Custom level": "Custom level", "Custom level": "Custom level",
"Room directory": "Room directory", "Room directory": "Room directory",
"Start chat": "Start chat", "Start chat": "Start chat",