summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2015-08-27 10:01:54 -0400
committerChristopher Speller <crspeller@gmail.com>2015-08-27 10:01:54 -0400
commitd5e202a4d9b735dca2e3cc54137b8d66cb167580 (patch)
treea61e54ec8a7d6eb318ac9077ede6dc1ef00c3ef8 /web
parentcf1c2ad2cc5d5c24eabc3ebd2bce9f79b2e420fc (diff)
parenta56603d666a4f3e22a92a0271eef56ab613ce848 (diff)
downloadchat-d5e202a4d9b735dca2e3cc54137b8d66cb167580.tar.gz
chat-d5e202a4d9b735dca2e3cc54137b8d66cb167580.tar.bz2
chat-d5e202a4d9b735dca2e3cc54137b8d66cb167580.zip
Merge pull request #472 from rgarmsen2295/mm-1853
MM-1853 Prevents users from typing more than 4000 characters into any any post/comment
Diffstat (limited to 'web')
-rw-r--r--web/react/components/create_comment.jsx7
-rw-r--r--web/react/components/create_post.jsx8
-rw-r--r--web/react/components/edit_post_modal.jsx10
-rw-r--r--web/react/components/textbox.jsx2
-rw-r--r--web/react/utils/constants.jsx1
-rw-r--r--web/react/utils/utils.jsx52
6 files changed, 72 insertions, 8 deletions
diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx
index 1de768872..94b6e1b7f 100644
--- a/web/react/components/create_comment.jsx
+++ b/web/react/components/create_comment.jsx
@@ -105,14 +105,17 @@ module.exports = React.createClass({
this.lastTime = t;
}
},
- handleUserInput: function(messageText) {
+ handleUserInput: function(message) {
+ var messageText = utils.truncateText(message);
+ var newPostError = utils.checkMessageLengthError(messageText, this.state.postError, 'Comment length cannot exceed ' + Constants.MAX_POST_LEN + ' characters');
+
var draft = PostStore.getCommentDraft(this.props.rootId);
draft.message = messageText;
PostStore.storeCommentDraft(this.props.rootId, draft);
$('.post-right__scroll').scrollTop($('.post-right__scroll')[0].scrollHeight);
$('.post-right__scroll').perfectScrollbar('update');
- this.setState({messageText: messageText});
+ this.setState({messageText: messageText, postError: newPostError});
},
handleUploadStart: function(clientIds, channelId) {
var draft = PostStore.getCommentDraft(this.props.rootId);
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index efaa40577..19270197e 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -18,6 +18,7 @@ var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
module.exports = React.createClass({
+ displayName: 'CreatePost',
lastTime: 0,
handleSubmit: function(e) {
e.preventDefault();
@@ -131,9 +132,12 @@ module.exports = React.createClass({
this.lastTime = t;
}
},
- handleUserInput: function(messageText) {
+ handleUserInput: function(message) {
+ var messageText = utils.truncateText(message);
+ var newPostError = utils.checkMessageLengthError(messageText, this.state.postError, 'Message length cannot exceed ' + Constants.MAX_POST_LEN + ' characters');
+
this.resizePostHolder();
- this.setState({messageText: messageText});
+ this.setState({messageText: messageText, postError: newPostError});
var draft = PostStore.getCurrentDraft();
draft['message'] = messageText;
diff --git a/web/react/components/edit_post_modal.jsx b/web/react/components/edit_post_modal.jsx
index 2d865a45d..8ffd5013a 100644
--- a/web/react/components/edit_post_modal.jsx
+++ b/web/react/components/edit_post_modal.jsx
@@ -3,6 +3,8 @@
var Client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
+var Constants = require('../utils/constants.jsx');
+var utils = require('../utils/utils.jsx');
var Textbox = require('./textbox.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
@@ -37,7 +39,9 @@ module.exports = React.createClass({
$(this.state.refocusId).focus();
},
handleEditInput: function(editText) {
- this.setState({ editText: editText });
+ var editMessage = utils.truncateText(editText);
+ var newError = utils.checkMessageLengthError(editMessage, this.state.error, 'New message length cannot exceed ' + Constants.MAX_POST_LEN + ' characters');
+ this.setState({editText: editMessage, error: newError});
},
handleEditKeyPress: function(e) {
if (e.which == 13 && !e.shiftKey && !e.altKey) {
@@ -53,7 +57,7 @@ module.exports = React.createClass({
var self = this;
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
- self.setState({ editText: "", title: "", channel_id: "", post_id: "", comments: 0, refocusId: "" });
+ self.setState({editText: "", title: "", channel_id: "", post_id: "", comments: 0, refocusId: "", error: ''});
});
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
@@ -69,7 +73,7 @@ module.exports = React.createClass({
return { editText: "", title: "", post_id: "", channel_id: "", comments: 0, refocusId: "" };
},
render: function() {
- var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null;
+ var error = this.state.error ? <div className='form-group has-error'><br /><label className='control-label'>{ this.state.error }</label></div> : <div className='form-group'><br /></div>;
return (
<div className="modal fade edit-modal" ref="modal" id="edit_post" role="dialog" tabIndex="-1" aria-hidden="true">
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index b5c5cc564..efd2dd810 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -257,7 +257,7 @@ module.exports = React.createClass({
return (
<div ref='wrapper' className='textarea-wrapper'>
<CommandList ref='commands' addCommand={this.addCommand} channelId={this.props.channelId} />
- <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} />
+ <textarea id={this.props.id} ref='message' className={'form-control custom-textarea ' + this.state.connection} spellCheck='true' autoComplete='off' autoCorrect='off' rows='1' maxLength={Constants.MAX_POST_LEN} 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/utils/constants.jsx b/web/react/utils/constants.jsx
index 8239a4a69..82fc3da22 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -92,6 +92,7 @@ module.exports = {
],
MONTHS: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
MAX_DMS: 20,
+ MAX_POST_LEN: 4000,
ONLINE_ICON_SVG: "<svg version='1.1' id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' sodipodi:docname='TRASH_1_4.svg' inkscape:version='0.48.4 r9939' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='12px' height='12px' viewBox='0 0 12 12' enable-background='new 0 0 12 12' xml:space='preserve'><sodipodi:namedview inkscape:cy='139.7898' inkscape:cx='26.358185' inkscape:zoom='1.18' showguides='true' showgrid='false' id='namedview6' guidetolerance='10' gridtolerance='10' objecttolerance='10' borderopacity='1' bordercolor='#666666' pagecolor='#ffffff' inkscape:current-layer='Layer_1' inkscape:window-maximized='1' inkscape:window-y='-8' inkscape:window-x='-8' inkscape:window-height='705' inkscape:window-width='1366' inkscape:guide-bbox='true' inkscape:pageshadow='2' inkscape:pageopacity='0'><sodipodi:guide position='50.036793,85.991376' orientation='1,0' id='guide2986'></sodipodi:guide><sodipodi:guide position='58.426196,66.216355' orientation='0,1' id='guide3047'></sodipodi:guide></sodipodi:namedview><g><g><path class='online--icon' d='M6,5.487c1.371,0,2.482-1.116,2.482-2.493c0-1.378-1.111-2.495-2.482-2.495S3.518,1.616,3.518,2.994C3.518,4.371,4.629,5.487,6,5.487z M10.452,8.545c-0.101-0.829-0.36-1.968-0.726-2.541C9.475,5.606,8.5,5.5,8.5,5.5S8.43,7.521,6,7.521C3.507,7.521,3.5,5.5,3.5,5.5S2.527,5.606,2.273,6.004C1.908,6.577,1.648,7.716,1.547,8.545C1.521,8.688,1.49,9.082,1.498,9.142c0.161,1.295,2.238,2.322,4.375,2.358C5.916,11.501,5.958,11.501,6,11.501c0.043,0,0.084,0,0.127-0.001c2.076-0.026,4.214-1.063,4.375-2.358C10.509,9.082,10.471,8.696,10.452,8.545z'/></g></g></svg>",
OFFLINE_ICON_SVG: "<svg version='1.1' id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' sodipodi:docname='TRASH_1_4.svg' inkscape:version='0.48.4 r9939' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='12px' height='12px' viewBox='0 0 12 12' enable-background='new 0 0 12 12' xml:space='preserve'><sodipodi:namedview inkscape:cy='139.7898' inkscape:cx='26.358185' inkscape:zoom='1.18' showguides='true' showgrid='false' id='namedview6' guidetolerance='10' gridtolerance='10' objecttolerance='10' borderopacity='1' bordercolor='#666666' pagecolor='#ffffff' inkscape:current-layer='Layer_1' inkscape:window-maximized='1' inkscape:window-y='-8' inkscape:window-x='-8' inkscape:window-height='705' inkscape:window-width='1366' inkscape:guide-bbox='true' inkscape:pageshadow='2' inkscape:pageopacity='0'><sodipodi:guide position='50.036793,85.991376' orientation='1,0' id='guide2986'></sodipodi:guide><sodipodi:guide position='58.426196,66.216355' orientation='0,1' id='guide3047'></sodipodi:guide></sodipodi:namedview><g><g><path fill='#cccccc' d='M6.002,7.143C5.645,7.363,5.167,7.52,4.502,7.52c-2.493,0-2.5-2.02-2.5-2.02S1.029,5.607,0.775,6.004C0.41,6.577,0.15,7.716,0.049,8.545c-0.025,0.145-0.057,0.537-0.05,0.598c0.162,1.295,2.237,2.321,4.375,2.357c0.043,0.001,0.085,0.001,0.127,0.001c0.043,0,0.084,0,0.127-0.001c1.879-0.023,3.793-0.879,4.263-2h-2.89L6.002,7.143L6.002,7.143z M4.501,5.488c1.372,0,2.483-1.117,2.483-2.494c0-1.378-1.111-2.495-2.483-2.495c-1.371,0-2.481,1.117-2.481,2.495C2.02,4.371,3.13,5.488,4.501,5.488z M7.002,6.5v2h5v-2H7.002z'/></g></g></svg>",
MENU_ICON: "<svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='4px' height='16px' viewBox='0 0 8 32' enable-background='new 0 0 8 32' xml:space='preserve'> <g> <circle cx='4' cy='4.062' r='4'/> <circle cx='4' cy='16' r='4'/> <circle cx='4' cy='28' r='4'/> </g> </svg>",
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index f19dd2b47..00da9ce5f 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -987,6 +987,58 @@ module.exports.isBrowserFirefox = function() {
return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
};
+// Checks if browser is IE10 or IE11
+module.exports.isBrowserIE = function() {
+ if (window.navigator && window.navigator.userAgent) {
+ var ua = window.navigator.userAgent;
+
+ return ua.indexOf('Trident/7.0') > 0 || ua.indexOf('Trident/6.0') > 0;
+ }
+
+ return false;
+};
+
+module.exports.isBrowserEdge = function() {
+ return window.naviagtor && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('edge') > -1;
+};
+
+// Gets text length consistent with maxlength property of textarea html tag
+module.exports.getLengthOfTextInTextarea = function(messageText) {
+ // Need to get length with carriage returns counting as two characters to match textbox maxlength behavior
+ // unless ie10/ie11/edge which already do
+
+ var len = messageText.length;
+ if (!module.exports.isBrowserIE() && !module.exports.isBrowserEdge()) {
+ len = messageText.replace(/\r(?!\n)|\n(?!\r)/g, '--').length;
+ }
+
+ return len;
+};
+
+module.exports.checkMessageLengthError = function(message, currentError, newError) {
+ var updatedError = currentError;
+ var len = module.exports.getLengthOfTextInTextarea(message);
+
+ if (!currentError && len >= Constants.MAX_POST_LEN) {
+ updatedError = newError;
+ } else if (currentError === newError && len < Constants.MAX_POST_LEN) {
+ updatedError = '';
+ }
+
+ return updatedError;
+};
+
+// Necessary due to issues with textarea max length and pasting newlines
+module.exports.truncateText = function(message) {
+ var lengthDifference = module.exports.getLengthOfTextInTextarea(message) - message.length;
+
+ if (lengthDifference > 0) {
+ return message.substring(0, Constants.MAX_POST_LEN - lengthDifference);
+ }
+
+ return message.substring(0, Constants.MAX_POST_LEN);
+};
+
// Used to get the id of the other user from a DM channel
module.exports.getUserIdFromChannelName = function(channel) {
var ids = channel.name.split('__');