diff options
-rw-r--r-- | web/react/components/create_comment.jsx | 14 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 15 | ||||
-rw-r--r-- | web/react/components/signup_user_complete.jsx | 2 | ||||
-rw-r--r-- | web/react/components/team_signup_username_page.jsx | 2 | ||||
-rw-r--r-- | web/react/components/time_since.jsx | 3 | ||||
-rw-r--r-- | web/react/components/user_settings/user_settings_general.jsx | 1 | ||||
-rw-r--r-- | web/react/stores/socket_store.jsx | 24 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 5 | ||||
-rw-r--r-- | web/react/utils/text_formatting.jsx | 8 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 15 | ||||
-rw-r--r-- | web/templates/head.html | 6 |
11 files changed, 73 insertions, 22 deletions
diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 9e7c67515..709485991 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -59,6 +59,7 @@ class CreateComment extends React.Component { this.getFileCount = this.getFileCount.bind(this); this.handleResize = this.handleResize.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this); + this.focusTextbox = this.focusTextbox.bind(this); PostStore.clearCommentDraftUploads(); @@ -76,7 +77,7 @@ class CreateComment extends React.Component { PreferenceStore.addChangeListener(this.onPreferenceChange); window.addEventListener('resize', this.handleResize); - this.refs.textbox.focus(); + this.focusTextbox(); } componentWillUnmount() { PreferenceStore.removeChangeListener(this.onPreferenceChange); @@ -99,7 +100,7 @@ class CreateComment extends React.Component { } if (prevProps.rootId !== this.props.rootId) { - this.refs.textbox.focus(); + this.focusTextbox(); } } handleSubmit(e) { @@ -226,7 +227,7 @@ class CreateComment extends React.Component { } } handleUploadClick() { - this.refs.textbox.focus(); + this.focusTextbox(); } handleUploadStart(clientIds) { let draft = PostStore.getCommentDraft(this.props.rootId); @@ -238,7 +239,7 @@ class CreateComment extends React.Component { // this is a bit redundant with the code that sets focus when the file input is clicked, // but this also resets the focus after a drag and drop - this.refs.textbox.focus(); + this.focusTextbox(); } handleFileUploadComplete(filenames, clientIds) { let draft = PostStore.getCommentDraft(this.props.rootId); @@ -306,6 +307,11 @@ class CreateComment extends React.Component { getFileCount() { return this.state.previews.length + this.state.uploadsInProgress.length; } + focusTextbox() { + if (!Utils.isMobile()) { + this.refs.textbox.focus(); + } + } render() { let serverError = null; if (this.state.serverError) { diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 6ea80cd13..ecabdaee6 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -63,6 +63,7 @@ class CreatePost extends React.Component { this.getFileCount = this.getFileCount.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.sendMessage = this.sendMessage.bind(this); + this.focusTextbox = this.focusTextbox.bind(this); PostStore.clearDraftUploads(); @@ -193,6 +194,11 @@ class CreatePost extends React.Component { } ); } + focusTextbox() { + if (!Utils.isMobile()) { + this.refs.textbox.focus(); + } + } postMsgKeyPress(e) { if (this.state.ctrlSend && e.ctrlKey || !this.state.ctrlSend) { if (e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) { @@ -216,7 +222,7 @@ class CreatePost extends React.Component { PostStore.storeCurrentDraft(draft); } handleUploadClick() { - this.refs.textbox.focus(); + this.focusTextbox(); } handleUploadStart(clientIds, channelId) { const draft = PostStore.getDraft(channelId); @@ -228,7 +234,7 @@ class CreatePost extends React.Component { // this is a bit redundant with the code that sets focus when the file input is clicked, // but this also resets the focus after a drag and drop - this.refs.textbox.focus(); + this.focusTextbox(); } handleFileUploadComplete(filenames, clientIds, channelId) { const draft = PostStore.getDraft(channelId); @@ -305,11 +311,12 @@ class CreatePost extends React.Component { componentDidMount() { ChannelStore.addChangeListener(this.onChange); PreferenceStore.addChangeListener(this.onPreferenceChange); - this.refs.textbox.focus(); + + this.focusTextbox(); } componentDidUpdate(prevProps, prevState) { if (prevState.channelId !== this.state.channelId) { - this.refs.textbox.focus(); + this.focusTextbox(); } } componentWillUnmount() { diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index 98a832542..672213d1a 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -303,7 +303,7 @@ class SignupUserComplete extends React.Component { ref='name' className='form-control' placeholder='' - maxLength='128' + maxLength={Constants.MAX_USERNAME_LENGTH} spellCheck='false' /> {nameError} diff --git a/web/react/components/team_signup_username_page.jsx b/web/react/components/team_signup_username_page.jsx index a7332975d..0fa9cb103 100644 --- a/web/react/components/team_signup_username_page.jsx +++ b/web/react/components/team_signup_username_page.jsx @@ -115,7 +115,7 @@ class TeamSignupUsernamePage extends React.Component { className='form-control' placeholder='' defaultValue={this.props.state.user.username} - maxLength='128' + maxLength={Constants.MAX_USERNAME_LENGTH} spellCheck='false' /> {nameHelpText} diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx index ba8dbffcc..1560d2469 100644 --- a/web/react/components/time_since.jsx +++ b/web/react/components/time_since.jsx @@ -2,6 +2,7 @@ // See License.txt for license information. import Constants from '../utils/constants.jsx'; +import * as Utils from '../utils/utils.jsx'; import {FormattedRelative, FormattedDate} from 'mm-intl'; @@ -24,7 +25,7 @@ export default class TimeSince extends React.Component { if (this.props.sameUser) { return ( <time className='post__time'> - <FormattedRelative value={this.props.eventTime} /> + {Utils.displayTimeFormatted(this.props.eventTime)} </time> ); } diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index f20b4b807..cd229775f 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -514,6 +514,7 @@ class UserSettingsGeneralTab extends React.Component { <label className='col-sm-5 control-label'>{usernameLabel}</label> <div className='col-sm-7'> <input + maxLength={Constants.MAX_USERNAME_LENGTH} className='form-control' type='text' onChange={this.updateUsername} diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx index 9c3270f68..bc2bdbe64 100644 --- a/web/react/stores/socket_store.jsx +++ b/web/react/stores/socket_store.jsx @@ -28,10 +28,13 @@ class SocketStoreClass extends EventEmitter { this.addChangeListener = this.addChangeListener.bind(this); this.removeChangeListener = this.removeChangeListener.bind(this); this.sendMessage = this.sendMessage.bind(this); + this.close = this.close.bind(this); + this.failCount = 0; this.initialize(); } + initialize() { if (!UserStore.getCurrentId()) { return; @@ -106,15 +109,19 @@ class SocketStoreClass extends EventEmitter { }; } } + emitChange(msg) { this.emit(CHANGE_EVENT, msg); } + addChangeListener(callback) { this.on(CHANGE_EVENT, callback); } + removeChangeListener(callback) { this.removeListener(CHANGE_EVENT, callback); } + handleMessage(msg) { switch (msg.action) { case SocketEvents.POSTED: @@ -153,6 +160,7 @@ class SocketStoreClass extends EventEmitter { default: } } + sendMessage(msg) { if (conn && conn.readyState === WebSocket.OPEN) { conn.send(JSON.stringify(msg)); @@ -161,9 +169,16 @@ class SocketStoreClass extends EventEmitter { this.initialize(); } } + setTranslations(messages) { this.translations = messages; } + + close() { + if (conn && conn.readyState === WebSocket.OPEN) { + conn.close(); + } + } } function handleNewPostEvent(msg, translations) { @@ -305,12 +320,5 @@ function handlePreferenceChangedEvent(msg) { var SocketStore = new SocketStoreClass(); -/*SocketStore.dispatchToken = AppDispatcher.register((payload) => { - var action = payload.action; - - switch (action.type) { - default: - } - });*/ - export default SocketStore; +window.SocketStore = SocketStore; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index c1bd41b88..d78776aa3 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -464,8 +464,9 @@ export default { }, OVERLAY_TIME_DELAY: 400, MIN_USERNAME_LENGTH: 3, - MAX_USERNAME_LENGTH: 15, + MAX_USERNAME_LENGTH: 64, MIN_PASSWORD_LENGTH: 5, MAX_PASSWORD_LENGTH: 50, - TIME_SINCE_UPDATE_INTERVAL: 30000 + TIME_SINCE_UPDATE_INTERVAL: 30000, + MIN_HASHTAG_LINK_LENGTH: 3 }; diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index e837ded53..dae2252a6 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -248,8 +248,14 @@ function autolinkHashtags(text, tokens) { const index = tokens.size; const alias = `MM_HASHTAG${index}`; + let value = hashtag; + + if (hashtag.length > Constants.MIN_HASHTAG_LINK_LENGTH) { + value = `<a class='mention-link' href='#' data-hashtag='${hashtag}'>${hashtag}</a>`; + } + tokens.set(alias, { - value: `<a class='mention-link' href='#' data-hashtag='${hashtag}'>${hashtag}</a>`, + value, originalText: hashtag }); diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 6bb7baa64..4beec8d64 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -14,6 +14,8 @@ import * as AsyncClient from './async_client.jsx'; import * as client from './client.jsx'; import Autolinker from 'autolinker'; +import {FormattedTime} from 'mm-intl'; + export function isEmail(email) { // writing a regex to match all valid email addresses is really, really hard (see http://stackoverflow.com/a/201378) // so we just do a simple check and rely on a verification email to tell if it's a real address @@ -245,6 +247,19 @@ export function displayTime(ticks, utc) { return hours + ':' + minutes + ampm + timezone; } +export function displayTimeFormatted(ticks) { + const useMilitaryTime = PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time'); + + return ( + <FormattedTime + value={ticks} + hour='numeric' + minute='numeric' + hour12={!useMilitaryTime} + /> + ); +} + export function displayDateTime(ticks) { var seconds = Math.floor((Date.now() - ticks) / 1000); diff --git a/web/templates/head.html b/web/templates/head.html index b1ec905b5..da65e1779 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -122,6 +122,12 @@ } }); }); + + $(window).on('beforeunload', function(){ + if (window.SocketStore) { + SocketStore.close(); + } + }); </script> <script> |