diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js
new file mode 100644
index 0000000000..267244759a
--- /dev/null
+++ b/src/components/views/elements/EditableItemList.js
@@ -0,0 +1,149 @@
+/*
+Copyright 2017 New Vector 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.
+*/
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import sdk from '../../../index';
+import {_t} from '../../../languageHandler.js';
+
+const EditableItem = React.createClass({
+ displayName: 'EditableItem',
+
+ propTypes: {
+ initialValue: PropTypes.string,
+ index: PropTypes.number,
+ placeholder: PropTypes.string,
+
+ onChange: PropTypes.func,
+ onRemove: PropTypes.func,
+ onAdd: PropTypes.func,
+
+ addOnChange: PropTypes.bool,
+ },
+
+ onChange: function(value) {
+ this.setState({ value });
+ if (this.props.onChange) this.props.onChange(value, this.props.index);
+ if (this.props.addOnChange && this.props.onAdd) this.props.onAdd(value);
+ },
+
+ onRemove: function() {
+ if (this.props.onRemove) this.props.onRemove(this.props.index);
+ },
+
+ onAdd: function() {
+ if (this.props.onAdd) this.props.onAdd(this.state.value);
+ },
+
+ render: function() {
+ const EditableText = sdk.getComponent('elements.EditableText');
+ return
+
+ { this.props.onAdd ?
+
+
+
+ :
+
+
+
+ }
+
;
+ },
+});
+
+module.exports = React.createClass({
+ displayName: 'EditableItemList',
+
+ propTypes: {
+ items: PropTypes.arrayOf(PropTypes.string).isRequired,
+ onNewItemChanged: PropTypes.func,
+ onItemAdded: PropTypes.func,
+ onItemEdited: PropTypes.func,
+ onItemRemoved: PropTypes. func,
+ },
+
+ getDefaultProps: function() {
+ return {
+ onItemAdded: () => {},
+ onItemEdited: () => {},
+ onItemRemoved: () => {},
+ onNewItemChanged: () => {},
+ };
+ },
+
+ onItemAdded: function(value) {
+ this.props.onItemAdded(value);
+ },
+
+ onItemEdited: function(value, index) {
+ if (value.length === 0) {
+ this.onItemRemoved(index);
+ } else {
+ this.onItemEdited(value, index);
+ }
+ },
+
+ onItemRemoved: function(index) {
+ this.props.onItemRemoved(index);
+ },
+
+ onNewItemChanged: function(value) {
+ this.props.onNewItemChanged(value);
+ },
+
+ render: function() {
+ const editableItems = this.props.items.map((item, index) => {
+ return ;
+ });
+
+ const label = this.props.items.length > 0 ?
+ this.props.itemsLabel : this.props.noItemsLabel;
+
+ return (
+
+ { label }
+
+ { editableItems }
+
+
);
+ },
+});
diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js
index ea3bad390f..94301c432d 100644
--- a/src/components/views/room_settings/AliasSettings.js
+++ b/src/components/views/room_settings/AliasSettings.js
@@ -136,24 +136,25 @@ module.exports = React.createClass({
return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
},
- onAliasAdded: function(alias) {
+ onNewAliasChanged: function(value) {
+ this.setState({newAlias: value});
+ },
+
+ onLocalAliasAdded: function(alias) {
if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases
- if (this.isAliasValid(alias)) {
- // add this alias to the domain to aliases dict
- var domain = alias.replace(/^.*?:/, '');
- // XXX: do we need to deep copy aliases before editing it?
- this.state.domainToAliases[domain] = this.state.domainToAliases[domain] || [];
- this.state.domainToAliases[domain].push(alias);
- this.setState({
- domainToAliases: this.state.domainToAliases
- });
+ const localDomain = MatrixClientPeg.get().getDomain();
+ if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
+ this.state.domainToAliases[localDomain] = this.state.domainToAliases[localDomain] || [];
+ this.state.domainToAliases[localDomain].push(alias);
- // reset the add field
- this.refs.add_alias.setValue(''); // FIXME
- }
- else {
- var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ this.setState({
+ domainToAliases: this.state.domainToAliases,
+ // Reset the add field
+ newAlias: "",
+ });
+ } else {
+ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Invalid alias format', '', ErrorDialog, {
title: _t('Invalid alias format'),
description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
@@ -161,15 +162,13 @@ module.exports = React.createClass({
}
},
- onAliasChanged: function(domain, index, alias) {
+ onLocalAliasChanged: function(alias, index) {
if (alias === "") return; // hit the delete button to delete please
- var oldAlias;
- if (this.isAliasValid(alias)) {
- oldAlias = this.state.domainToAliases[domain][index];
- this.state.domainToAliases[domain][index] = alias;
- }
- else {
- var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
+ const localDomain = MatrixClientPeg.get().getDomain();
+ 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 }),
@@ -177,15 +176,16 @@ module.exports = React.createClass({
}
},
- onAliasDeleted: function(domain, index) {
+ onLocalAliasDeleted: function(index) {
+ const localDomain = MatrixClientPeg.get().getDomain();
// 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
// promptly setState anyway, it's just about acceptable. The alternative
// would be to arbitrarily deepcopy to a temp variable and then setState
// that, but why bother when we can cut this corner.
- var alias = this.state.domainToAliases[domain].splice(index, 1);
+ this.state.domainToAliases[localDomain].splice(index, 1);
this.setState({
- domainToAliases: this.state.domainToAliases
+ domainToAliases: this.state.domainToAliases,
});
},
@@ -198,6 +198,7 @@ module.exports = React.createClass({
render: function() {
var self = this;
var EditableText = sdk.getComponent("elements.EditableText");
+ var EditableItemList = sdk.getComponent("elements.EditableItemList");
var localDomain = MatrixClientPeg.get().getDomain();
var canonical_alias_section;
@@ -257,58 +258,24 @@ module.exports = React.createClass({
{ _t('The main address for this room is') }: { canonical_alias_section }
-
- { (this.state.domainToAliases[localDomain] &&
- this.state.domainToAliases[localDomain].length > 0)
- ? _t('Local addresses for this room:')
- : _t('This room has no local addresses') }
-
-
- { (this.state.domainToAliases[localDomain] || []).map((alias, i) => {
- var deleteButton;
- if (this.props.canSetAliases) {
- deleteButton = (
-
- );
- }
- return (
-
-
-
- { deleteButton }
-
-
- );
- })}
-
- { this.props.canSetAliases ?
-
-
-
-
-
-
: ""
- }
-
+
{ remote_aliases_section }
);
- }
+ },
});