Add error to RHS reply box for messages > 4000 chars, consistent with create post and edit post errors (#4871)
* functionality * CSS updates * cleanup * moved message length checks to Textbox component * cleanup
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
87d84dfc30
Коммит
0a1b0d051a
@@ -55,6 +55,7 @@ export default class CreateComment extends React.Component {
|
|||||||
this.focusTextbox = this.focusTextbox.bind(this);
|
this.focusTextbox = this.focusTextbox.bind(this);
|
||||||
this.showPostDeletedModal = this.showPostDeletedModal.bind(this);
|
this.showPostDeletedModal = this.showPostDeletedModal.bind(this);
|
||||||
this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this);
|
this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this);
|
||||||
|
this.handlePostError = this.handlePostError.bind(this);
|
||||||
|
|
||||||
PostStore.clearCommentDraftUploads();
|
PostStore.clearCommentDraftUploads();
|
||||||
MessageHistoryStore.resetHistoryIndex('comment');
|
MessageHistoryStore.resetHistoryIndex('comment');
|
||||||
@@ -96,6 +97,10 @@ export default class CreateComment extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePostError(postError) {
|
||||||
|
this.setState({postError});
|
||||||
|
}
|
||||||
|
|
||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -109,16 +114,11 @@ export default class CreateComment extends React.Component {
|
|||||||
|
|
||||||
const message = this.state.message;
|
const message = this.state.message;
|
||||||
|
|
||||||
if (message.length > Constants.CHARACTER_LIMIT) {
|
if (this.state.postError) {
|
||||||
this.setState({
|
this.setState({errorClass: 'animation--highlight'});
|
||||||
postError: (
|
setTimeout(() => {
|
||||||
<FormattedMessage
|
this.setState({errorClass: null});
|
||||||
id='create_comment.commentLength'
|
}, Constants.ANIMATION_TIMEOUT);
|
||||||
defaultMessage='Comment length must be less than {max} characters.'
|
|
||||||
values={{max: Constants.CHARACTER_LIMIT}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +420,8 @@ export default class CreateComment extends React.Component {
|
|||||||
|
|
||||||
let postError = null;
|
let postError = null;
|
||||||
if (this.state.postError) {
|
if (this.state.postError) {
|
||||||
postError = <label className='control-label'>{this.state.postError}</label>;
|
const postErrorClass = 'post-error' + (this.state.errorClass ? (' ' + this.state.errorClass) : '');
|
||||||
|
postError = <label className={postErrorClass}>{this.state.postError}</label>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let preview = null;
|
let preview = null;
|
||||||
@@ -434,11 +435,6 @@ export default class CreateComment extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let postFooterClassName = 'post-create-footer';
|
|
||||||
if (postError) {
|
|
||||||
postFooterClassName += ' has-error';
|
|
||||||
}
|
|
||||||
|
|
||||||
let uploadsInProgressText = null;
|
let uploadsInProgressText = null;
|
||||||
if (this.state.uploadsInProgress.length > 0) {
|
if (this.state.uploadsInProgress.length > 0) {
|
||||||
uploadsInProgressText = (
|
uploadsInProgressText = (
|
||||||
@@ -470,6 +466,7 @@ export default class CreateComment extends React.Component {
|
|||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onKeyPress={this.commentMsgKeyPress}
|
onKeyPress={this.commentMsgKeyPress}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
|
handlePostError={this.handlePostError}
|
||||||
value={this.state.message}
|
value={this.state.message}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
createMessage={Utils.localizeMessage('create_comment.addComment', 'Add a comment...')}
|
createMessage={Utils.localizeMessage('create_comment.addComment', 'Add a comment...')}
|
||||||
@@ -494,7 +491,7 @@ export default class CreateComment extends React.Component {
|
|||||||
channelId={this.props.channelId}
|
channelId={this.props.channelId}
|
||||||
parentId={this.props.rootId}
|
parentId={this.props.rootId}
|
||||||
/>
|
/>
|
||||||
<div className={postFooterClassName}>
|
<div className='post-create-footer'>
|
||||||
<input
|
<input
|
||||||
type='button'
|
type='button'
|
||||||
className='btn btn-primary comment-btn pull-right'
|
className='btn btn-primary comment-btn pull-right'
|
||||||
@@ -502,8 +499,8 @@ export default class CreateComment extends React.Component {
|
|||||||
onClick={this.handleSubmit}
|
onClick={this.handleSubmit}
|
||||||
/>
|
/>
|
||||||
{uploadsInProgressText}
|
{uploadsInProgressText}
|
||||||
{preview}
|
|
||||||
{postError}
|
{postError}
|
||||||
|
{preview}
|
||||||
{serverError}
|
{serverError}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import PreferenceStore from 'stores/preference_store.jsx';
|
|||||||
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
|
import {FormattedHTMLMessage} from 'react-intl';
|
||||||
import {browserHistory} from 'react-router/es6';
|
import {browserHistory} from 'react-router/es6';
|
||||||
|
|
||||||
const Preferences = Constants.Preferences;
|
const Preferences = Constants.Preferences;
|
||||||
@@ -61,7 +61,7 @@ export default class CreatePost extends React.Component {
|
|||||||
this.showPostDeletedModal = this.showPostDeletedModal.bind(this);
|
this.showPostDeletedModal = this.showPostDeletedModal.bind(this);
|
||||||
this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this);
|
this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this);
|
||||||
this.showShortcuts = this.showShortcuts.bind(this);
|
this.showShortcuts = this.showShortcuts.bind(this);
|
||||||
this.checkMessageLength = this.checkMessageLength.bind(this);
|
this.handlePostError = this.handlePostError.bind(this);
|
||||||
|
|
||||||
PostStore.clearDraftUploads();
|
PostStore.clearDraftUploads();
|
||||||
|
|
||||||
@@ -81,6 +81,10 @@ export default class CreatePost extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePostError(postError) {
|
||||||
|
this.setState({postError});
|
||||||
|
}
|
||||||
|
|
||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -218,25 +222,6 @@ export default class CreatePost extends React.Component {
|
|||||||
const draft = PostStore.getCurrentDraft();
|
const draft = PostStore.getCurrentDraft();
|
||||||
draft.message = message;
|
draft.message = message;
|
||||||
PostStore.storeCurrentDraft(draft);
|
PostStore.storeCurrentDraft(draft);
|
||||||
|
|
||||||
this.checkMessageLength(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkMessageLength(message) {
|
|
||||||
if (message.length > Constants.CHARACTER_LIMIT) {
|
|
||||||
const errorMessage = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='create_post.error_message'
|
|
||||||
defaultMessage='Your message is too long. Character count: {length}/{limit}'
|
|
||||||
values={{
|
|
||||||
length: message.length,
|
|
||||||
limit: Constants.CHARACTER_LIMIT
|
|
||||||
}}
|
|
||||||
/>);
|
|
||||||
this.setState({postError: errorMessage});
|
|
||||||
} else {
|
|
||||||
this.setState({postError: null});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUploadClick() {
|
handleUploadClick() {
|
||||||
@@ -335,8 +320,6 @@ export default class CreatePost extends React.Component {
|
|||||||
fullWidthTextBox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN,
|
fullWidthTextBox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN,
|
||||||
showTutorialTip: tutorialStep === TutorialSteps.POST_POPOVER
|
showTutorialTip: tutorialStep === TutorialSteps.POST_POPOVER
|
||||||
});
|
});
|
||||||
|
|
||||||
this.checkMessageLength(this.state.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -543,6 +526,7 @@ export default class CreatePost extends React.Component {
|
|||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onKeyPress={this.postMsgKeyPress}
|
onKeyPress={this.postMsgKeyPress}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
|
handlePostError={this.handlePostError}
|
||||||
value={this.state.message}
|
value={this.state.message}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
createMessage={Utils.localizeMessage('create_post.write', 'Write a message...')}
|
createMessage={Utils.localizeMessage('create_post.write', 'Write a message...')}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export default class EditPostModal extends React.Component {
|
|||||||
this.onModalShown = this.onModalShown.bind(this);
|
this.onModalShown = this.onModalShown.bind(this);
|
||||||
this.onModalHide = this.onModalHide.bind(this);
|
this.onModalHide = this.onModalHide.bind(this);
|
||||||
this.onModalKeyDown = this.onModalKeyDown.bind(this);
|
this.onModalKeyDown = this.onModalKeyDown.bind(this);
|
||||||
|
this.handlePostError = this.handlePostError.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
editText: '',
|
editText: '',
|
||||||
@@ -52,6 +53,12 @@ export default class EditPostModal extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePostError(postError) {
|
||||||
|
if (this.state.postError !== postError) {
|
||||||
|
this.setState({postError});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleEdit() {
|
handleEdit() {
|
||||||
const updatedPost = {
|
const updatedPost = {
|
||||||
message: this.state.editText,
|
message: this.state.editText,
|
||||||
@@ -103,21 +110,6 @@ export default class EditPostModal extends React.Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
editText: message
|
editText: message
|
||||||
});
|
});
|
||||||
|
|
||||||
if (message.length > Constants.CHARACTER_LIMIT) {
|
|
||||||
const errorMessage = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='create_post.error_message'
|
|
||||||
defaultMessage='Your message is too long. Character count: {length}/{limit}'
|
|
||||||
values={{
|
|
||||||
length: message.length,
|
|
||||||
limit: Constants.CHARACTER_LIMIT
|
|
||||||
}}
|
|
||||||
/>);
|
|
||||||
this.setState({postError: errorMessage});
|
|
||||||
} else {
|
|
||||||
this.setState({postError: ''});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditKeyPress(e) {
|
handleEditKeyPress(e) {
|
||||||
@@ -262,6 +254,7 @@ export default class EditPostModal extends React.Component {
|
|||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onKeyPress={this.handleEditKeyPress}
|
onKeyPress={this.handleEditKeyPress}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
|
handlePostError={this.handlePostError}
|
||||||
value={this.state.editText}
|
value={this.state.editText}
|
||||||
channelId={this.state.channel_id}
|
channelId={this.state.channel_id}
|
||||||
createMessage={Utils.localizeMessage('edit_post.editPost', 'Edit the post...')}
|
createMessage={Utils.localizeMessage('edit_post.editPost', 'Edit the post...')}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default class Textbox extends React.Component {
|
|||||||
this.handleBlur = this.handleBlur.bind(this);
|
this.handleBlur = this.handleBlur.bind(this);
|
||||||
this.handleHeightChange = this.handleHeightChange.bind(this);
|
this.handleHeightChange = this.handleHeightChange.bind(this);
|
||||||
this.showPreview = this.showPreview.bind(this);
|
this.showPreview = this.showPreview.bind(this);
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
connection: ''
|
connection: ''
|
||||||
@@ -51,6 +52,10 @@ export default class Textbox extends React.Component {
|
|||||||
ErrorStore.addChangeListener(this.onRecievedError);
|
ErrorStore.addChangeListener(this.onRecievedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.checkMessageLength(this.props.value);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ErrorStore.removeChangeListener(this.onRecievedError);
|
ErrorStore.removeChangeListener(this.onRecievedError);
|
||||||
}
|
}
|
||||||
@@ -65,6 +70,30 @@ export default class Textbox extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChange(e) {
|
||||||
|
this.checkMessageLength(e.target.value);
|
||||||
|
this.props.onChange(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMessageLength(message) {
|
||||||
|
if (this.props.handlePostError) {
|
||||||
|
if (message.length > Constants.CHARACTER_LIMIT) {
|
||||||
|
const errorMessage = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='create_post.error_message'
|
||||||
|
defaultMessage='Your message is too long. Character count: {length}/{limit}'
|
||||||
|
values={{
|
||||||
|
length: message.length,
|
||||||
|
limit: Constants.CHARACTER_LIMIT
|
||||||
|
}}
|
||||||
|
/>);
|
||||||
|
this.props.handlePostError(errorMessage);
|
||||||
|
} else {
|
||||||
|
this.props.handlePostError(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleKeyPress(e) {
|
handleKeyPress(e) {
|
||||||
this.props.onKeyPress(e);
|
this.props.onKeyPress(e);
|
||||||
}
|
}
|
||||||
@@ -206,7 +235,7 @@ export default class Textbox extends React.Component {
|
|||||||
type='textarea'
|
type='textarea'
|
||||||
spellCheck='true'
|
spellCheck='true'
|
||||||
placeholder={this.props.createMessage}
|
placeholder={this.props.createMessage}
|
||||||
onChange={this.props.onChange}
|
onChange={this.handleChange}
|
||||||
onKeyPress={this.handleKeyPress}
|
onKeyPress={this.handleKeyPress}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
@@ -257,5 +286,6 @@ Textbox.propTypes = {
|
|||||||
createMessage: React.PropTypes.string.isRequired,
|
createMessage: React.PropTypes.string.isRequired,
|
||||||
onKeyDown: React.PropTypes.func,
|
onKeyDown: React.PropTypes.func,
|
||||||
onBlur: React.PropTypes.func,
|
onBlur: React.PropTypes.func,
|
||||||
supportsCommands: React.PropTypes.bool.isRequired
|
supportsCommands: React.PropTypes.bool.isRequired,
|
||||||
|
handlePostError: React.PropTypes.func
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,24 @@
|
|||||||
form {
|
form {
|
||||||
padding: .5em 15px 0;
|
padding: .5em 15px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-create-footer {
|
||||||
|
@include clearfix;
|
||||||
|
font-size: 13px;
|
||||||
|
overflow: visible;
|
||||||
|
position: relative;
|
||||||
|
clear: both;
|
||||||
|
|
||||||
|
.post-error {
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 0;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: .85em;
|
||||||
|
@include opacity(.55);
|
||||||
|
position: absolute;
|
||||||
|
top: -25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.help__format-text {
|
.help__format-text {
|
||||||
|
|||||||
@@ -1073,6 +1073,11 @@
|
|||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-error {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 32px;
|
left: 32px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
.sidebar--right & {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user