diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/activity_log_modal.jsx | 3 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 4 | ||||
-rw-r--r-- | web/react/components/edit_channel_modal.jsx | 7 | ||||
-rw-r--r-- | web/react/components/removed_from_channel_modal.jsx | 64 | ||||
-rw-r--r-- | web/react/components/rename_channel_modal.jsx | 7 | ||||
-rw-r--r-- | web/react/components/rename_team_modal.jsx | 11 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 14 | ||||
-rw-r--r-- | web/react/components/signup_user_complete.jsx | 11 | ||||
-rw-r--r-- | web/react/components/textbox.jsx | 37 | ||||
-rw-r--r-- | web/react/components/user_settings.jsx | 52 |
10 files changed, 161 insertions, 49 deletions
diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index 7cce807a9..90f139e8b 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -102,8 +102,9 @@ module.exports = React.createClass({ <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> - <h4 className="modal-title" id="myModalLabel">Active Devices</h4> + <h4 className="modal-title" id="myModalLabel">Active Sessions</h4> </div> + <p className="session-help-text">Sessions are created when you log in with your email and password to a new browser on a device. Sessions let you use Mattermost for up to 30 days without having to log in again. If you want to log out sooner, use the "Logout" button below to end a session.</p> <div ref="modalBody" className="modal-body"> <form role="form"> { activityList } diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index b065dff83..327520210 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -32,7 +32,7 @@ module.exports = React.createClass({ post.message = this.state.messageText; // if this is a reply, trim off any carets from the beginning of a message - if (this.state.rootId && post.message.startsWith("^")) { + if (this.state.rootId && post.message[0] === "^") { post.message = post.message.replace(/^\^+\s*/g, ""); } @@ -275,7 +275,7 @@ module.exports = React.createClass({ messageText = draft['message']; uploadsInProgress = draft['uploadsInProgress']; } - this.setState({ channel_id: channel_id, messageText: messageText, initialText: messageText, submitting: false, post_error: null, previews: previews, uploadsInProgress: uploadsInProgress }); + this.setState({ channel_id: channel_id, messageText: messageText, initialText: messageText, submitting: false, limit_error: null, server_error: null, post_error: null, previews: previews, uploadsInProgress: uploadsInProgress }); } }, _onActiveThreadChanged: function(rootId, parentId) { diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx index d055feacd..a35a531b5 100644 --- a/web/react/components/edit_channel_modal.jsx +++ b/web/react/components/edit_channel_modal.jsx @@ -30,12 +30,19 @@ module.exports = React.createClass({ handleUserInput: function(e) { this.setState({ description: e.target.value }); }, + handleClose: function() { + this.setState({description: "", server_error: ""}); + }, componentDidMount: function() { var self = this; $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { var button = e.relatedTarget; self.setState({ description: $(button).attr('data-desc'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), server_error: "" }); }); + $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose) + }, + componentWillUnmount: function() { + $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose) }, getInitialState: function() { return { description: "", title: "", channel_id: "" }; diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx new file mode 100644 index 000000000..a8889a92a --- /dev/null +++ b/web/react/components/removed_from_channel_modal.jsx @@ -0,0 +1,64 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var ChannelStore = require('../stores/channel_store.jsx'); +var UserStore = require('../stores/user_store.jsx'); +var BrowserStore = require('../stores/browser_store.jsx') +var utils = require('../utils/utils.jsx'); + +module.exports = React.createClass({ + handleShow: function() { + var newState = {}; + if(BrowserStore.getItem("channel-removed-state")) { + newState = BrowserStore.getItem("channel-removed-state"); + BrowserStore.removeItem("channel-removed-state"); + } + + this.setState(newState); + }, + handleClose: function() { + var townSquare = ChannelStore.getByName("town-square"); + utils.switchChannel(townSquare); + + this.setState({channelName: "", remover: ""}) + }, + componentDidMount: function() { + $(this.getDOMNode()).on('show.bs.modal',this.handleShow); + $(this.getDOMNode()).on('hidden.bs.modal',this.handleClose); + }, + componentWillUnmount: function() { + $(this.getDOMNode()).off('show.bs.modal',this.handleShow); + $(this.getDOMNode()).off('hidden.bs.modal',this.handleClose); + }, + getInitialState: function() { + return {channelName: "", remover: ""} + }, + render: function() { + var currentUser = UserStore.getCurrentUser(); + var channelName = this.state.channelName ? this.state.channelName : "the channel" + var remover = this.state.remover ? this.state.remover : "Someone" + + if (currentUser != null) { + return ( + <div className="modal fade" ref="modal" id="removed_from_channel" tabIndex="-1" role="dialog" aria-hidden="true"> + <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> + <h4 className="modal-title">Removed from {channelName}</h4> + </div> + <div className="modal-body"> + <p>{remover} removed you from {channelName}</p> + </div> + <div className="modal-footer"> + <button type="button" className="btn btn-primary" data-dismiss="modal">Okay</button> + </div> + </div> + </div> + </div> + ); + } else { + return <div/>; + } + } +});
\ No newline at end of file diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx index 2ae331626..9e4a25f85 100644 --- a/web/react/components/rename_channel_modal.jsx +++ b/web/react/components/rename_channel_modal.jsx @@ -89,12 +89,19 @@ module.exports = React.createClass({ this.refs.channel_name.getDOMNode().value = channel_name; this.setState({ channel_name: channel_name }) }, + handleClose: function() { + this.setState({display_name: "", channel_name: "", display_name_error: "", server_error: "", name_error: ""}); + }, componentDidMount: function() { var self = this; $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { var button = $(e.relatedTarget); self.setState({ display_name: button.attr('data-display'), title: button.attr('data-name'), channel_id: button.attr('data-channelid') }); }); + $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose); + }, + componentWillUnmount: function() { + $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose); }, getInitialState: function() { return { display_name: "", channel_name: "", channel_id: "" }; diff --git a/web/react/components/rename_team_modal.jsx b/web/react/components/rename_team_modal.jsx index a6da57b67..dfd775a3b 100644 --- a/web/react/components/rename_team_modal.jsx +++ b/web/react/components/rename_team_modal.jsx @@ -44,11 +44,14 @@ module.exports = React.createClass({ onNameChange: function() { this.setState({ name: this.refs.name.getDOMNode().value }) }, + handleClose: function() { + this.setState({ name: this.props.teamDisplayName, name_error: "", server_error: ""}); + }, componentDidMount: function() { - var self = this; - $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) { - self.setState({ name: self.props.teamDisplayName }); - }); + $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose); + }, + componentWillUnmount: function() { + $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose); }, getInitialState: function() { return { name: this.props.teamDisplayName }; diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 3cf67e410..5b8d6c542 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -7,6 +7,7 @@ var AsyncClient = require('../utils/async_client.jsx'); var SocketStore = require('../stores/socket_store.jsx'); var UserStore = require('../stores/user_store.jsx'); var TeamStore = require('../stores/team_store.jsx'); +var BrowserStore = require('../stores/browser_store.jsx') var utils = require('../utils/utils.jsx'); var SidebarHeader = require('./sidebar_header.jsx'); var SearchBox = require('./search_bar.jsx'); @@ -197,6 +198,19 @@ module.exports = React.createClass({ if (UserStore.getCurrentId() === msg.user_id) { AsyncClient.getChannels(true); } + } else if(msg.action === "user_removed") { + if(msg.user_id === UserStore.getCurrentId()) { + AsyncClient.getChannels(true); + + if(msg.props.channel_id === ChannelStore.getCurrentId() && $('#removed_from_channel').length > 0) { + var sentState = {}; + sentState.channelName = ChannelStore.getCurrent().display_name; + sentState.remover = UserStore.getProfile(msg.props.remover).username; + + BrowserStore.setItem('channel-removed-state',sentState); + $('#removed_from_channel').modal('show'); + } + } } }, updateTitle: function() { diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index dc5ba64aa..bbf1f670c 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -117,24 +117,24 @@ module.exports = React.createClass({ var signup_message; if (auth_services.indexOf("gitlab") >= 0) { - signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team} <a href={"/"+this.props.teamName+"/signup/gitlab"+window.location.search}>{"or sign up with GitLab."}</a></p>; - } else { - signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team + "."}</p>; + signup_message = <div><a className="btn btn-custom-login gitlab" href={"/"+this.props.teamName+"/signup/gitlab"+window.location.search}><span className="icon" />{"with GitLab"}</a> + <div className="or__container"><span>or</span></div></div>; } return ( <div> <img className="signup-team-logo" src="/static/images/logo.png" /> - <h4>Welcome to { config.SiteName }</h4> + <h3 className="text-center extra-margin">Signup to { config.SiteName }</h3> <div className="form-group form-group--small"> <span></span> </div> { signup_message } - <p>Your username can be made of lowercase letters and numbers.</p> <label className="control-label">Username</label> <div className={ name_error ? "form-group has-error" : "form-group" }> <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" /> { name_error } + <p className="form__hint">Your username can be made of lowercase letters and numbers.</p> + <p className="form__hint">{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others"}</p> </div> { email } <label className="control-label">Password</label> @@ -142,7 +142,6 @@ module.exports = React.createClass({ <input type="password" ref="password" className="form-control" placeholder="" maxLength="128" /> { password_error } </div> - <p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others"}</p> <p className={ this.state.original_email == "" ? "hidden" : ""}>{ yourEmailIs } You’ll use this address to sign in to {config.SiteName}.</p> <div className="checkbox"><label><input type="checkbox" ref="email_service" /> It's ok to send me occassional email with updates about the {config.SiteName} service. </label></div> <p><button onClick={this.handleSubmit} className="btn-primary btn">Create Account</button></p> diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx index ad50b7920..bbd1f84b6 100644 --- a/web/react/components/textbox.jsx +++ b/web/react/components/textbox.jsx @@ -36,7 +36,6 @@ module.exports = React.createClass({ this.resize(); this.processMentions(); - this.updateTextdiv(); }, componentWillUnmount: function() { PostStore.removeAddMentionListener(this._onChange); @@ -87,7 +86,6 @@ module.exports = React.createClass({ this.processMentions(); this.doProcessMentions = false; } - this.updateTextdiv(); this.resize(); }, componentWillReceiveProps: function(nextProps) { @@ -117,17 +115,6 @@ module.exports = React.createClass({ }); }, 1); }, - updateTextdiv: function() { - var html = utils.insertHtmlEntities(this.refs.message.getDOMNode().value); - for (var k in this.mentions) { - var m = this.mentions[k]; - var re = new RegExp('( |^)@' + m + '( |$|\n)', 'm'); - html = html.replace(re, '$1<span class="mention">@'+m+'</span>$2'); - } - var re2 = new RegExp('(^$)(?![.\n])', 'gm'); - html = html.replace(re2, '<br/><br/>'); - $(this.refs.textdiv.getDOMNode()).html(html); - }, handleChange: function() { this.props.onUserInput(this.refs.message.getDOMNode().value); this.resize(); @@ -181,7 +168,7 @@ module.exports = React.createClass({ } }, processMentions: function() { - /* First, find all the possible mentions, highlight them in the HTML and add + /* First, find all the possible mentions and add them all to a list of mentions */ var text = utils.insertHtmlEntities(this.refs.message.getDOMNode().value); @@ -192,9 +179,7 @@ module.exports = React.createClass({ var matches = text.match(re1); if (!matches) { - $(this.refs.textdiv.getDOMNode()).text(text); this.updateMentionTab(null, []); - this.mentions = []; return; } @@ -207,7 +192,7 @@ module.exports = React.createClass({ } /* Figure out what the user is currently typing. If it's a mention then we don't - want to highlight it and add it to the mention list yet, so we remove it if + want to add it to the mention list yet, so we remove it if there is only one occurence of that mention so far. */ var caret = utils.getCaretPosition(this.refs.message.getDOMNode()); @@ -225,14 +210,13 @@ module.exports = React.createClass({ typingMention = text.substring(atIndex+1, caret); } - var re3 = new RegExp('@' + typingMention + '( |$|\n)', 'g'); + var re2 = new RegExp('@' + typingMention + '( |$|\n)', 'g'); - if ((text.match(re3) || []).length === 1 && mentions.indexOf(typingMention) !== -1) { + if ((text.match(re2) || []).length === 1 && mentions.indexOf(typingMention) !== -1) { mentions.splice(mentions.indexOf(typingMention), 1); } this.updateMentionTab(null, mentions); - this.mentions = mentions; }, checkForNewMention: function(text) { var caret = utils.getCaretPosition(this.refs.message.getDOMNode()); @@ -287,15 +271,9 @@ module.exports = React.createClass({ elm.value = cmd; this.handleChange(); }, - scroll: function() { - var e = this.refs.message.getDOMNode(); - var d = this.refs.textdiv.getDOMNode(); - $(d).scrollTop($(e).scrollTop()); - }, resize: function() { var e = this.refs.message.getDOMNode(); var w = this.refs.wrapper.getDOMNode(); - var d = this.refs.textdiv.getDOMNode(); var lht = parseInt($(e).css('lineHeight'),10); var lines = e.scrollHeight / lht; @@ -303,15 +281,11 @@ module.exports = React.createClass({ if (e.scrollHeight - mod < 167) { $(e).css({'height':'auto','overflow-y':'hidden'}).height(e.scrollHeight - mod); - $(d).css({'height':'auto','overflow-y':'hidden'}).height(e.scrollHeight - mod); $(w).css({'height':'auto'}).height(e.scrollHeight+2); } else { $(e).css({'height':'auto','overflow-y':'scroll'}).height(167); - $(d).css({'height':'auto','overflow-y':'scroll'}).height(167); $(w).css({'height':'auto'}).height(167); } - - $(d).scrollTop($(e).scrollTop()); }, handleFocus: function() { var elm = this.refs.message.getDOMNode(); @@ -332,8 +306,7 @@ module.exports = React.createClass({ return ( <div ref="wrapper" className="textarea-wrapper"> <CommandList ref='commands' addCommand={this.addCommand} channelId={this.props.channelId} /> - <div className="form-control textarea-div" ref="textdiv"/> - <textarea id={this.props.id} ref="message" className={"form-control custom-textarea " + this.state.connection} spellCheck="true" autoComplete="off" autoCorrect="off" rows="1" placeholder={this.props.createMessage} value={this.props.messageText} onInput={this.handleChange} onChange={this.handleChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} onScroll={this.scroll} onFocus={this.handleFocus} onBlur={this.handleBlur} onPaste={this.handlePaste} /> + <textarea id={this.props.id} ref="message" className={"form-control custom-textarea " + this.state.connection} spellCheck="true" autoComplete="off" autoCorrect="off" rows="1" placeholder={this.props.createMessage} value={this.props.messageText} onInput={this.handleChange} onChange={this.handleChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} onFocus={this.handleFocus} onBlur={this.handleBlur} onPaste={this.handlePaste} /> </div> ); } diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx index 298f5ee70..e1ae6da52 100644 --- a/web/react/components/user_settings.jsx +++ b/web/react/components/user_settings.jsx @@ -11,6 +11,7 @@ var client = require('../utils/client.jsx'); var AsyncClient = require('../utils/async_client.jsx'); var utils = require('../utils/utils.jsx'); var Constants = require('../utils/constants.jsx'); +var assign = require('object-assign'); function getNotificationsStateFromStores() { var user = UserStore.getCurrentUser(); @@ -95,11 +96,20 @@ var NotificationsTab = React.createClass({ }.bind(this) ); }, + handleClose: function() { + $(this.getDOMNode()).find(".form-control").each(function() { + this.value = ""; + }); + + this.setState(assign({},getNotificationsStateFromStores(),{server_error: null})); + }, componentDidMount: function() { UserStore.addChangeListener(this._onChange); + $('#user_settings1').on('hidden.bs.modal', this.handleClose); }, componentWillUnmount: function() { UserStore.removeChangeListener(this._onChange); + $('#user_settings1').off('hidden.bs.modal', this.handleClose); }, _onChange: function() { var newState = getNotificationsStateFromStores(); @@ -502,6 +512,18 @@ var SecurityTab = React.createClass({ handleDevicesOpen: function() { $("#user_settings1").modal('hide'); }, + handleClose: function() { + $(this.getDOMNode()).find(".form-control").each(function() { + this.value = ""; + }); + this.setState({current_password: '', new_password: '', confirm_password: '', server_error: null, password_error: null}); + }, + componentDidMount: function() { + $('#user_settings1').on('hidden.bs.modal', this.handleClose); + }, + componentWillUnmount: function() { + $('#user_settings1').off('hidden.bs.modal', this.handleClose); + }, getInitialState: function() { return { current_password: '', new_password: '', confirm_password: '' }; }, @@ -595,7 +617,7 @@ var SecurityTab = React.createClass({ <br></br> <a data-toggle="modal" className="security-links theme" data-target="#access-history" href="#" onClick={this.handleHistoryOpen}><i className="fa fa-clock-o"></i>View Access History</a> <b> </b> - <a data-toggle="modal" className="security-links theme" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Devices</a> + <a data-toggle="modal" className="security-links theme" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Sessions</a> </div> </div> ); @@ -699,13 +721,15 @@ var GeneralTab = React.createClass({ if(!this.submitActive) return; - if(this.state.picture.type !== "image/jpeg") { - this.setState({client_error: "Only JPG images may be used for profile pictures"}); + var picture = this.state.picture; + + if(picture.type !== "image/jpeg" && picture.type !== "image/png") { + this.setState({client_error: "Only JPG or PNG images may be used for profile pictures"}); return; } formData = new FormData(); - formData.append('image', this.state.picture, this.state.picture.name); + formData.append('image', picture, picture.name); client.uploadProfileImage(formData, function(data) { @@ -751,6 +775,19 @@ var GeneralTab = React.createClass({ this.submitActive = false this.props.updateSection(section); }, + handleClose: function() { + $(this.getDOMNode()).find(".form-control").each(function() { + this.value = ""; + }); + + this.setState(assign({}, this.getInitialState(), {client_error: null, server_error: null, email_error: null})); + }, + componentDidMount: function() { + $('#user_settings1').on('hidden.bs.modal', this.handleClose); + }, + componentWillUnmount: function() { + $('#user_settings1').off('hidden.bs.modal', this.handleClose); + }, getInitialState: function() { var user = this.props.user; @@ -994,10 +1031,14 @@ var AppearanceTab = React.createClass({ var hex = utils.rgb2hex(e.target.style.backgroundColor); this.setState({ theme: hex.toLowerCase() }); }, + handleClose: function() { + this.setState({server_error: null}); + }, componentDidMount: function() { if (this.props.activeSection === "theme") { $(this.refs[this.state.theme].getDOMNode()).addClass('active-border'); } + $('#user_settings1').on('hidden.bs.modal', this.handleClose); }, componentDidUpdate: function() { if (this.props.activeSection === "theme") { @@ -1005,6 +1046,9 @@ var AppearanceTab = React.createClass({ $(this.refs[this.state.theme].getDOMNode()).addClass('active-border'); } }, + componentWillUnmount: function() { + $('#user_settings1').off('hidden.bs.modal', this.handleClose); + }, getInitialState: function() { var user = UserStore.getCurrentUser(); var theme = config.ThemeColors != null ? config.ThemeColors[0] : "#2389d7"; |