Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 2903a0e

Browse files
committed
Rework EditableItemList to support mxField
Also improves upon the general UX to be a bit friendlier for direct manipulation things.
1 parent 86c49d5 commit 2903a0e

File tree

3 files changed

+128
-153
lines changed

3 files changed

+128
-153
lines changed
Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2017 New Vector Ltd.
2+
Copyright 2017, 2019 New Vector Ltd.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -16,47 +16,38 @@ limitations under the License.
1616

1717
.mx_EditableItemList {
1818
margin-top: 12px;
19-
margin-bottom: 0px;
19+
margin-bottom: 10px;
2020
}
2121

2222
.mx_EditableItem {
23-
display: flex;
24-
margin-left: 56px;
23+
margin-bottom: 5px;
24+
margin-left: 15px;
2525
}
2626

27-
.mx_EditableItem .mx_EditableItem_editable {
28-
border: 0px;
29-
border-bottom: 1px solid $strong-input-border-color;
30-
padding: 0px;
31-
min-width: 240px;
32-
max-width: 400px;
33-
margin-bottom: 16px;
27+
.mx_EditableItem_delete {
28+
margin-right: 5px;
29+
cursor: pointer;
30+
vertical-align: middle;
3431
}
3532

36-
.mx_EditableItem .mx_EditableItem_editable:focus {
37-
border-bottom: 1px solid $accent-color;
38-
outline: none;
39-
box-shadow: none;
33+
.mx_EditableItem_email {
34+
vertical-align: middle;
4035
}
4136

42-
.mx_EditableItem .mx_EditableItem_editablePlaceholder {
43-
color: $settings-grey-fg-color;
37+
.mx_EditableItem_promptText {
38+
margin-right: 10px;
4439
}
4540

46-
.mx_EditableItem .mx_EditableItem_addButton,
47-
.mx_EditableItem .mx_EditableItem_removeButton {
48-
padding-left: 0.5em;
49-
position: relative;
50-
cursor: pointer;
51-
52-
visibility: hidden;
41+
.mx_EditableItem_confirmBtn {
42+
margin-right: 5px;
5343
}
5444

55-
.mx_EditableItem:hover .mx_EditableItem_addButton,
56-
.mx_EditableItem:hover .mx_EditableItem_removeButton {
57-
visibility: visible;
45+
.mx_EditableItemList_newItem .mx_Field input {
46+
// Use 100% of the space available for the input, but don't let the 10px
47+
// padding on either side of the input to push it out of alignment.
48+
width: calc(100% - 20px);
5849
}
5950

6051
.mx_EditableItemList_label {
61-
margin-bottom: 8px;
62-
}
52+
margin-bottom: 5px;
53+
}
Lines changed: 104 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2017 New Vector Ltd.
2+
Copyright 2017, 2019 New Vector Ltd.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -18,140 +18,132 @@ import React from 'react';
1818
import PropTypes from 'prop-types';
1919
import sdk from '../../../index';
2020
import {_t} from '../../../languageHandler.js';
21+
import Field from "./Field";
22+
import AccessibleButton from "./AccessibleButton";
2123

22-
const EditableItem = React.createClass({
23-
displayName: 'EditableItem',
24-
25-
propTypes: {
26-
initialValue: PropTypes.string,
24+
export class EditableItem extends React.Component {
25+
static propTypes = {
2726
index: PropTypes.number,
28-
placeholder: PropTypes.string,
29-
30-
onChange: PropTypes.func,
27+
value: PropTypes.string,
3128
onRemove: PropTypes.func,
32-
onAdd: PropTypes.func,
29+
};
3330

34-
addOnChange: PropTypes.bool,
35-
},
31+
constructor() {
32+
super();
3633

37-
onChange: function(value) {
38-
this.setState({ value });
39-
if (this.props.onChange) this.props.onChange(value, this.props.index);
40-
if (this.props.addOnChange && this.props.onAdd) this.props.onAdd(value);
41-
},
34+
this.state = {
35+
verifyRemove: false,
36+
};
37+
}
4238

43-
onRemove: function() {
44-
if (this.props.onRemove) this.props.onRemove(this.props.index);
45-
},
46-
47-
onAdd: function() {
48-
if (this.props.onAdd) this.props.onAdd(this.state.value);
49-
},
50-
51-
render: function() {
52-
const EditableText = sdk.getComponent('elements.EditableText');
53-
return <div className="mx_EditableItem">
54-
<EditableText
55-
className="mx_EditableItem_editable"
56-
placeholderClassName="mx_EditableItem_editablePlaceholder"
57-
placeholder={this.props.placeholder}
58-
blurToCancel={false}
59-
editable={true}
60-
initialValue={this.props.initialValue}
61-
onValueChanged={this.onChange} />
62-
{ this.props.onAdd ?
63-
<div className="mx_EditableItem_addButton">
64-
<img className="mx_filterFlipColor"
65-
src={require("../../../../res/img/plus.svg")} width="14" height="14"
66-
alt={_t("Add")} onClick={this.onAdd} />
67-
</div>
68-
:
69-
<div className="mx_EditableItem_removeButton">
70-
<img className="mx_filterFlipColor"
71-
src={require("../../../../res/img/cancel-small.svg")} width="14" height="14"
72-
alt={_t("Delete")} onClick={this.onRemove} />
73-
</div>
74-
}
75-
</div>;
76-
},
77-
});
78-
79-
// TODO: Make this use the new Field element
80-
module.exports = React.createClass({
81-
displayName: 'EditableItemList',
82-
83-
propTypes: {
84-
items: PropTypes.arrayOf(PropTypes.string).isRequired,
85-
onNewItemChanged: PropTypes.func,
86-
onItemAdded: PropTypes.func,
87-
onItemEdited: PropTypes.func,
88-
onItemRemoved: PropTypes.func,
39+
_onRemove = (e) => {
40+
e.stopPropagation();
41+
e.preventDefault();
8942

90-
canEdit: PropTypes.bool,
91-
},
92-
93-
getDefaultProps: function() {
94-
return {
95-
onItemAdded: () => {},
96-
onItemEdited: () => {},
97-
onItemRemoved: () => {},
98-
onNewItemChanged: () => {},
99-
};
100-
},
43+
this.setState({verifyRemove: true});
44+
};
10145

102-
onItemAdded: function(value) {
103-
this.props.onItemAdded(value);
104-
},
46+
_onDontRemove = (e) => {
47+
e.stopPropagation();
48+
e.preventDefault();
10549

106-
onItemEdited: function(value, index) {
107-
if (value.length === 0) {
108-
this.onItemRemoved(index);
109-
} else {
110-
this.props.onItemEdited(value, index);
111-
}
112-
},
50+
this.setState({verifyRemove: false});
51+
};
11352

114-
onItemRemoved: function(index) {
115-
this.props.onItemRemoved(index);
116-
},
53+
_onActuallyRemove = (e) => {
54+
e.stopPropagation();
55+
e.preventDefault();
11756

118-
onNewItemChanged: function(value) {
119-
this.props.onNewItemChanged(value);
120-
},
57+
if (this.props.onRemove) this.props.onRemove(this.props.index);
58+
this.setState({verifyRemove: false});
59+
};
60+
61+
render() {if (this.state.verifyRemove) {
62+
return (
63+
<div className="mx_EditableItem">
64+
<span className="mx_EditableItem_promptText">
65+
{_t("Are you sure?")}
66+
</span>
67+
<AccessibleButton onClick={this._onActuallyRemove} kind="primary_sm"
68+
className="mx_EditableItem_confirmBtn">
69+
{_t("Yes")}
70+
</AccessibleButton>
71+
<AccessibleButton onClick={this._onDontRemove} kind="danger_sm"
72+
className="mx_EditableItem_confirmBtn">
73+
{_t("No")}
74+
</AccessibleButton>
75+
</div>
76+
);
77+
}
78+
79+
return (
80+
<div className="mx_EditableItem">
81+
<img src={require("../../../../res/img/feather-icons/cancel.svg")} width={14} height={14}
82+
onClick={this._onRemove} className="mx_EditableItem_delete" alt={_t("Remove")} />
83+
<span className="mx_EditableItem_item">{this.props.value}</span>
84+
</div>
85+
);
86+
}
87+
}
88+
89+
export default class EditableItemList extends React.Component{
90+
static propTypes = {
91+
items: PropTypes.arrayOf(PropTypes.string).isRequired,
92+
itemsLabel: PropTypes.string,
93+
noItemsLabel: PropTypes.string,
94+
placeholder: PropTypes.string,
12195

122-
render: function() {
96+
onItemAdded: PropTypes.func,
97+
onItemRemoved: PropTypes.func,
98+
99+
canEdit: PropTypes.bool,
100+
};
101+
102+
_onItemAdded = (e) => {
103+
e.stopPropagation();
104+
e.preventDefault();
105+
106+
if (!this.refs.newItem) return;
107+
108+
const value = this.refs.newItem.value;
109+
if (this.props.onItemAdded) this.props.onItemAdded(value);
110+
};
111+
112+
_onItemRemoved = (index) => {
113+
if (this.props.onItemRemoved) this.props.onItemRemoved(index);
114+
};
115+
116+
_renderNewItemField() {
117+
return (
118+
<form onSubmit={this._onAddClick} autoComplete={false}
119+
noValidate={true} className="mx_EditableItemList_newItem">
120+
<Field id="newEmailAddress" ref="newItem" label={this.props.placeholder}
121+
type="text" autoComplete="off" />
122+
<AccessibleButton onClick={this._onItemAdded} kind="primary">
123+
{_t("Add")}
124+
</AccessibleButton>
125+
</form>
126+
)
127+
}
128+
129+
render() {
123130
const editableItems = this.props.items.map((item, index) => {
124131
return <EditableItem
125132
key={index}
126133
index={index}
127-
initialValue={item}
128-
onChange={this.onItemEdited}
129-
onRemove={this.onItemRemoved}
130-
placeholder={this.props.placeholder}
134+
value={item}
135+
onRemove={this._onItemRemoved}
131136
/>;
132137
});
133138

134-
const label = this.props.items.length > 0 ?
135-
this.props.itemsLabel : this.props.noItemsLabel;
139+
const label = this.props.items.length > 0 ? this.props.itemsLabel : this.props.noItemsLabel;
136140

137141
return (<div className="mx_EditableItemList">
138142
<div className="mx_EditableItemList_label">
139143
{ label }
140144
</div>
141145
{ editableItems }
142-
{ this.props.canEdit ?
143-
// This is slightly evil; we want a new instance of
144-
// EditableItem when the list grows. To make sure it's
145-
// reset to its initial state.
146-
<EditableItem
147-
key={editableItems.length}
148-
initialValue={this.props.newItem}
149-
onAdd={this.onItemAdded}
150-
onChange={this.onNewItemChanged}
151-
addOnChange={true}
152-
placeholder={this.props.placeholder}
153-
/> : <div />
154-
}
146+
{ this.props.canEdit ? this._renderNewItemField() : <div /> }
155147
</div>);
156-
},
157-
});
148+
}
149+
}

src/components/views/room_settings/AliasSettings.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -259,21 +259,13 @@ module.exports = React.createClass({
259259
<div>
260260
{ _t("Remote addresses for this room:") }
261261
</div>
262-
<div>
262+
<ul>
263263
{ this.state.remoteDomains.map((domain, i) => {
264-
return this.state.domainToAliases[domain].map(function(alias, j) {
265-
return (
266-
<div key={i + "_" + j}>
267-
<EditableText
268-
className="mx_AliasSettings_alias mx_AliasSettings_editable"
269-
blurToCancel={false}
270-
editable={false}
271-
initialValue={alias} />
272-
</div>
273-
);
264+
return this.state.domainToAliases[domain].map((alias, j) => {
265+
return <li key={i + "_" + j}>{alias}</li>;
274266
});
275267
}) }
276-
</div>
268+
</ul>
277269
</div>
278270
);
279271
}

0 commit comments

Comments
 (0)