diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/channel_header.jsx | 27 | ||||
-rw-r--r-- | web/react/components/edit_channel_modal.jsx | 174 | ||||
-rw-r--r-- | web/react/components/navbar.jsx | 56 | ||||
-rw-r--r-- | web/react/components/toggle_modal_button.jsx | 17 |
4 files changed, 139 insertions, 135 deletions
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 8c721348f..06d5db8b0 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -4,6 +4,7 @@ import NavbarSearchBox from './search_bar.jsx'; import MessageWrapper from './message_wrapper.jsx'; import PopoverListMembers from './popover_list_members.jsx'; +import EditChannelModal from './edit_channel_modal.jsx'; import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx'; import ChannelInfoModal from './channel_info_modal.jsx'; import ChannelInviteModal from './channel_invite_modal.jsx'; @@ -167,17 +168,13 @@ export default class ChannelHeader extends React.Component { key='edit_header_direct' role='presentation' > - <a + <ToggleModalButton role='menuitem' - href='#' - data-toggle='modal' - data-target='#edit_channel' - data-header={channel.header} - data-title={channel.display_name} - data-channelid={channel.id} + dialogType={EditChannelModal} + dialogProps={{channel}} > {'Set Channel Header...'} - </a> + </ToggleModalButton> </li> ); } else { @@ -235,17 +232,13 @@ export default class ChannelHeader extends React.Component { key='set_channel_header' role='presentation' > - <a + <ToggleModalButton role='menuitem' - href='#' - data-toggle='modal' - data-target='#edit_channel' - data-header={channel.header} - data-title={channel.display_name} - data-channelid={channel.id} + dialogType={EditChannelModal} + dialogProps={{channel}} > - {'Set '}{channelTerm}{' Header...'} - </a> + {`Set ${channelTerm} Header...`} + </ToggleModalButton> </li> ); dropdownContents.push( diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx index 80dab4a57..487ae6964 100644 --- a/web/react/components/edit_channel_modal.jsx +++ b/web/react/components/edit_channel_modal.jsx @@ -3,39 +3,51 @@ import * as Client from '../utils/client.jsx'; import * as AsyncClient from '../utils/async_client.jsx'; +import * as Utils from '../utils/utils.jsx'; + +const Modal = ReactBootstrap.Modal; export default class EditChannelModal extends React.Component { constructor(props) { super(props); this.handleEdit = this.handleEdit.bind(this); - this.handleUserInput = this.handleUserInput.bind(this); - this.handleClose = this.handleClose.bind(this); + this.onShow = this.onShow.bind(this); - this.handleShown = this.handleShown.bind(this); + this.onHide = this.onHide.bind(this); this.state = { - header: '', - title: '', - channelId: '', serverError: '' }; } + + componentDidMount() { + if (this.props.show) { + this.onShow(); + } + } + + componentDidUpdate(prevProps) { + if (this.props.show && !prevProps.show) { + this.onShow(); + } + } + handleEdit() { var data = {}; - data.channel_id = this.state.channelId; + data.channel_id = this.props.channel.id; if (data.channel_id.length !== 26) { return; } - data.channel_header = this.state.header.trim(); + data.channel_header = ReactDOM.findDOMNode(this.refs.textarea).value; Client.updateChannelHeader(data, () => { this.setState({serverError: ''}); - AsyncClient.getChannel(this.state.channelId); - $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide'); + AsyncClient.getChannel(this.props.channel.id); + this.onHide(); }, (err) => { if (err.message === 'Invalid channel_header parameter') { @@ -46,105 +58,69 @@ export default class EditChannelModal extends React.Component { } ); } - handleUserInput(e) { - this.setState({header: e.target.value}); - } - handleClose() { - this.setState({header: '', serverError: ''}); - } - onShow(e) { - const button = e.relatedTarget; - this.setState({header: $(button).attr('data-header'), title: $(button).attr('data-title'), channelId: $(button).attr('data-channelid'), serverError: ''}); - } - handleShown() { - $('#edit_channel #edit_header').focus(); - } - componentDidMount() { - $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow); - $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose); - $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.handleShown); + + onShow() { + const textarea = ReactDOM.findDOMNode(this.refs.textarea); + Utils.placeCaretAtEnd(textarea); } - componentWillUnmount() { - $(ReactDOM.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose); + + onHide() { + this.setState({ + serverError: '' + }); + + this.props.onHide(); } + render() { var serverError = null; if (this.state.serverError) { serverError = <div className='form-group has-error'><br/><label className='control-label'>{this.state.serverError}</label></div>; } - var editTitle = ( - <h4 - className='modal-title' - ref='title' - > - {'Edit Header'} - </h4> - ); - if (this.state.title) { - editTitle = ( - <h4 - className='modal-title' - ref='title' - > - {'Edit Header for '}<span className='name'>{this.state.title}</span> - </h4> - ); - } - return ( - <div - className='modal fade' - ref='modal' - id='edit_channel' - role='dialog' - tabIndex='-1' - aria-hidden='true' + <Modal + show={this.props.show} + onHide={this.onHide} > - <div className='modal-dialog'> - <div className='modal-content'> - <div className='modal-header'> - <button - type='button' - className='close' - data-dismiss='modal' - aria-label='Close' - > - <span aria-hidden='true'>{'×'}</span> - </button> - {editTitle} - </div> - <div className='modal-body'> - <p>{'Edit the text appearing next to the channel name in the channel header.'}</p> - <textarea - className='form-control no-resize' - rows='6' - id='edit_header' - maxLength='1024' - value={this.state.header} - onChange={this.handleUserInput} - /> - {serverError} - </div> - <div className='modal-footer'> - <button - type='button' - className='btn btn-default' - data-dismiss='modal' - > - {'Cancel'} - </button> - <button - type='button' - className='btn btn-primary' - onClick={this.handleEdit} - > - {'Save'} - </button> - </div> - </div> - </div> - </div> + <Modal.Header closeButton={true}> + {'Edit Header for ' + this.props.channel.display_name} + </Modal.Header> + <Modal.Body> + <p>{'Edit the text appearing next to the channel name in the channel header.'}</p> + <textarea + ref='textarea' + className='form-control no-resize' + rows='6' + id='edit_header' + maxLength='1024' + defaultValue={this.props.channel.header} + /> + {serverError} + </Modal.Body> + <Modal.Footer> + <button + type='button' + className='btn btn-default' + onClick={this.props.onHide} + > + {'Cancel'} + </button> + <button + type='button' + className='btn btn-primary' + onClick={this.handleEdit} + > + {'Save'} + </button> + </Modal.Footer> + </Modal> ); } } + +EditChannelModal.propTypes = { + show: React.PropTypes.bool.isRequired, + onHide: React.PropTypes.func.isRequired, + channel: React.PropTypes.object.isRequired +}; diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx index 6848ee5da..8d3d779f3 100644 --- a/web/react/components/navbar.jsx +++ b/web/react/components/navbar.jsx @@ -1,6 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import EditChannelModal from './edit_channel_modal.jsx'; import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx'; import MessageWrapper from './message_wrapper.jsx'; import NotifyCounts from './notify_counts.jsx'; @@ -33,11 +34,15 @@ export default class Navbar extends React.Component { this.onChange = this.onChange.bind(this); this.handleLeave = this.handleLeave.bind(this); this.showSearch = this.showSearch.bind(this); + + this.showEditChannelHeaderModal = this.showEditChannelHeaderModal.bind(this); + this.createCollapseButtons = this.createCollapseButtons.bind(this); this.createDropdown = this.createDropdown.bind(this); const state = this.getStateFromStores(); state.showEditChannelPurposeModal = false; + state.showEditChannelHeaderModal = false; state.showMembersModal = false; state.showInviteModal = false; this.state = state; @@ -110,6 +115,16 @@ export default class Navbar extends React.Component { this.setState(this.getStateFromStores()); $('#navbar .navbar-brand .description').popover({placement: 'bottom', trigger: 'click', html: true}); } + showEditChannelHeaderModal() { + // this can't be done using a ToggleModalButton because we can't use one inside an OverlayTrigger + if (this.refs.headerOverlay) { + this.refs.headerOverlay.hide(); + } + + this.setState({ + showEditChannelHeaderModal: true + }); + } createDropdown(channel, channelTitle, isAdmin, isDirect, popoverContent) { if (channel) { var viewInfoOption = ( @@ -129,11 +144,7 @@ export default class Navbar extends React.Component { <a role='menuitem' href='#' - data-toggle='modal' - data-target='#edit_channel' - data-header={channel.header} - data-title={channel.display_name} - data-channelid={channel.id} + onClick={this.showEditChannelHeaderModal} > {'Set Channel Header...'} </a> @@ -239,7 +250,7 @@ export default class Navbar extends React.Component { dialogType={ChannelNotificationsModal} dialogProps={{channel}} > - {'Notification Preferences'} + {'Notification Preferences'} </ToggleModalButton> </li> ); @@ -249,6 +260,7 @@ export default class Navbar extends React.Component { <div className='navbar-brand'> <div className='dropdown'> <OverlayTrigger + ref='headerOverlay' trigger='click' placement='bottom' overlay={popoverContent} @@ -358,6 +370,9 @@ export default class Navbar extends React.Component { var isAdmin = false; var isDirect = false; + var editChannelHeaderModal = null; + var editChannelPurposeModal = null; + if (channel) { popoverContent = ( <Popover @@ -400,11 +415,7 @@ export default class Navbar extends React.Component { <br/> <a href='#' - data-toggle='modal' - data-header={channel.header} - data-title={channel.display_name} - data-channelid={channel.id} - data-target='#edit_channel' + onClick={this.showEditChannelHeaderModal} > {'Click here'} </a> @@ -413,6 +424,22 @@ export default class Navbar extends React.Component { </Popover> ); } + + editChannelHeaderModal = ( + <EditChannelModal + show={this.state.showEditChannelHeaderModal} + onHide={() => this.setState({showEditChannelHeaderModal: false})} + channel={channel} + /> + ); + + editChannelPurposeModal = ( + <EditChannelPurposeModal + show={this.state.showEditChannelPurposeModal} + onModalDismissed={() => this.setState({showEditChannelPurposeModal: false})} + channel={channel} + /> + ); } var collapseButtons = this.createCollapseButtons(currentId); @@ -443,11 +470,8 @@ export default class Navbar extends React.Component { </div> </div> </nav> - <EditChannelPurposeModal - show={this.state.showEditChannelPurposeModal} - onModalDismissed={() => this.setState({showEditChannelPurposeModal: false})} - channel={channel} - /> + {editChannelHeaderModal} + {editChannelPurposeModal} <ChannelMembersModal show={this.state.showMembersModal} onModalDismissed={() => this.setState({showMembersModal: false})} diff --git a/web/react/components/toggle_modal_button.jsx b/web/react/components/toggle_modal_button.jsx index eae4a024d..ce8ff3f60 100644 --- a/web/react/components/toggle_modal_button.jsx +++ b/web/react/components/toggle_modal_button.jsx @@ -22,7 +22,17 @@ export default class ModalToggleButton extends React.Component { } render() { - const {children, dialogType, dialogProps, ...props} = this.props; //eslint-disable-line no-redeclare + const {children, dialogType, dialogProps, onClick, ...props} = this.props; // eslint-disable-line no-redeclare + + // allow callers to provide an onClick which will be called before the modal is shown + let clickHandler = this.show; + if (onClick) { + clickHandler = () => { + onClick(); + + this.show(); + }; + } // this assumes that all modals will have a show property and an onHide event const dialog = React.createElement(this.props.dialogType, Object.assign({}, dialogProps, { @@ -42,7 +52,7 @@ export default class ModalToggleButton extends React.Component { <a {...props} href='#' - onClick={this.show} + onClick={clickHandler} > {children} {dialog} @@ -54,7 +64,8 @@ export default class ModalToggleButton extends React.Component { ModalToggleButton.propTypes = { children: React.PropTypes.node.isRequired, dialogType: React.PropTypes.func.isRequired, - dialogProps: React.PropTypes.object + dialogProps: React.PropTypes.object, + onClick: React.PropTypes.func }; ModalToggleButton.defaultProps = { |