From 2903a0e71218830c8b1c9ef072f1e8d98f589a67 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 8 Feb 2019 09:11:30 -0700 Subject: [PATCH] Rework EditableItemList to support mxField Also improves upon the general UX to be a bit friendlier for direct manipulation things. --- res/css/views/elements/_EditableItemList.scss | 59 +++-- .../views/elements/EditableItemList.js | 212 +++++++++--------- .../views/room_settings/AliasSettings.js | 16 +- 3 files changed, 131 insertions(+), 156 deletions(-) diff --git a/res/css/views/elements/_EditableItemList.scss b/res/css/views/elements/_EditableItemList.scss index 9fbb39aa17..be96d811d3 100644 --- a/res/css/views/elements/_EditableItemList.scss +++ b/res/css/views/elements/_EditableItemList.scss @@ -1,5 +1,5 @@ /* -Copyright 2017 New Vector Ltd. +Copyright 2017, 2019 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. @@ -16,47 +16,38 @@ limitations under the License. .mx_EditableItemList { margin-top: 12px; - margin-bottom: 0px; + margin-bottom: 10px; } .mx_EditableItem { - display: flex; - margin-left: 56px; + margin-bottom: 5px; + margin-left: 15px; } -.mx_EditableItem .mx_EditableItem_editable { - border: 0px; - border-bottom: 1px solid $strong-input-border-color; - padding: 0px; - min-width: 240px; - max-width: 400px; - margin-bottom: 16px; -} - -.mx_EditableItem .mx_EditableItem_editable:focus { - border-bottom: 1px solid $accent-color; - outline: none; - box-shadow: none; -} - -.mx_EditableItem .mx_EditableItem_editablePlaceholder { - color: $settings-grey-fg-color; -} - -.mx_EditableItem .mx_EditableItem_addButton, -.mx_EditableItem .mx_EditableItem_removeButton { - padding-left: 0.5em; - position: relative; +.mx_EditableItem_delete { + margin-right: 5px; cursor: pointer; - - visibility: hidden; + vertical-align: middle; } -.mx_EditableItem:hover .mx_EditableItem_addButton, -.mx_EditableItem:hover .mx_EditableItem_removeButton { - visibility: visible; +.mx_EditableItem_email { + vertical-align: middle; +} + +.mx_EditableItem_promptText { + margin-right: 10px; +} + +.mx_EditableItem_confirmBtn { + margin-right: 5px; +} + +.mx_EditableItemList_newItem .mx_Field input { + // Use 100% of the space available for the input, but don't let the 10px + // padding on either side of the input to push it out of alignment. + width: calc(100% - 20px); } .mx_EditableItemList_label { - margin-bottom: 8px; -} + margin-bottom: 5px; +} \ No newline at end of file diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index 7d96b1fd20..b87b2e78a5 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -1,5 +1,5 @@ /* -Copyright 2017 New Vector Ltd. +Copyright 2017, 2019 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. @@ -18,140 +18,132 @@ import React from 'react'; import PropTypes from 'prop-types'; import sdk from '../../../index'; import {_t} from '../../../languageHandler.js'; +import Field from "./Field"; +import AccessibleButton from "./AccessibleButton"; -const EditableItem = React.createClass({ - displayName: 'EditableItem', - - propTypes: { - initialValue: PropTypes.string, +export class EditableItem extends React.Component { + static propTypes = { index: PropTypes.number, + value: PropTypes.string, + onRemove: PropTypes.func, + }; + + constructor() { + super(); + + this.state = { + verifyRemove: false, + }; + } + + _onRemove = (e) => { + e.stopPropagation(); + e.preventDefault(); + + this.setState({verifyRemove: true}); + }; + + _onDontRemove = (e) => { + e.stopPropagation(); + e.preventDefault(); + + this.setState({verifyRemove: false}); + }; + + _onActuallyRemove = (e) => { + e.stopPropagation(); + e.preventDefault(); + + if (this.props.onRemove) this.props.onRemove(this.props.index); + this.setState({verifyRemove: false}); + }; + + render() {if (this.state.verifyRemove) { + return ( +
+ + {_t("Are you sure?")} + + + {_t("Yes")} + + + {_t("No")} + +
+ ); + } + + return ( +
+ {_t("Remove")} + {this.props.value} +
+ ); + } +} + +export default class EditableItemList extends React.Component{ + static propTypes = { + items: PropTypes.arrayOf(PropTypes.string).isRequired, + itemsLabel: PropTypes.string, + noItemsLabel: PropTypes.string, 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 ? -
- {_t("Add")} -
- : -
- {_t("Delete")} -
- } -
; - }, -}); - -// TODO: Make this use the new Field element -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, canEdit: PropTypes.bool, - }, + }; - getDefaultProps: function() { - return { - onItemAdded: () => {}, - onItemEdited: () => {}, - onItemRemoved: () => {}, - onNewItemChanged: () => {}, - }; - }, + _onItemAdded = (e) => { + e.stopPropagation(); + e.preventDefault(); - onItemAdded: function(value) { - this.props.onItemAdded(value); - }, + if (!this.refs.newItem) return; - onItemEdited: function(value, index) { - if (value.length === 0) { - this.onItemRemoved(index); - } else { - this.props.onItemEdited(value, index); - } - }, + const value = this.refs.newItem.value; + if (this.props.onItemAdded) this.props.onItemAdded(value); + }; - onItemRemoved: function(index) { - this.props.onItemRemoved(index); - }, + _onItemRemoved = (index) => { + if (this.props.onItemRemoved) this.props.onItemRemoved(index); + }; - onNewItemChanged: function(value) { - this.props.onNewItemChanged(value); - }, + _renderNewItemField() { + return ( +
+ + + {_t("Add")} + + + ) + } - render: function() { + render() { const editableItems = this.props.items.map((item, index) => { return ; }); - const label = this.props.items.length > 0 ? - this.props.itemsLabel : this.props.noItemsLabel; + const label = this.props.items.length > 0 ? this.props.itemsLabel : this.props.noItemsLabel; return (
{ label }
{ editableItems } - { this.props.canEdit ? - // This is slightly evil; we want a new instance of - // EditableItem when the list grows. To make sure it's - // reset to its initial state. - :
- } + { this.props.canEdit ? this._renderNewItemField() :
}
); - }, -}); + } +} diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index 827656e770..a56b4903bc 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -259,21 +259,13 @@ module.exports = React.createClass({
{ _t("Remote addresses for this room:") }
-
+
    { this.state.remoteDomains.map((domain, i) => { - return this.state.domainToAliases[domain].map(function(alias, j) { - return ( -
    - -
    - ); + return this.state.domainToAliases[domain].map((alias, j) => { + return
  • {alias}
  • ; }); }) } -
+
); }