mirror of
https://github.com/element-hq/element-web
synced 2024-11-24 02:05:45 +03:00
Make adding aliases direct manipulation
This commit is contained in:
parent
2903a0e712
commit
5d2f17c49a
3 changed files with 78 additions and 82 deletions
|
@ -92,9 +92,11 @@ export default class EditableItemList extends React.Component{
|
||||||
itemsLabel: PropTypes.string,
|
itemsLabel: PropTypes.string,
|
||||||
noItemsLabel: PropTypes.string,
|
noItemsLabel: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
|
newItem: PropTypes.string,
|
||||||
|
|
||||||
onItemAdded: PropTypes.func,
|
onItemAdded: PropTypes.func,
|
||||||
onItemRemoved: PropTypes.func,
|
onItemRemoved: PropTypes.func,
|
||||||
|
onNewItemChanged: PropTypes.func,
|
||||||
|
|
||||||
canEdit: PropTypes.bool,
|
canEdit: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
@ -103,22 +105,25 @@ export default class EditableItemList extends React.Component{
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!this.refs.newItem) return;
|
if (this.props.onItemAdded) this.props.onItemAdded(this.props.newItem);
|
||||||
|
|
||||||
const value = this.refs.newItem.value;
|
|
||||||
if (this.props.onItemAdded) this.props.onItemAdded(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_onItemRemoved = (index) => {
|
_onItemRemoved = (index) => {
|
||||||
if (this.props.onItemRemoved) this.props.onItemRemoved(index);
|
if (this.props.onItemRemoved) this.props.onItemRemoved(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_onNewItemChanged = (e) => {
|
||||||
|
if (this.props.onNewItemChanged) this.props.onNewItemChanged(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
_renderNewItemField() {
|
_renderNewItemField() {
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this._onAddClick} autoComplete={false}
|
<form onSubmit={this._onItemAdded} autoComplete={false}
|
||||||
noValidate={true} className="mx_EditableItemList_newItem">
|
noValidate={true} className="mx_EditableItemList_newItem">
|
||||||
<Field id="newEmailAddress" ref="newItem" label={this.props.placeholder}
|
<Field id="newEmailAddress" label={this.props.placeholder}
|
||||||
type="text" autoComplete="off" />
|
type="text" autoComplete="off" value={this.props.newItem}
|
||||||
|
onChange={this._onNewItemChanged}
|
||||||
|
/>
|
||||||
<AccessibleButton onClick={this._onItemAdded} kind="primary">
|
<AccessibleButton onClick={this._onItemAdded} kind="primary">
|
||||||
{_t("Add")}
|
{_t("Add")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018, 2019 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -23,32 +23,32 @@ const MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
const sdk = require("../../../index");
|
const sdk = require("../../../index");
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
|
import ErrorDialog from "../dialogs/ErrorDialog";
|
||||||
const Modal = require("../../../Modal");
|
const Modal = require("../../../Modal");
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class AliasSettings extends React.Component {
|
||||||
displayName: 'AliasSettings',
|
static propTypes = {
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
roomId: PropTypes.string.isRequired,
|
roomId: PropTypes.string.isRequired,
|
||||||
canSetCanonicalAlias: PropTypes.bool.isRequired,
|
canSetCanonicalAlias: PropTypes.bool.isRequired,
|
||||||
canSetAliases: PropTypes.bool.isRequired,
|
canSetAliases: PropTypes.bool.isRequired,
|
||||||
aliasEvents: PropTypes.array, // [MatrixEvent]
|
aliasEvents: PropTypes.array, // [MatrixEvent]
|
||||||
canonicalAliasEvent: PropTypes.object, // MatrixEvent
|
canonicalAliasEvent: PropTypes.object, // MatrixEvent
|
||||||
},
|
};
|
||||||
|
|
||||||
getDefaultProps: function() {
|
static defaultProps = {
|
||||||
return {
|
canSetAliases: false,
|
||||||
canSetAliases: false,
|
canSetCanonicalAlias: false,
|
||||||
canSetCanonicalAlias: false,
|
aliasEvents: [],
|
||||||
aliasEvents: [],
|
};
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState: function() {
|
constructor(props) {
|
||||||
return this.recalculateState(this.props.aliasEvents, this.props.canonicalAliasEvent);
|
super(props);
|
||||||
},
|
|
||||||
|
|
||||||
recalculateState: function(aliasEvents, canonicalAliasEvent) {
|
const aliasState = this.recalculateState(props.aliasEvents, props.canonicalAliasEvent);
|
||||||
|
this.state = Object.assign({newItem: ""}, aliasState);
|
||||||
|
}
|
||||||
|
|
||||||
|
recalculateState(aliasEvents, canonicalAliasEvent) {
|
||||||
aliasEvents = aliasEvents || [];
|
aliasEvents = aliasEvents || [];
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
@ -69,9 +69,9 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
},
|
}
|
||||||
|
|
||||||
saveSettings: function() {
|
saveSettings() {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
|
|
||||||
// save new aliases for m.room.aliases
|
// save new aliases for m.room.aliases
|
||||||
|
@ -118,9 +118,9 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return promises;
|
return promises;
|
||||||
},
|
}
|
||||||
|
|
||||||
aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events
|
aliasEventsToDictionary(aliasEvents) { // m.room.alias events
|
||||||
const dict = {};
|
const dict = {};
|
||||||
aliasEvents.forEach((event) => {
|
aliasEvents.forEach((event) => {
|
||||||
dict[event.getStateKey()] = (
|
dict[event.getStateKey()] = (
|
||||||
|
@ -128,35 +128,53 @@ module.exports = React.createClass({
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return dict;
|
return dict;
|
||||||
},
|
}
|
||||||
|
|
||||||
isAliasValid: function(alias) {
|
isAliasValid(alias) {
|
||||||
// XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
|
// XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
|
||||||
return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
|
return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
|
||||||
},
|
}
|
||||||
|
|
||||||
getAliasOperations: function() {
|
getAliasOperations() {
|
||||||
const oldAliases = this.aliasEventsToDictionary(this.props.aliasEvents);
|
const oldAliases = this.aliasEventsToDictionary(this.props.aliasEvents);
|
||||||
return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
|
return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
|
||||||
},
|
}
|
||||||
|
|
||||||
onNewAliasChanged: function(value) {
|
onNewAliasChanged = (value) => {
|
||||||
this.setState({newAlias: value});
|
this.setState({newAlias: value});
|
||||||
},
|
};
|
||||||
|
|
||||||
onLocalAliasAdded: function(alias) {
|
onLocalAliasAdded = (alias) => {
|
||||||
if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases
|
if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases
|
||||||
|
|
||||||
const localDomain = MatrixClientPeg.get().getDomain();
|
const localDomain = MatrixClientPeg.get().getDomain();
|
||||||
if (!alias.includes(':')) alias += ':' + localDomain;
|
if (!alias.includes(':')) alias += ':' + localDomain;
|
||||||
if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
|
if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
|
||||||
this.state.domainToAliases[localDomain] = this.state.domainToAliases[localDomain] || [];
|
MatrixClientPeg.get().createAlias(alias, this.props.roomId).then(() => {
|
||||||
this.state.domainToAliases[localDomain].push(alias);
|
const localAliases = this.state.domainToAliases[localDomain] || [];
|
||||||
|
const domainAliases = Object.assign({}, this.state.domainToAliases);
|
||||||
|
domainAliases[localDomain] = [...localAliases, alias];
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
domainToAliases: this.state.domainToAliases,
|
domainToAliases: domainAliases,
|
||||||
// Reset the add field
|
// Reset the add field
|
||||||
newAlias: "",
|
newAlias: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.props.canonicalAlias) {
|
||||||
|
this.setState({
|
||||||
|
canonicalAlias: alias,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
Modal.createTrackedDialog('Error creating alias', '', ErrorDialog, {
|
||||||
|
title: _t("Error creating alias"),
|
||||||
|
description: _t(
|
||||||
|
"There was an error creating that alias. It may not be allowed by the server " +
|
||||||
|
"or a temporary failure occurred."
|
||||||
|
),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
@ -165,30 +183,9 @@ module.exports = React.createClass({
|
||||||
description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
|
description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!this.props.canonicalAlias) {
|
onLocalAliasDeleted = (index) => {
|
||||||
this.setState({
|
|
||||||
canonicalAlias: alias,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onLocalAliasChanged: function(alias, index) {
|
|
||||||
if (alias === "") return; // hit the delete button to delete please
|
|
||||||
const localDomain = MatrixClientPeg.get().getDomain();
|
|
||||||
if (!alias.includes(':')) alias += ':' + localDomain;
|
|
||||||
if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
|
|
||||||
this.state.domainToAliases[localDomain][index] = alias;
|
|
||||||
} else {
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
||||||
Modal.createTrackedDialog('Invalid address format', '', ErrorDialog, {
|
|
||||||
title: _t('Invalid address format'),
|
|
||||||
description: _t('\'%(alias)s\' is not a valid format for an address', { alias: alias }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onLocalAliasDeleted: function(index) {
|
|
||||||
const localDomain = MatrixClientPeg.get().getDomain();
|
const localDomain = MatrixClientPeg.get().getDomain();
|
||||||
// It's a bit naughty to directly manipulate this.state, and React would
|
// It's a bit naughty to directly manipulate this.state, and React would
|
||||||
// normally whine at you, but it can't see us doing the splice. Given we
|
// normally whine at you, but it can't see us doing the splice. Given we
|
||||||
|
@ -204,17 +201,15 @@ module.exports = React.createClass({
|
||||||
canonicalAlias: null,
|
canonicalAlias: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
onCanonicalAliasChange: function(event) {
|
onCanonicalAliasChange = (event) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
canonicalAlias: event.target.value,
|
canonicalAlias: event.target.value,
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
|
|
||||||
render: function() {
|
render() {
|
||||||
const self = this;
|
|
||||||
const EditableText = sdk.getComponent("elements.EditableText");
|
|
||||||
const EditableItemList = sdk.getComponent("elements.EditableItemList");
|
const EditableItemList = sdk.getComponent("elements.EditableItemList");
|
||||||
const localDomain = MatrixClientPeg.get().getDomain();
|
const localDomain = MatrixClientPeg.get().getDomain();
|
||||||
|
|
||||||
|
@ -227,8 +222,8 @@ module.exports = React.createClass({
|
||||||
element='select' id='canonicalAlias' label={_t('Main address')}>
|
element='select' id='canonicalAlias' label={_t('Main address')}>
|
||||||
<option value="" key="unset">{ _t('not specified') }</option>
|
<option value="" key="unset">{ _t('not specified') }</option>
|
||||||
{
|
{
|
||||||
Object.keys(self.state.domainToAliases).map((domain, i) => {
|
Object.keys(this.state.domainToAliases).map((domain, i) => {
|
||||||
return self.state.domainToAliases[domain].map((alias, j) => {
|
return this.state.domainToAliases[domain].map((alias, j) => {
|
||||||
if (alias === this.state.canonicalAlias) found = true;
|
if (alias === this.state.canonicalAlias) found = true;
|
||||||
return (
|
return (
|
||||||
<option value={alias} key={i + "_" + j}>
|
<option value={alias} key={i + "_" + j}>
|
||||||
|
@ -239,7 +234,7 @@ module.exports = React.createClass({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
found || !this.stateCanonicalAlias ? '' :
|
found || !this.state.canonicalAlias ? '' :
|
||||||
<option value={ this.state.canonicalAlias } key='arbitrary'>
|
<option value={ this.state.canonicalAlias } key='arbitrary'>
|
||||||
{ this.state.canonicalAlias }
|
{ this.state.canonicalAlias }
|
||||||
</option>
|
</option>
|
||||||
|
@ -280,7 +275,6 @@ module.exports = React.createClass({
|
||||||
onNewItemChanged={this.onNewAliasChanged}
|
onNewItemChanged={this.onNewAliasChanged}
|
||||||
canEdit={this.props.canSetAliases}
|
canEdit={this.props.canSetAliases}
|
||||||
onItemAdded={this.onLocalAliasAdded}
|
onItemAdded={this.onLocalAliasAdded}
|
||||||
onItemEdited={this.onLocalAliasChanged}
|
|
||||||
onItemRemoved={this.onLocalAliasDeleted}
|
onItemRemoved={this.onLocalAliasDeleted}
|
||||||
itemsLabel={_t('Local addresses for this room:')}
|
itemsLabel={_t('Local addresses for this room:')}
|
||||||
noItemsLabel={_t('This room has no local addresses')}
|
noItemsLabel={_t('This room has no local addresses')}
|
||||||
|
@ -288,10 +282,8 @@ module.exports = React.createClass({
|
||||||
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
|
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{ remote_aliases_section }
|
{ remote_aliases_section }
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
});
|
};
|
||||||
|
|
|
@ -804,10 +804,10 @@
|
||||||
"Hide Stickers": "Hide Stickers",
|
"Hide Stickers": "Hide Stickers",
|
||||||
"Show Stickers": "Show Stickers",
|
"Show Stickers": "Show Stickers",
|
||||||
"Jump to first unread message.": "Jump to first unread message.",
|
"Jump to first unread message.": "Jump to first unread message.",
|
||||||
|
"Error creating alias": "Error creating alias",
|
||||||
|
"There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.",
|
||||||
"Invalid alias format": "Invalid alias format",
|
"Invalid alias format": "Invalid alias format",
|
||||||
"'%(alias)s' is not a valid format for an alias": "'%(alias)s' is not a valid format for an alias",
|
"'%(alias)s' is not a valid format for an alias": "'%(alias)s' is not a valid format for an alias",
|
||||||
"Invalid address format": "Invalid address format",
|
|
||||||
"'%(alias)s' is not a valid format for an address": "'%(alias)s' is not a valid format for an address",
|
|
||||||
"Main address": "Main address",
|
"Main address": "Main address",
|
||||||
"not specified": "not specified",
|
"not specified": "not specified",
|
||||||
"not set": "not set",
|
"not set": "not set",
|
||||||
|
@ -925,7 +925,6 @@
|
||||||
"Verify...": "Verify...",
|
"Verify...": "Verify...",
|
||||||
"Join": "Join",
|
"Join": "Join",
|
||||||
"No results": "No results",
|
"No results": "No results",
|
||||||
"Delete": "Delete",
|
|
||||||
"Communities": "Communities",
|
"Communities": "Communities",
|
||||||
"Home": "Home",
|
"Home": "Home",
|
||||||
"You cannot delete this image. (%(code)s)": "You cannot delete this image. (%(code)s)",
|
"You cannot delete this image. (%(code)s)": "You cannot delete this image. (%(code)s)",
|
||||||
|
|
Loading…
Reference in a new issue