summaryrefslogtreecommitdiffstats
path: root/web/react
diff options
context:
space:
mode:
Diffstat (limited to 'web/react')
-rw-r--r--web/react/components/create_post.jsx26
-rw-r--r--web/react/components/edit_post_modal.jsx36
-rw-r--r--web/react/components/navbar_dropdown.jsx25
-rw-r--r--web/react/components/post_list.jsx3
-rw-r--r--web/react/components/rhs_thread.jsx14
-rw-r--r--web/react/components/sidebar.jsx6
-rw-r--r--web/react/components/textbox.jsx8
-rw-r--r--web/react/components/user_settings/user_settings.jsx12
-rw-r--r--web/react/components/user_settings/user_settings_display.jsx168
-rw-r--r--web/react/components/user_settings/user_settings_modal.jsx1
-rw-r--r--web/react/pages/channel.jsx3
-rw-r--r--web/react/stores/post_store.jsx37
-rw-r--r--web/react/stores/preference_store.jsx1
-rw-r--r--web/react/utils/async_client.jsx15
-rw-r--r--web/react/utils/client.jsx13
-rw-r--r--web/react/utils/constants.jsx13
-rw-r--r--web/react/utils/utils.jsx33
17 files changed, 377 insertions, 37 deletions
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index 6203e567a..2581bdcca 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -16,6 +16,7 @@ const Utils = require('../utils/utils.jsx');
const Constants = require('../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
+const KeyCodes = Constants.KeyCodes;
export default class CreatePost extends React.Component {
constructor(props) {
@@ -35,6 +36,7 @@ export default class CreatePost extends React.Component {
this.removePreview = this.removePreview.bind(this);
this.onChange = this.onChange.bind(this);
this.getFileCount = this.getFileCount.bind(this);
+ this.handleArrowUp = this.handleArrowUp.bind(this);
PostStore.clearDraftUploads();
@@ -172,7 +174,7 @@ export default class CreatePost extends React.Component {
}
}
postMsgKeyPress(e) {
- if (e.which === 13 && !e.shiftKey && !e.altKey) {
+ if (e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) {
e.preventDefault();
ReactDOM.findDOMNode(this.refs.textbox).blur();
this.handleSubmit(e);
@@ -292,6 +294,27 @@ export default class CreatePost extends React.Component {
const draft = PostStore.getDraft(channelId);
return draft.previews.length + draft.uploadsInProgress.length;
}
+ handleArrowUp(e) {
+ if (e.keyCode === KeyCodes.UP && this.state.messageText === '') {
+ e.preventDefault();
+
+ const channelId = ChannelStore.getCurrentId();
+ const lastPost = PostStore.getCurrentUsersLatestPost(channelId);
+ if (!lastPost) {
+ return;
+ }
+ var type = (lastPost.root_id && lastPost.root_id.length > 0) ? 'Comment' : 'Post';
+
+ AppDispatcher.handleViewAction({
+ type: ActionTypes.RECIEVED_EDIT_POST,
+ refocusId: '#post_textbox',
+ title: type,
+ message: lastPost.message,
+ postId: lastPost.id,
+ channelId: lastPost.channel_id
+ });
+ }
+ }
render() {
let serverError = null;
if (this.state.serverError) {
@@ -336,6 +359,7 @@ export default class CreatePost extends React.Component {
<Textbox
onUserInput={this.handleUserInput}
onKeyPress={this.postMsgKeyPress}
+ onKeyDown={this.handleArrowUp}
onHeightChange={this.resizePostHolder}
messageText={this.state.messageText}
createMessage='Write a message...'
diff --git a/web/react/components/edit_post_modal.jsx b/web/react/components/edit_post_modal.jsx
index 3dbff18cb..90d9696e7 100644
--- a/web/react/components/edit_post_modal.jsx
+++ b/web/react/components/edit_post_modal.jsx
@@ -5,6 +5,7 @@ var Client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var Textbox = require('./textbox.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
+var PostStore = require('../stores/post_store.jsx');
export default class EditPostModal extends React.Component {
constructor() {
@@ -14,6 +15,7 @@ export default class EditPostModal extends React.Component {
this.handleEditInput = this.handleEditInput.bind(this);
this.handleEditKeyPress = this.handleEditKeyPress.bind(this);
this.handleUserInput = this.handleUserInput.bind(this);
+ this.handleEditPostEvent = this.handleEditPostEvent.bind(this);
this.state = {editText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
}
@@ -35,16 +37,15 @@ export default class EditPostModal extends React.Component {
Client.updatePost(updatedPost,
function success() {
- AsyncClient.getPosts(this.state.channel_id);
+ AsyncClient.getPosts(updatedPost.channel_id);
window.scrollTo(0, 0);
- }.bind(this),
+ },
function error(err) {
AsyncClient.dispatchError(err, 'updatePost');
}
);
$('#edit_post').modal('hide');
- $(this.state.refocusId).focus();
}
handleEditInput(editMessage) {
this.setState({editText: editMessage});
@@ -59,6 +60,18 @@ export default class EditPostModal extends React.Component {
handleUserInput(e) {
this.setState({editText: e.target.value});
}
+ handleEditPostEvent(options) {
+ this.setState({
+ editText: options.message || '',
+ title: options.title || '',
+ post_id: options.postId || '',
+ channel_id: options.channelId || '',
+ comments: options.comments || 0,
+ refocusId: options.refocusId || ''
+ });
+
+ $(React.findDOMNode(this.refs.modal)).modal('show');
+ }
componentDidMount() {
var self = this;
@@ -68,12 +81,29 @@ export default class EditPostModal extends React.Component {
$(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function onShow(e) {
var button = e.relatedTarget;
+ if (!button) {
+ return;
+ }
self.setState({editText: $(button).attr('data-message'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), post_id: $(button).attr('data-postid'), comments: $(button).attr('data-comments'), refocusId: $(button).attr('data-refoucsid')});
});
$(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', function onShown() {
self.refs.editbox.resize();
+ $('#edit_textbox').get(0).focus();
});
+
+ $(React.findDOMNode(this.refs.modal)).on('hide.bs.modal', function onShown() {
+ if (self.state.refocusId !== '') {
+ setTimeout(() => {
+ $(self.state.refocusId).get(0).focus();
+ });
+ }
+ });
+
+ PostStore.addEditPostListener(this.handleEditPostEvent);
+ }
+ componentWillUnmount() {
+ PostStore.removeEditPostListener(this.handleEditPostEvent);
}
render() {
var error = (<div className='form-group'><br /></div>);
diff --git a/web/react/components/navbar_dropdown.jsx b/web/react/components/navbar_dropdown.jsx
index 33a7bf26d..2b2cc2f95 100644
--- a/web/react/components/navbar_dropdown.jsx
+++ b/web/react/components/navbar_dropdown.jsx
@@ -11,7 +11,24 @@ var AboutBuildModal = require('./about_build_modal.jsx');
var Constants = require('../utils/constants.jsx');
function getStateFromStores() {
- return {teams: UserStore.getTeams()};
+ let teams = [];
+ let teamsObject = UserStore.getTeams();
+ for (let teamId in teamsObject) {
+ if (teamsObject.hasOwnProperty(teamId)) {
+ teams.push(teamsObject[teamId]);
+ }
+ }
+ teams.sort(function sortByDisplayName(teamA, teamB) {
+ let teamADisplayName = teamA.display_name.toLowerCase();
+ let teamBDisplayName = teamB.display_name.toLowerCase();
+ if (teamADisplayName < teamBDisplayName) {
+ return -1;
+ } else if (teamADisplayName > teamBDisplayName) {
+ return 1;
+ }
+ return 0;
+ });
+ return {teams};
}
export default class NavbarDropdown extends React.Component {
@@ -154,9 +171,9 @@ export default class NavbarDropdown extends React.Component {
</li>
);
- this.state.teams.forEach((teamName) => {
- if (teamName !== this.props.teamName) {
- teams.push(<li key={teamName}><a href={Utils.getWindowLocationOrigin() + '/' + teamName}>{'Switch to ' + teamName}</a></li>);
+ this.state.teams.forEach((team) => {
+ if (team.name !== this.props.teamName) {
+ teams.push(<li key={team.name}><a href={Utils.getWindowLocationOrigin() + '/' + team.name}>{'Switch to ' + team.display_name}</a></li>);
}
});
}
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index 7e5160c2b..29728d368 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -4,6 +4,7 @@
var PostStore = require('../stores/post_store.jsx');
var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx');
+var PreferenceStore = require('../stores/preference_store.jsx');
var UserProfile = require('./user_profile.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var Post = require('./post.jsx');
@@ -105,6 +106,7 @@ export default class PostList extends React.Component {
PostStore.clearUnseenDeletedPosts(this.props.channelId);
PostStore.addChangeListener(this.onChange);
UserStore.addStatusesChangeListener(this.onTimeChange);
+ PreferenceStore.addChangeListener(this.onTimeChange);
SocketStore.addChangeListener(this.onSocketChange);
const postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
@@ -156,6 +158,7 @@ export default class PostList extends React.Component {
PostStore.removeChangeListener(this.onChange);
UserStore.removeStatusesChangeListener(this.onTimeChange);
SocketStore.removeChangeListener(this.onSocketChange);
+ PreferenceStore.removeChangeListener(this.onTimeChange);
$('body').off('click.userpopover');
$(window).off('resize');
var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index 131253aa5..467d74681 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -3,6 +3,7 @@
var PostStore = require('../stores/post_store.jsx');
var UserStore = require('../stores/user_store.jsx');
+var PreferenceStore = require('../stores/preference_store.jsx');
var utils = require('../utils/utils.jsx');
var SearchBox = require('./search_bar.jsx');
var CreateComment = require('./create_comment.jsx');
@@ -18,6 +19,7 @@ export default class RhsThread extends React.Component {
this.onChange = this.onChange.bind(this);
this.onChangeAll = this.onChangeAll.bind(this);
+ this.forceUpdateInfo = this.forceUpdateInfo.bind(this);
this.state = this.getStateFromStores();
}
@@ -43,6 +45,7 @@ export default class RhsThread extends React.Component {
componentDidMount() {
PostStore.addSelectedPostChangeListener(this.onChange);
PostStore.addChangeListener(this.onChangeAll);
+ PreferenceStore.addChangeListener(this.forceUpdateInfo);
this.resize();
$(window).resize(function resize() {
this.resize();
@@ -57,6 +60,16 @@ export default class RhsThread extends React.Component {
componentWillUnmount() {
PostStore.removeSelectedPostChangeListener(this.onChange);
PostStore.removeChangeListener(this.onChangeAll);
+ PreferenceStore.removeChangeListener(this.forceUpdateInfo);
+ }
+ forceUpdateInfo() {
+ if (this.state.postList) {
+ for (var postId in this.state.postList.posts) {
+ if (this.refs[postId]) {
+ this.refs[postId].forceUpdate();
+ }
+ }
+ }
}
onChange() {
var newState = this.getStateFromStores();
@@ -174,6 +187,7 @@ export default class RhsThread extends React.Component {
/>
<div className='post-right__scroll'>
<RootPost
+ ref={rootPost.id}
post={rootPost}
commentCount={postsArray.length}
/>
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 5561c5b73..2c98db7f3 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -132,11 +132,7 @@ export default class Sidebar extends React.Component {
SocketStore.addChangeListener(this.onSocketChange);
PreferenceStore.addChangeListener(this.onChange);
- AsyncClient.getDirectChannelPreferences();
-
- if ($(window).width() > 768) {
- $('.nav-pills__container').perfectScrollbar();
- }
+ $('.nav-pills__container').perfectScrollbar();
this.updateTitle();
this.updateUnreadIndicators();
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index d51fb9523..86bb42f62 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -9,6 +9,7 @@ const ErrorStore = require('../stores/error_store.jsx');
const Utils = require('../utils/utils.jsx');
const Constants = require('../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
+const KeyCodes = Constants.KeyCodes;
export default class Textbox extends React.Component {
constructor(props) {
@@ -148,8 +149,10 @@ export default class Textbox extends React.Component {
this.doProcessMentions = true;
}
- if (e.keyCode === 8) {
+ if (e.keyCode === KeyCodes.BACKSPACE) {
this.handleBackspace(e);
+ } else if (this.props.onKeyDown) {
+ this.props.onKeyDown(e);
}
}
@@ -318,5 +321,6 @@ Textbox.propTypes = {
onUserInput: React.PropTypes.func.isRequired,
onKeyPress: React.PropTypes.func.isRequired,
onHeightChange: React.PropTypes.func,
- createMessage: React.PropTypes.string.isRequired
+ createMessage: React.PropTypes.string.isRequired,
+ onKeyDown: React.PropTypes.func
};
diff --git a/web/react/components/user_settings/user_settings.jsx b/web/react/components/user_settings/user_settings.jsx
index 5ce9b6330..15bf961d6 100644
--- a/web/react/components/user_settings/user_settings.jsx
+++ b/web/react/components/user_settings/user_settings.jsx
@@ -9,6 +9,7 @@ var GeneralTab = require('./user_settings_general.jsx');
var AppearanceTab = require('./user_settings_appearance.jsx');
var DeveloperTab = require('./user_settings_developer.jsx');
var IntegrationsTab = require('./user_settings_integrations.jsx');
+var DisplayTab = require('./user_settings_display.jsx');
export default class UserSettings extends React.Component {
constructor(props) {
@@ -98,6 +99,17 @@ export default class UserSettings extends React.Component {
/>
</div>
);
+ } else if (this.props.activeTab === 'display') {
+ return (
+ <div>
+ <DisplayTab
+ user={this.state.user}
+ activeSection={this.props.activeSection}
+ updateSection={this.props.updateSection}
+ updateTab={this.props.updateTab}
+ />
+ </div>
+ );
}
return <div/>;
diff --git a/web/react/components/user_settings/user_settings_display.jsx b/web/react/components/user_settings/user_settings_display.jsx
new file mode 100644
index 000000000..ec209c218
--- /dev/null
+++ b/web/react/components/user_settings/user_settings_display.jsx
@@ -0,0 +1,168 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import { savePreferences } from '../../utils/client.jsx';
+import SettingItemMin from '../setting_item_min.jsx';
+import SettingItemMax from '../setting_item_max.jsx';
+import Constants from '../../utils/constants.jsx';
+import PreferenceStore from '../../stores/preference_store.jsx';
+
+function getDisplayStateFromStores() {
+ const militaryTime = PreferenceStore.getPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', {value: 'false'});
+
+ return {militaryTime: militaryTime.value};
+}
+
+export default class UserSettingsDisplay extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleClockRadio = this.handleClockRadio.bind(this);
+ this.updateSection = this.updateSection.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+
+ this.state = getDisplayStateFromStores();
+ }
+ handleSubmit() {
+ const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', this.state.militaryTime);
+
+ savePreferences([preference],
+ () => {
+ PreferenceStore.emitChange();
+ this.updateSection('');
+ },
+ (err) => {
+ this.setState({serverError: err.message});
+ }
+ );
+ }
+ handleClockRadio(militaryTime) {
+ this.setState({militaryTime: militaryTime});
+ }
+ updateSection(section) {
+ this.setState(getDisplayStateFromStores());
+ this.props.updateSection(section);
+ }
+ handleClose() {
+ this.updateSection('');
+ }
+ componentDidMount() {
+ $('#user_settings').on('hidden.bs.modal', this.handleClose);
+ }
+ componentWillUnmount() {
+ $('#user_settings').off('hidden.bs.modal', this.handleClose);
+ }
+ render() {
+ const serverError = this.state.serverError || null;
+ let clockSection;
+ if (this.props.activeSection === 'clock') {
+ let clockFormat = [false, false];
+ if (this.state.militaryTime === 'true') {
+ clockFormat[1] = true;
+ } else {
+ clockFormat[0] = true;
+ }
+
+ const handleUpdateClockSection = (e) => {
+ this.updateSection('');
+ e.preventDefault();
+ };
+
+ const inputs = [
+ <div key='userDisplayClockOptions'>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={clockFormat[0]}
+ onChange={this.handleClockRadio.bind(this, 'false')}
+ >
+ 12-hour clock (example: 4:00 PM)
+ </input>
+ </label>
+ <br/>
+ </div>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={clockFormat[1]}
+ onChange={this.handleClockRadio.bind(this, 'true')}
+ >
+ 24-hour clock (example: 16:00)
+ </input>
+ </label>
+ <br/>
+ </div>
+ <div><br/>{'Select how you prefer time displayed.'}</div>
+ </div>
+ ];
+
+
+ clockSection = (
+ <SettingItemMax
+ title='Clock Display'
+ inputs={inputs}
+ submit={this.handleSubmit}
+ server_error={serverError}
+ updateSection={handleUpdateClockSection}
+ />
+ );
+ } else {
+ let describe = '';
+ if (this.state.militaryTime === 'true') {
+ describe = '24-hour clock (example: 16:00)';
+ } else {
+ describe = '12-hour clock (example: 4:00 PM)';
+ }
+
+ const handleUpdateClockSection = () => {
+ this.props.updateSection('clock');
+ };
+
+ clockSection = (
+ <SettingItemMin
+ title='Clock Display'
+ describe={describe}
+ updateSection={handleUpdateClockSection}
+ />
+ );
+ }
+
+ return (
+ <div>
+ <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'
+ ref='title'
+ >
+ <i className='modal-back'></i>
+ {'Display Settings'}
+ </h4>
+ </div>
+ <div className='user-settings'>
+ <h3 className='tab-header'>{'Display Settings'}</h3>
+ <div className='divider-dark first'/>
+ {clockSection}
+ <div className='divider-dark'/>
+ </div>
+ </div>
+ );
+ }
+}
+
+UserSettingsDisplay.propTypes = {
+ user: React.PropTypes.object,
+ updateSection: React.PropTypes.func,
+ updateTab: React.PropTypes.func,
+ activeSection: React.PropTypes.string
+};
diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx
index fbb003fd5..4296d7909 100644
--- a/web/react/components/user_settings/user_settings_modal.jsx
+++ b/web/react/components/user_settings/user_settings_modal.jsx
@@ -41,6 +41,7 @@ export default class UserSettingsModal extends React.Component {
if (global.window.mm_config.EnableIncomingWebhooks === 'true') {
tabs.push({name: 'integrations', uiName: 'Integrations', icon: 'glyphicon glyphicon-transfer'});
}
+ tabs.push({name: 'display', uiName: 'Display', icon: 'glyphicon glyphicon-eye-open'});
return (
<div
diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx
index d63bad35e..03e049db0 100644
--- a/web/react/pages/channel.jsx
+++ b/web/react/pages/channel.jsx
@@ -36,6 +36,7 @@ var FileUploadOverlay = require('../components/file_upload_overlay.jsx');
var RegisterAppModal = require('../components/register_app_modal.jsx');
var ImportThemeModal = require('../components/user_settings/import_theme_modal.jsx');
+var AsyncClient = require('../utils/async_client.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
@@ -46,6 +47,8 @@ function setupChannelPage(props) {
id: props.ChannelId
});
+ AsyncClient.getAllPreferences();
+
// ChannelLoader must be rendered first
ReactDOM.render(
<ChannelLoader/>,
diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx
index 07e8b461e..b073ca68d 100644
--- a/web/react/stores/post_store.jsx
+++ b/web/react/stores/post_store.jsx
@@ -6,6 +6,7 @@ var EventEmitter = require('events').EventEmitter;
var ChannelStore = require('../stores/channel_store.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
+var UserStore = require('../stores/user_store.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
@@ -16,6 +17,7 @@ var SEARCH_TERM_CHANGE_EVENT = 'search_term_change';
var SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
var MENTION_DATA_CHANGE_EVENT = 'mention_data_change';
var ADD_MENTION_EVENT = 'add_mention';
+var EDIT_POST_EVENT = 'edit_post';
class PostStoreClass extends EventEmitter {
constructor() {
@@ -75,6 +77,10 @@ class PostStoreClass extends EventEmitter {
this.clearCommentDraftUploads = this.clearCommentDraftUploads.bind(this);
this.storeLatestUpdate = this.storeLatestUpdate.bind(this);
this.getLatestUpdate = this.getLatestUpdate.bind(this);
+ this.emitEditPost = this.emitEditPost.bind(this);
+ this.addEditPostListener = this.addEditPostListener.bind(this);
+ this.removeEditPostListener = this.removeEditPostListener.bind(this);
+ this.getCurrentUsersLatestPost = this.getCurrentUsersLatestPost.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT);
@@ -148,6 +154,18 @@ class PostStoreClass extends EventEmitter {
this.removeListener(ADD_MENTION_EVENT, callback);
}
+ emitEditPost(post) {
+ this.emit(EDIT_POST_EVENT, post);
+ }
+
+ addEditPostListener(callback) {
+ this.on(EDIT_POST_EVENT, callback);
+ }
+
+ removeEditPostListener(callback) {
+ this.removeListener(EDIT_POST_EVENT, callback);
+ }
+
getCurrentPosts() {
var currentId = ChannelStore.getCurrentId();
@@ -212,6 +230,22 @@ class PostStoreClass extends EventEmitter {
getPosts(channelId) {
return BrowserStore.getItem('posts_' + channelId);
}
+ getCurrentUsersLatestPost(channelId) {
+ const userId = UserStore.getCurrentId();
+ var postList = makePostListNonNull(this.getPosts(channelId));
+ var i = 0;
+ var len = postList.order.length;
+ var lastPost = null;
+
+ for (i; i < len; i++) {
+ if (postList.posts[postList.order[i]].user_id === userId) {
+ lastPost = postList.posts[postList.order[i]];
+ break;
+ }
+ }
+
+ return lastPost;
+ }
storePost(post) {
this.pStorePost(post);
this.emitChange();
@@ -446,6 +480,9 @@ PostStore.dispatchToken = AppDispatcher.register(function registry(payload) {
case ActionTypes.RECIEVED_ADD_MENTION:
PostStore.emitAddMention(action.id, action.username);
break;
+ case ActionTypes.RECIEVED_EDIT_POST:
+ PostStore.emitEditPost(action);
+ break;
default:
}
});
diff --git a/web/react/stores/preference_store.jsx b/web/react/stores/preference_store.jsx
index d71efa10f..f630d150d 100644
--- a/web/react/stores/preference_store.jsx
+++ b/web/react/stores/preference_store.jsx
@@ -120,3 +120,4 @@ class PreferenceStoreClass extends EventEmitter {
const PreferenceStore = new PreferenceStoreClass();
export default PreferenceStore;
+window.PreferenceStore = PreferenceStore;
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
index 379c2fc19..fb7631159 100644
--- a/web/react/utils/async_client.jsx
+++ b/web/react/utils/async_client.jsx
@@ -639,16 +639,15 @@ export function getMyTeam() {
);
}
-export function getDirectChannelPreferences() {
- if (isCallInProgress('getDirectChannelPreferences')) {
+export function getAllPreferences() {
+ if (isCallInProgress('getAllPreferences')) {
return;
}
- callTracker.getDirectChannelPreferences = utils.getTimestamp();
- client.getPreferenceCategory(
- Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
+ callTracker.getAllPreferences = utils.getTimestamp();
+ client.getAllPreferences(
(data, textStatus, xhr) => {
- callTracker.getDirectChannelPreferences = 0;
+ callTracker.getAllPreferences = 0;
if (xhr.status === 304 || !data) {
return;
@@ -660,8 +659,8 @@ export function getDirectChannelPreferences() {
});
},
(err) => {
- callTracker.getDirectChannelPreferences = 0;
- dispatchError(err, 'getDirectChannelPreferences');
+ callTracker.getAllPreferences = 0;
+ dispatchError(err, 'getAllPreferences');
}
);
}
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index f1df2a786..3130e9277 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -1142,6 +1142,19 @@ export function listIncomingHooks(success, error) {
});
}
+export function getAllPreferences(success, error) {
+ $.ajax({
+ url: `/api/v1/preferences/`,
+ dataType: 'json',
+ type: 'GET',
+ success,
+ error: (xhr, status, err) => {
+ var e = handleError('getAllPreferences', xhr, status, err);
+ error(e);
+ }
+ });
+}
+
export function getPreferenceCategory(category, success, error) {
$.ajax({
url: `/api/v1/preferences/${category}`,
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index a7b0b159b..d6da91fe2 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -17,6 +17,7 @@ module.exports = {
RECIEVED_POSTS: null,
RECIEVED_POST: null,
+ RECIEVED_EDIT_POST: null,
RECIEVED_SEARCH: null,
RECIEVED_POST_SELECTED: null,
RECIEVED_MENTION_DATA: null,
@@ -287,6 +288,16 @@ module.exports = {
}
],
Preferences: {
- CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show'
+ CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show',
+ CATEGORY_DISPLAY_SETTINGS: 'display_settings'
+ },
+ KeyCodes: {
+ UP: 38,
+ DOWN: 40,
+ LEFT: 37,
+ RIGHT: 39,
+ BACKSPACE: 8,
+ ENTER: 13,
+ ESCAPE: 27
}
};
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 0457d620f..561c2c4c4 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -4,6 +4,7 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx');
+var PreferenceStore = require('../stores/preference_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
@@ -164,23 +165,29 @@ export function displayDate(ticks) {
}
export function displayTime(ticks) {
- var d = new Date(ticks);
- var hours = d.getHours();
- var minutes = d.getMinutes();
-
- var ampm = 'AM';
- if (hours >= 12) {
- ampm = 'PM';
- }
+ const d = new Date(ticks);
+ let hours = d.getHours();
+ let minutes = d.getMinutes();
+ let ampm = '';
- hours = hours % 12;
- if (!hours) {
- hours = '12';
- }
if (minutes <= 9) {
minutes = '0' + minutes;
}
- return hours + ':' + minutes + ' ' + ampm;
+
+ const useMilitaryTime = PreferenceStore.getPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', {value: 'false'}).value;
+ if (useMilitaryTime === 'false') {
+ ampm = ' AM';
+ if (hours >= 12) {
+ ampm = ' PM';
+ }
+
+ hours = hours % 12;
+ if (!hours) {
+ hours = '12';
+ }
+ }
+
+ return hours + ':' + minutes + ampm;
}
export function displayDateTime(ticks) {