Этот коммит содержится в:
nickago
2015-08-31 10:10:22 -07:00
родитель 72575ac7bd
Коммит 069f851313
28 изменённых файлов: 1487 добавлений и 986 удалений

Просмотреть файл

@@ -3,13 +3,21 @@
var Client = require('../utils/client.jsx'); var Client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_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 Textbox = require('./textbox.jsx');
var BrowserStore = require('../stores/browser_store.jsx'); var BrowserStore = require('../stores/browser_store.jsx');
module.exports = React.createClass({ export default class EditPostModal extends React.Component {
handleEdit: function(e) { constructor() {
super();
this.handleEdit = this.handleEdit.bind(this);
this.handleEditInput = this.handleEditInput.bind(this);
this.handleEditKeyPress = this.handleEditKeyPress.bind(this);
this.handleUserInput = this.handleUserInput.bind(this);
this.state = {editText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
}
handleEdit() {
var updatedPost = {}; var updatedPost = {};
updatedPost.message = this.state.editText.trim(); updatedPost.message = this.state.editText.trim();
@@ -17,8 +25,8 @@ module.exports = React.createClass({
var tempState = this.state; var tempState = this.state;
delete tempState.editText; delete tempState.editText;
BrowserStore.setItem('edit_state_transfer', tempState); BrowserStore.setItem('edit_state_transfer', tempState);
$("#edit_post").modal('hide'); $('#edit_post').modal('hide');
$("#delete_post").modal('show'); $('#delete_post').modal('show');
return; return;
} }
@@ -26,79 +34,102 @@ module.exports = React.createClass({
updatedPost.channel_id = this.state.channel_id; updatedPost.channel_id = this.state.channel_id;
Client.updatePost(updatedPost, Client.updatePost(updatedPost,
function(data) { function success() {
AsyncClient.getPosts(this.state.channel_id); AsyncClient.getPosts(this.state.channel_id);
window.scrollTo(0, 0); window.scrollTo(0, 0);
}.bind(this), }.bind(this),
function(err) { function error(err) {
AsyncClient.dispatchError(err, "updatePost"); AsyncClient.dispatchError(err, 'updatePost');
}.bind(this) }
); );
$("#edit_post").modal('hide'); $('#edit_post').modal('hide');
$(this.state.refocusId).focus(); $(this.state.refocusId).focus();
}, }
handleEditInput: function(editMessage) { handleEditInput(editMessage) {
this.setState({editText: editMessage}); this.setState({editText: editMessage});
}, }
handleEditKeyPress: function(e) { handleEditKeyPress(e) {
if (e.which == 13 && !e.shiftKey && !e.altKey) { if (e.which === 13 && !e.shiftKey && !e.altKey) {
e.preventDefault(); e.preventDefault();
this.refs.editbox.getDOMNode().blur(); React.findDOMNode(this.refs.editbox).blur();
this.handleEdit(e); this.handleEdit(e);
} }
}, }
handleUserInput: function(e) { handleUserInput(e) {
this.setState({ editText: e.target.value }); this.setState({editText: e.target.value});
}, }
componentDidMount: function() { componentDidMount() {
var self = this; var self = this;
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) { $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function onHidden() {
self.setState({editText: "", title: "", channel_id: "", post_id: "", comments: 0, refocusId: "", error: ''}); self.setState({editText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''});
}); });
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onShow(e) {
var button = e.relatedTarget; var button = e.relatedTarget;
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') }); 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')});
}); });
$(this.refs.modal.getDOMNode()).on('shown.bs.modal', function(e) { $(React.findDOMNode(this.refs.modal)).on('shown.bs.modal', function onShown() {
self.refs.editbox.resize(); self.refs.editbox.resize();
}); });
}, }
getInitialState: function() { render() {
return { editText: "", title: "", post_id: "", channel_id: "", comments: 0, refocusId: "" }; var error = (<div className='form-group'><br /></div>);
}, if (this.state.error) {
render: function() { error = (<div className='form-group has-error'><br /><label className='control-label'>{this.state.error}</label></div>);
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 ( return (
<div className="modal fade edit-modal" ref="modal" id="edit_post" role="dialog" tabIndex="-1" aria-hidden="true"> <div
<div className="modal-dialog modal-push-down"> className='modal fade edit-modal'
<div className="modal-content"> ref='modal'
<div className="modal-header"> id='edit_post'
<button type="button" className="close" data-dismiss="modal" aria-label="Close" onClick={this.handleEditClose}><span aria-hidden="true">&times;</span></button> role='dialog'
<h4 className="modal-title">Edit {this.state.title}</h4> tabIndex='-1'
</div> aria-hidden='true' >
<div className="edit-modal-body modal-body"> <div className='modal-dialog modal-push-down'>
<Textbox <div className='modal-content'>
onUserInput={this.handleEditInput} <div className='modal-header'>
onKeyPress={this.handleEditKeyPress} <button
messageText={this.state.editText} type='button'
createMessage="Edit the post..." className='close'
id="edit_textbox" data-dismiss='modal'
ref="editbox" aria-label='Close'
/> onClick={this.handleEditClose}>
{ error } <span aria-hidden='true'>&times;</span>
</div> </button>
<div className="modal-footer"> <h4 className='modal-title'>Edit {this.state.title}</h4>
<button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button> </div>
<button type="button" className="btn btn-primary" onClick={this.handleEdit}>Save</button> <div className='edit-modal-body modal-body'>
</div> <Textbox
onUserInput={this.handleEditInput}
onKeyPress={this.handleEditKeyPress}
messageText={this.state.editText}
createMessage='Edit the post...'
id='edit_textbox'
ref='editbox'
/>
{error}
</div>
<div className='modal-footer'>
<button
type='button'
className='btn btn-default'
data-dismiss='modal' >
Cancel
</button>
<button
type='button'
className='btn btn-primary'
onClick={this.handleEdit}>
Save
</button>
</div>
</div>
</div> </div>
</div>
</div> </div>
); );
} }
}); }

Просмотреть файл

@@ -7,32 +7,40 @@ var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
function getStateFromStores() { export default class ErrorBar extends React.Component {
var error = ErrorStore.getLastError(); constructor() {
if (error && error.message !== "There appears to be a problem with your internet connection") { super();
return { message: error.message };
} else { this.onErrorChange = this.onErrorChange.bind(this);
return { message: null }; this.handleClose = this.handleClose.bind(this);
this.state = this.getStateFromStores();
if (this.state.message) {
setTimeout(this.handleClose, 10000);
}
} }
} getStateFromStores() {
var error = ErrorStore.getLastError();
if (!error || error.message === 'There appears to be a problem with your internet connection') {
return {message: null};
}
module.exports = React.createClass({ return {message: error.message};
displayName: 'ErrorBar', }
componentDidMount() {
componentDidMount: function() { ErrorStore.addChangeListener(this.onErrorChange);
ErrorStore.addChangeListener(this._onChange);
$('body').css('padding-top', $(React.findDOMNode(this)).outerHeight()); $('body').css('padding-top', $(React.findDOMNode(this)).outerHeight());
$(window).resize(function() { $(window).resize(function onResize() {
if (this.state.message) { if (this.state.message) {
$('body').css('padding-top', $(React.findDOMNode(this)).outerHeight()); $('body').css('padding-top', $(React.findDOMNode(this)).outerHeight());
} }
}.bind(this)); }.bind(this));
}, }
componentWillUnmount: function() { componentWillUnmount() {
ErrorStore.removeChangeListener(this._onChange); ErrorStore.removeChangeListener(this.onErrorChange);
}, }
_onChange: function() { onErrorChange() {
var newState = getStateFromStores(); var newState = this.getStateFromStores();
if (!utils.areStatesEqual(newState, this.state)) { if (!utils.areStatesEqual(newState, this.state)) {
if (newState.message) { if (newState.message) {
setTimeout(this.handleClose, 10000); setTimeout(this.handleClose, 10000);
@@ -40,9 +48,11 @@ module.exports = React.createClass({
this.setState(newState); this.setState(newState);
} }
}, }
handleClose: function(e) { handleClose(e) {
if (e) e.preventDefault(); if (e) {
e.preventDefault();
}
AppDispatcher.handleServerAction({ AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_ERROR, type: ActionTypes.RECIEVED_ERROR,
@@ -50,24 +60,22 @@ module.exports = React.createClass({
}); });
$('body').css('padding-top', '0'); $('body').css('padding-top', '0');
}, }
getInitialState: function() { render() {
var state = getStateFromStores();
if (state.message) {
setTimeout(this.handleClose, 10000);
}
return state;
},
render: function() {
if (this.state.message) { if (this.state.message) {
return ( return (
<div className="error-bar"> <div className='error-bar'>
<span>{this.state.message}</span> <span>{this.state.message}</span>
<a href="#" className="error-bar__close" onClick={this.handleClose}>&times;</a> <a
href='#'
className='error-bar__close'
onClick={this.handleClose}>
&times;
</a>
</div> </div>
); );
} else {
return <div/>;
} }
return <div/>;
} }
}); }

Просмотреть файл

@@ -5,31 +5,24 @@ var utils = require('../utils/utils.jsx');
var Client = require('../utils/client.jsx'); var Client = require('../utils/client.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
module.exports = React.createClass({ export default class FileAttachment extends React.Component {
displayName: "FileAttachment", constructor(props) {
canSetState: false, super(props);
propTypes: {
// a list of file pathes displayed by the parent FileAttachmentList this.loadFiles = this.loadFiles.bind(this);
filename: React.PropTypes.string.isRequired,
// the index of this attachment preview in the parent FileAttachmentList this.canSetState = false;
index: React.PropTypes.number.isRequired, this.state = {fileSize: -1};
// the identifier of the modal dialog used to preview files }
modalId: React.PropTypes.string.isRequired, componentDidMount() {
// handler for when the thumbnail is clicked
handleImageClick: React.PropTypes.func
},
getInitialState: function() {
return {fileSize: -1};
},
componentDidMount: function() {
this.loadFiles(); this.loadFiles();
}, }
componentDidUpdate: function(prevProps) { componentDidUpdate(prevProps) {
if (this.props.filename !== prevProps.filename) { if (this.props.filename !== prevProps.filename) {
this.loadFiles(); this.loadFiles();
} }
}, }
loadFiles: function() { loadFiles() {
this.canSetState = true; this.canSetState = true;
var filename = this.props.filename; var filename = this.props.filename;
@@ -39,91 +32,92 @@ module.exports = React.createClass({
var type = utils.getFileType(fileInfo.ext); var type = utils.getFileType(fileInfo.ext);
// This is a temporary patch to fix issue with old files using absolute paths // This is a temporary patch to fix issue with old files using absolute paths
if (fileInfo.path.indexOf("/api/v1/files/get") != -1) { if (fileInfo.path.indexOf('/api/v1/files/get') !== -1) {
fileInfo.path = fileInfo.path.split("/api/v1/files/get")[1]; fileInfo.path = fileInfo.path.split('/api/v1/files/get')[1];
} }
fileInfo.path = utils.getWindowLocationOrigin() + "/api/v1/files/get" + fileInfo.path; fileInfo.path = utils.getWindowLocationOrigin() + '/api/v1/files/get' + fileInfo.path;
if (type === "image") { if (type === 'image') {
var self = this; var self = this; // Need this reference since we use the given "this"
$('<img/>').attr('src', fileInfo.path+'_thumb.jpg').load(function(path, name){ return function() { $('<img/>').attr('src', fileInfo.path + '_thumb.jpg').load(function loadWrapper(path, name) {
$(this).remove(); return function loader() {
if (name in self.refs) { $(this).remove();
var imgDiv = self.refs[name].getDOMNode(); if (name in self.refs) {
var imgDiv = React.findDOMNode(self.refs[name]);
$(imgDiv).removeClass('post__load'); $(imgDiv).removeClass('post__load');
$(imgDiv).addClass('post__image'); $(imgDiv).addClass('post__image');
var width = this.width || $(this).width(); var width = this.width || $(this).width();
var height = this.height || $(this).height(); var height = this.height || $(this).height();
if (width < Constants.THUMBNAIL_WIDTH if (width < Constants.THUMBNAIL_WIDTH &&
&& height < Constants.THUMBNAIL_HEIGHT) { height < Constants.THUMBNAIL_HEIGHT) {
$(imgDiv).addClass('small'); $(imgDiv).addClass('small');
} else { } else {
$(imgDiv).addClass('normal'); $(imgDiv).addClass('normal');
}
var re1 = new RegExp(' ', 'g');
var re2 = new RegExp('\\(', 'g');
var re3 = new RegExp('\\)', 'g');
var url = path.replace(re1, '%20').replace(re2, '%28').replace(re3, '%29');
$(imgDiv).css('background-image', 'url(' + url + '_thumb.jpg)');
} }
}; }(fileInfo.path, filename));
var re1 = new RegExp(' ', 'g');
var re2 = new RegExp('\\(', 'g');
var re3 = new RegExp('\\)', 'g');
var url = path.replace(re1, '%20').replace(re2, '%28').replace(re3, '%29');
$(imgDiv).css('background-image', 'url('+url+'_thumb.jpg)');
}
}}(fileInfo.path, filename));
} }
} }
}, }
componentWillUnmount: function() { componentWillUnmount() {
// keep track of when this component is mounted so that we can asynchronously change state without worrying about whether or not we're mounted // keep track of when this component is mounted so that we can asynchronously change state without worrying about whether or not we're mounted
this.canSetState = false; this.canSetState = false;
}, }
shouldComponentUpdate: function(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
if (!utils.areStatesEqual(nextProps, this.props)) { if (!utils.areStatesEqual(nextProps, this.props)) {
return true; return true;
} }
// the only time this object should update is when it receives an updated file size which we can usually handle without re-rendering // the only time this object should update is when it receives an updated file size which we can usually handle without re-rendering
if (nextState.fileSize != this.state.fileSize) { if (nextState.fileSize !== this.state.fileSize) {
if (this.refs.fileSize) { if (this.refs.fileSize) {
// update the UI element to display the file size without re-rendering the whole component // update the UI element to display the file size without re-rendering the whole component
this.refs.fileSize.getDOMNode().innerHTML = utils.fileSizeToString(nextState.fileSize); React.findDOMNode(this.refs.fileSize).innerHTML = utils.fileSizeToString(nextState.fileSize);
return false; return false;
} else {
// we can't find the element that should hold the file size so we must not have rendered yet
return true;
} }
} else {
// we can't find the element that should hold the file size so we must not have rendered yet
return true; return true;
} }
},
render: function() { return true;
}
render() {
var filename = this.props.filename; var filename = this.props.filename;
var fileInfo = utils.splitFileLocation(filename); var fileInfo = utils.splitFileLocation(filename);
var type = utils.getFileType(fileInfo.ext); var type = utils.getFileType(fileInfo.ext);
var thumbnail; var thumbnail;
if (type === "image") { if (type === 'image') {
thumbnail = <div ref={filename} className="post__load" style={{backgroundImage: 'url(/static/images/load.gif)'}}/>; thumbnail = (<div
ref={filename}
className='post__load'
style={{backgroundImage: 'url(/static/images/load.gif)'}} />);
} else { } else {
thumbnail = <div className={"file-icon "+utils.getIconClassName(type)}/>; thumbnail = <div className={'file-icon ' + utils.getIconClassName(type)}/>;
} }
var fileSizeString = ""; var fileSizeString = '';
if (this.state.fileSize < 0) { if (this.state.fileSize < 0) {
var self = this;
Client.getFileInfo( Client.getFileInfo(
filename, filename,
function(data) { function success(data) {
if (self.canSetState) { if (this.canSetState) {
self.setState({fileSize: parseInt(data["size"], 10)}); this.setState({fileSize: parseInt(data.size, 10)});
} }
}, }.bind(this),
function(err) { function error() {}
}
); );
} else { } else {
fileSizeString = utils.fileSizeToString(this.state.fileSize); fileSizeString = utils.fileSizeToString(this.state.fileSize);
@@ -132,25 +126,51 @@ module.exports = React.createClass({
var filenameString = decodeURIComponent(utils.getFileName(filename)); var filenameString = decodeURIComponent(utils.getFileName(filename));
var trimmedFilename; var trimmedFilename;
if (filenameString.length > 35) { if (filenameString.length > 35) {
trimmedFilename = filenameString.substring(0, Math.min(35, filenameString.length)) + "..."; trimmedFilename = filenameString.substring(0, Math.min(35, filenameString.length)) + '...';
} else { } else {
trimmedFilename = filenameString; trimmedFilename = filenameString;
} }
return ( return (
<div className="post-image__column" key={filename}> <div
<a className="post-image__thumbnail" href="#" onClick={this.props.handleImageClick} className='post-image__column'
data-img-id={this.props.index} data-toggle="modal" data-target={"#" + this.props.modalId }> key={filename}>
<a className='post-image__thumbnail'
href='#'
onClick={this.props.handleImageClick}
data-img-id={this.props.index}
data-toggle='modal'
data-target={'#' + this.props.modalId} >
{thumbnail} {thumbnail}
</a> </a>
<div className="post-image__details"> <div className='post-image__details'>
<div data-toggle="tooltip" title={filenameString} className="post-image__name">{trimmedFilename}</div> <div
data-toggle='tooltip'
title={filenameString}
className='post-image__name' >
{trimmedFilename}
</div>
<div> <div>
<span className="post-image__type">{fileInfo.ext.toUpperCase()}</span> <span className='post-image__type'>{fileInfo.ext.toUpperCase()}</span>
<span className="post-image__size">{fileSizeString}</span> <span className='post-image__size'>{fileSizeString}</span>
</div> </div>
</div> </div>
</div> </div>
); );
} }
}); }
FileAttachment.propTypes = {
// a list of file pathes displayed by the parent FileAttachmentList
filename: React.PropTypes.string.isRequired,
// the index of this attachment preview in the parent FileAttachmentList
index: React.PropTypes.number.isRequired,
// the identifier of the modal dialog used to preview files
modalId: React.PropTypes.string.isRequired,
// handler for when the thumbnail is clicked
handleImageClick: React.PropTypes.func
};

Просмотреть файл

@@ -5,33 +5,30 @@ var ViewImageModal = require('./view_image.jsx');
var FileAttachment = require('./file_attachment.jsx'); var FileAttachment = require('./file_attachment.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
module.exports = React.createClass({ export default class FileAttachmentList extends React.Component {
displayName: "FileAttachmentList", constructor(props) {
propTypes: { super(props);
// a list of file pathes displayed by this this.state = {startImgId: 0};
filenames: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, }
// the identifier of the modal dialog used to preview files render() {
modalId: React.PropTypes.string.isRequired,
// the channel that this is part of
channelId: React.PropTypes.string,
// the user that owns the post that this is attached to
userId: React.PropTypes.string
},
getInitialState: function() {
return {startImgId: 0};
},
render: function() {
var filenames = this.props.filenames; var filenames = this.props.filenames;
var modalId = this.props.modalId; var modalId = this.props.modalId;
var postFiles = []; var postFiles = [];
for (var i = 0; i < filenames.length && i < Constants.MAX_DISPLAY_FILES; i++) { for (var i = 0; i < filenames.length && i < Constants.MAX_DISPLAY_FILES; i++) {
postFiles.push(<FileAttachment key={i} filename={filenames[i]} index={i} modalId={modalId} handleImageClick={this.handleImageClick} />); postFiles.push(
<FileAttachment
key={i}
filename={filenames[i]}
index={i}
modalId={modalId}
handleImageClick={this.handleImageClick} />
);
} }
return ( return (
<div> <div>
<div className="post-image__columns"> <div className='post-image__columns'>
{postFiles} {postFiles}
</div> </div>
<ViewImageModal <ViewImageModal
@@ -42,8 +39,23 @@ module.exports = React.createClass({
filenames={filenames} /> filenames={filenames} />
</div> </div>
); );
},
handleImageClick: function(e) {
this.setState({startImgId: parseInt($(e.target.parentNode).attr('data-img-id'))});
} }
}); handleImageClick(e) {
this.setState({startImgId: parseInt($(e.target.parentNode).attr('data-img-id'), 10)});
}
}
FileAttachmentList.propTypes = {
// a list of file pathes displayed by this
filenames: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
// the identifier of the modal dialog used to preview files
modalId: React.PropTypes.string.isRequired,
// the channel that this is part of
channelId: React.PropTypes.string,
// the user that owns the post that this is attached to
userId: React.PropTypes.string
};

Просмотреть файл

@@ -1,64 +1,116 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx'); var UserStore = require('../stores/user_store.jsx');
module.exports = React.createClass({ export default class MemberListItem extends React.Component {
displayName: 'MemberListItem', constructor(props) {
handleInvite: function(e) { super(props);
this.handleInvite = this.handleInvite.bind(this);
this.handleRemove = this.handleRemove.bind(this);
this.handleMakeAdmin = this.handleMakeAdmin.bind(this);
}
handleInvite(e) {
e.preventDefault(); e.preventDefault();
this.props.handleInvite(this.props.member.id); this.props.handleInvite(this.props.member.id);
}, }
handleRemove: function(e) { handleRemove(e) {
e.preventDefault(); e.preventDefault();
this.props.handleRemove(this.props.member.id); this.props.handleRemove(this.props.member.id);
}, }
handleMakeAdmin: function(e) { handleMakeAdmin(e) {
e.preventDefault(); e.preventDefault();
this.props.handleMakeAdmin(this.props.member.id); this.props.handleMakeAdmin(this.props.member.id);
}, }
render: function() { render() {
var member = this.props.member; var member = this.props.member;
var isAdmin = this.props.isAdmin; var isAdmin = this.props.isAdmin;
var isMemberAdmin = member.roles.indexOf("admin") > -1; var isMemberAdmin = member.roles.indexOf('admin') > -1;
var timestamp = UserStore.getCurrentUser().update_at; var timestamp = UserStore.getCurrentUser().update_at;
var invite; var invite;
if (member.invited && this.props.handleInvite) { if (member.invited && this.props.handleInvite) {
invite = <span className="member-role">Added</span>; invite = <span className='member-role'>Added</span>;
} else if (this.props.handleInvite) { } else if (this.props.handleInvite) {
invite = <a onClick={this.handleInvite} className="btn btn-sm btn-primary member-invite"><i className="glyphicon glyphicon-envelope"/> Add</a>;
} else if (isAdmin && !isMemberAdmin && (member.id != UserStore.getCurrentId())) {
var self = this;
invite = ( invite = (
<div className="dropdown member-drop"> <a
<a href="#" className="dropdown-toggle theme" type="button" id="channel_header_dropdown" data-toggle="dropdown" aria-expanded="true"> onClick={this.handleInvite}
<span className="text-capitalize">{member.roles || 'Member'} </span> className='btn btn-sm btn-primary member-invite'>
<span className="caret"></span> <i className='glyphicon glyphicon-envelope'/> Add
</a>
);
} else if (isAdmin && !isMemberAdmin && (member.id !== UserStore.getCurrentId())) {
var self = this;
let makeAdminOption = null;
if (makeAdminOption) {
makeAdminOption = (
<li role='presentation'>
<a
href=''
role='menuitem'
onClick={self.handleMakeAdmin}>Make Admin
</a>
</li>);
}
let handleRemoveOption = null;
if (handleRemoveOption) {
handleRemoveOption = (
<li role='presentation'>
<a
href=''
role='menuitem'
onClick={self.handleRemove}>Remove Member
</a>
</li>);
}
invite = (
<div className='dropdown member-drop'>
<a
href='#'
className='dropdown-toggle theme'
type='button'
id='channel_header_dropdown'
data-toggle='dropdown'
aria-expanded='true' >
<span className='text-capitalize'>{member.roles || 'Member'} </span>
<span className='caret'></span>
</a> </a>
<ul className="dropdown-menu member-menu" role="menu" aria-labelledby="channel_header_dropdown"> <ul
{ this.props.handleMakeAdmin ? className='dropdown-menu member-menu'
<li role="presentation"><a href="" role="menuitem" onClick={self.handleMakeAdmin}>Make Admin</a></li> role='menu'
: null } aria-labelledby='channel_header_dropdown'>
{ this.props.handleRemove ? {makeAdminOption}
<li role="presentation"><a href="" role="menuitem" onClick={self.handleRemove}>Remove Member</a></li> {handleRemoveOption}
: null }
</ul> </ul>
</div> </div>
); );
} else { } else {
invite = <div className="member-role text-capitalize">{member.roles || 'Member'}<span className="caret hidden"></span></div>; invite = <div className='member-role text-capitalize'>{member.roles || 'Member'}<span className='caret hidden'></span></div>;
} }
return ( return (
<div className="row member-div"> <div className='row member-div'>
<img className="post-profile-img pull-left" src={"/api/v1/users/" + member.id + "/image?time=" + timestamp} height="36" width="36" /> <img
<span className="member-name">{member.username}</span> className='post-profile-img pull-left'
<span className="member-email">{member.email}</span> src={'/api/v1/users/' + member.id + '/image?time=' + timestamp}
{ invite } height='36'
width='36' />
<span className='member-name'>{member.username}</span>
<span className='member-email'>{member.email}</span>
{invite}
</div> </div>
); );
} }
}); }
MemberListItem.propTypes = {
handleInvite: React.PropTypes.func,
handleRemove: React.PropTypes.func,
handleMakeAdmin: React.PropTypes.func,
member: React.PropTypes.object,
isAdmin: React.PropTypes.bool
};

Просмотреть файл

@@ -14,54 +14,66 @@ var MAX_HEIGHT_LIST = 292;
var MAX_ITEMS_IN_LIST = 25; var MAX_ITEMS_IN_LIST = 25;
var ITEM_HEIGHT = 36; var ITEM_HEIGHT = 36;
module.exports = React.createClass({ export default class MentionList extends React.Component {
displayName: 'MentionList', constructor(props) {
componentDidMount: function() { super(props);
PostStore.addMentionDataChangeListener(this.onListenerChange);
var self = this;
$('.post-right__scroll').scroll(function(){ this.onListenerChange = this.onListenerChange.bind(this);
if($('.mentions--top').length){ this.handleClick = this.handleClick.bind(this);
$('#reply_mention_tab .mentions--top').css({ bottom: $(window).height() - $('.post-right__scroll #reply_textbox').offset().top }); this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.getSelection = this.getSelection.bind(this);
this.addCurrentMention = this.addCurrentMention.bind(this);
this.addFirstMention = this.addFirstMention.bind(this);
this.isEmpty = this.isEmpty.bind(this);
this.scrollToMention = this.scrollToMention.bind(this);
this.state = {excludeUsers: [], mentionText: '-1', selectedMention: 0, selectedUsername: ''};
}
componentDidMount() {
PostStore.addMentionDataChangeListener(this.onListenerChange);
$('.post-right__scroll').scroll(function onScroll() {
if ($('.mentions--top').length) {
$('#reply_mention_tab .mentions--top').css({bottom: $(window).height() - $('.post-right__scroll #reply_textbox').offset().top});
} }
}); });
$('body').on('keydown.mentionlist', '#' + this.props.id, $('body').on('keydown.mentionlist', '#' + this.props.id,
function(e) { function onMentionListKey(e) {
if (!self.isEmpty() && self.state.mentionText !== '-1' && (e.which === 13 || e.which === 9)) { if (!this.isEmpty() && this.state.mentionText !== '-1' && (e.which === 13 || e.which === 9)) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
self.addCurrentMention(); this.addCurrentMention();
} else if (!self.isEmpty() && self.state.mentionText !== '-1' && (e.which === 38 || e.which === 40)) { } else if (!this.isEmpty() && this.state.mentionText !== '-1' && (e.which === 38 || e.which === 40)) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
if (e.which === 38) { if (e.which === 38) {
if (self.getSelection(self.state.selectedMention - 1)) { if (this.getSelection(this.state.selectedMention - 1)) {
self.setState({selectedMention: self.state.selectedMention - 1, selectedUsername: self.refs['mention' + (self.state.selectedMention - 1)].props.username}); this.setState({selectedMention: this.state.selectedMention - 1, selectedUsername: this.refs['mention' + (this.state.selectedMention - 1)].props.username});
} }
} else if (e.which === 40) { } else if (e.which === 40) {
if (self.getSelection(self.state.selectedMention + 1)) { if (this.getSelection(this.state.selectedMention + 1)) {
self.setState({selectedMention: self.state.selectedMention + 1, selectedUsername: self.refs['mention' + (self.state.selectedMention + 1)].props.username}); this.setState({selectedMention: this.state.selectedMention + 1, selectedUsername: this.refs['mention' + (this.state.selectedMention + 1)].props.username});
} }
} }
self.scrollToMention(e.which); this.scrollToMention(e.which);
} }
} }.bind(this)
); );
$(document).click(function(e) { $(document).click(function onClick(e) {
if (!($('#' + self.props.id).is(e.target) || $('#' + self.props.id).has(e.target).length || if (!($('#' + this.props.id).is(e.target) || $('#' + this.props.id).has(e.target).length ||
('mentionlist' in self.refs && $(self.refs.mentionlist.getDOMNode()).has(e.target).length))) { ('mentionlist' in this.refs && $(React.findDOMNode(this.refs.mentionlist)).has(e.target).length))) {
self.setState({mentionText: '-1'}); this.setState({mentionText: '-1'});
} }
}); }.bind(this));
}, }
componentWillUnmount: function() { componentWillUnmount() {
PostStore.removeMentionDataChangeListener(this.onListenerChange); PostStore.removeMentionDataChangeListener(this.onListenerChange);
$('body').off('keydown.mentionlist', '#' + this.props.id); $('body').off('keydown.mentionlist', '#' + this.props.id);
}, }
componentDidUpdate: function() { componentDidUpdate() {
if (this.state.mentionText !== '-1') { if (this.state.mentionText !== '-1') {
if (this.state.selectedUsername !== '' && (!this.getSelection(this.state.selectedMention) || this.state.selectedUsername !== this.refs['mention' + this.state.selectedMention].props.username)) { if (this.state.selectedUsername !== '' && (!this.getSelection(this.state.selectedMention) || this.state.selectedUsername !== this.refs['mention' + this.state.selectedMention].props.username)) {
var tempSelectedMention = -1; var tempSelectedMention = -1;
@@ -80,8 +92,8 @@ module.exports = React.createClass({
} else if (this.state.selectedMention !== 0) { } else if (this.state.selectedMention !== 0) {
this.setState({selectedMention: 0, selectedUsername: ''}); this.setState({selectedMention: 0, selectedUsername: ''});
} }
}, }
onListenerChange: function(id, mentionText) { onListenerChange(id, mentionText) {
if (id !== this.props.id) { if (id !== this.props.id) {
return; return;
} }
@@ -92,8 +104,8 @@ module.exports = React.createClass({
} }
this.setState(newState); this.setState(newState);
}, }
handleClick: function(name) { handleClick(name) {
AppDispatcher.handleViewAction({ AppDispatcher.handleViewAction({
type: ActionTypes.RECIEVED_ADD_MENTION, type: ActionTypes.RECIEVED_ADD_MENTION,
id: this.props.id, id: this.props.id,
@@ -101,33 +113,33 @@ module.exports = React.createClass({
}); });
this.setState({mentionText: '-1'}); this.setState({mentionText: '-1'});
}, }
handleMouseEnter: function(listId) { handleMouseEnter(listId) {
this.setState({selectedMention: listId, selectedUsername: this.refs['mention' + listId].props.username}); this.setState({selectedMention: listId, selectedUsername: this.refs['mention' + listId].props.username});
}, }
getSelection: function(listId) { getSelection(listId) {
if (!this.refs['mention' + listId]) { if (!this.refs['mention' + listId]) {
return false; return false;
} }
return true; return true;
}, }
addCurrentMention: function() { addCurrentMention() {
if (!this.getSelection(this.state.selectedMention)) { if (!this.getSelection(this.state.selectedMention)) {
this.addFirstMention(); this.addFirstMention();
} else { } else {
this.refs['mention' + this.state.selectedMention].handleClick(); this.refs['mention' + this.state.selectedMention].handleClick();
} }
}, }
addFirstMention: function() { addFirstMention() {
if (!this.refs.mention0) { if (!this.refs.mention0) {
return; return;
} }
this.refs.mention0.handleClick(); this.refs.mention0.handleClick();
}, }
isEmpty: function() { isEmpty() {
return (!this.refs.mention0); return (!this.refs.mention0);
}, }
scrollToMention: function(keyPressed) { scrollToMention(keyPressed) {
var direction; var direction;
if (keyPressed === 38) { if (keyPressed === 38) {
direction = 'up'; direction = 'up';
@@ -145,12 +157,8 @@ module.exports = React.createClass({
$('#mentionsbox').animate({ $('#mentionsbox').animate({
scrollTop: scrollAmount scrollTop: scrollAmount
}, 75); }, 75);
}, }
getInitialState: function() { render() {
return {excludeUsers: [], mentionText: '-1', selectedMention: 0, selectedUsername: ''};
},
render: function() {
var self = this;
var mentionText = this.state.mentionText; var mentionText = this.state.mentionText;
if (mentionText === '-1') { if (mentionText === '-1') {
return null; return null;
@@ -158,8 +166,10 @@ module.exports = React.createClass({
var profiles = UserStore.getActiveOnlyProfiles(); var profiles = UserStore.getActiveOnlyProfiles();
var users = []; var users = [];
for (var id in profiles) { for (let id in profiles) {
users.push(profiles[id]); if (profiles[id]) {
users.push(profiles[id]);
}
} }
var all = {}; var all = {};
@@ -176,7 +186,7 @@ module.exports = React.createClass({
channel.id = 'channelmention'; channel.id = 'channelmention';
users.push(channel); users.push(channel);
users.sort(function(a, b) { users.sort(function sortByUsername(a, b) {
if (a.username < b.username) { if (a.username < b.username) {
return -1; return -1;
} }
@@ -185,29 +195,34 @@ module.exports = React.createClass({
} }
return 0; return 0;
}); });
var mentions = {}; var mentions = [];
var index = 0; var index = 0;
for (var i = 0; i < users.length && index < MAX_ITEMS_IN_LIST; i++) { for (var i = 0; i < users.length && index < MAX_ITEMS_IN_LIST; i++) {
if ((users[i].first_name && users[i].first_name.lastIndexOf(mentionText, 0) === 0) || if ((users[i].first_name && users[i].first_name.lastIndexOf(mentionText, 0) === 0) ||
(users[i].last_name && users[i].last_name.lastIndexOf(mentionText, 0) === 0) || (users[i].last_name && users[i].last_name.lastIndexOf(mentionText, 0) === 0) ||
users[i].username.lastIndexOf(mentionText, 0) === 0) { users[i].username.lastIndexOf(mentionText, 0) === 0) {
let isFocused = '';
if (this.state.selectedMention === index) {
isFocused = 'mentions-focus';
}
mentions[index] = ( mentions[index] = (
<Mention <Mention
key={'mention_key_' + index}
ref={'mention' + index} ref={'mention' + index}
username={users[i].username} username={users[i].username}
secondary_text={Utils.getFullName(users[i])} secondary_text={Utils.getFullName(users[i])}
id={users[i].id} id={users[i].id}
listId={index} listId={index}
isFocused={this.state.selectedMention === index ? 'mentions-focus' : ''} isFocused={isFocused}
handleMouseEnter={function(value) { return function() { self.handleMouseEnter(value); } }(index)} handleMouseEnter={this.handleMouseEnter.bind(this, index)}
handleClick={this.handleClick} /> handleClick={this.handleClick} />
); );
index++; index++;
} }
} }
var numMentions = Object.keys(mentions).length; var numMentions = mentions.length;
if (numMentions < 1) { if (numMentions < 1) {
return null; return null;
@@ -223,11 +238,20 @@ module.exports = React.createClass({
}; };
return ( return (
<div className='mentions--top' style={style}> <div
<div ref='mentionlist' className='mentions-box' id='mentionsbox'> className='mentions--top'
style={style}>
<div
ref='mentionlist'
className='mentions-box'
id='mentionsbox'>
{mentions} {mentions}
</div> </div>
</div> </div>
); );
} }
}); }
MentionList.propTypes = {
id: React.PropTypes.string
};

Просмотреть файл

@@ -5,17 +5,24 @@ var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx'); var client = require('../utils/client.jsx');
var asyncClient = require('../utils/async_client.jsx'); var asyncClient = require('../utils/async_client.jsx');
var UserStore = require('../stores/user_store.jsx'); var UserStore = require('../stores/user_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
module.exports = React.createClass({ export default class NewChannelModal extends React.Component {
displayName: 'NewChannelModal', constructor() {
handleSubmit: function(e) { super();
this.handleSubmit = this.handleSubmit.bind(this);
this.displayNameKeyUp = this.displayNameKeyUp.bind(this);
this.handleClose = this.handleClose.bind(this);
this.state = {channelType: ''};
}
handleSubmit(e) {
e.preventDefault(); e.preventDefault();
var channel = {}; var channel = {};
var state = {serverError: ''}; var state = {serverError: ''};
channel.display_name = this.refs.display_name.getDOMNode().value.trim(); channel.display_name = React.findDOMNode(this.refs.display_name).value.trim();
if (!channel.display_name) { if (!channel.display_name) {
state.displayNameError = 'This field is required'; state.displayNameError = 'This field is required';
state.inValid = true; state.inValid = true;
@@ -26,7 +33,7 @@ module.exports = React.createClass({
state.displayNameError = ''; state.displayNameError = '';
} }
channel.name = this.refs.channel_name.getDOMNode().value.trim(); channel.name = React.findDOMNode(this.refs.channel_name).value.trim();
if (!channel.name) { if (!channel.name) {
state.nameError = 'This field is required'; state.nameError = 'This field is required';
state.inValid = true; state.inValid = true;
@@ -52,54 +59,51 @@ module.exports = React.createClass({
var cu = UserStore.getCurrentUser(); var cu = UserStore.getCurrentUser();
channel.team_id = cu.team_id; channel.team_id = cu.team_id;
channel.description = this.refs.channel_desc.getDOMNode().value.trim(); channel.description = React.findDOMNode(this.refs.channel_desc).value.trim();
channel.type = this.state.channelType; channel.type = this.state.channelType;
client.createChannel(channel, client.createChannel(channel,
function(data) { function success(data) {
$(this.refs.modal.getDOMNode()).modal('hide'); $(React.findDOMNode(this.refs.modal)).modal('hide');
asyncClient.getChannel(data.id); asyncClient.getChannel(data.id);
utils.switchChannel(data); utils.switchChannel(data);
this.refs.display_name.getDOMNode().value = ''; React.findDOMNode(this.refs.display_name).value = '';
this.refs.channel_name.getDOMNode().value = ''; React.findDOMNode(this.refs.channel_name).value = '';
this.refs.channel_desc.getDOMNode().value = ''; React.findDOMNode(this.refs.channel_desc).value = '';
}.bind(this), }.bind(this),
function(err) { function error(err) {
state.serverError = err.message; state.serverError = err.message;
state.inValid = true; state.inValid = true;
this.setState(state); this.setState(state);
}.bind(this) }.bind(this)
); );
}, }
displayNameKeyUp: function() { displayNameKeyUp() {
var displayName = this.refs.display_name.getDOMNode().value.trim(); var displayName = React.findDOMNode(this.refs.display_name).value.trim();
var channelName = utils.cleanUpUrlable(displayName); var channelName = utils.cleanUpUrlable(displayName);
this.refs.channel_name.getDOMNode().value = channelName; React.findDOMNode(this.refs.channel_name).value = channelName;
}, }
componentDidMount: function() { componentDidMount() {
var self = this; var self = this;
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onModalShow(e) {
var button = e.relatedTarget; var button = e.relatedTarget;
self.setState({channelType: $(button).attr('data-channeltype')}); self.setState({channelType: $(button).attr('data-channeltype')});
}); });
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose); $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
}, }
componentWillUnmount: function() { componentWillUnmount() {
$(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose); $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
}, }
handleClose: function() { handleClose() {
$(this.getDOMNode()).find('.form-control').each(function clearForms() { $(React.findDOMNode(this)).find('.form-control').each(function clearForms() {
this.value = ''; this.value = '';
}); });
this.setState({channelType: '', displayNameError: '', nameError: '', serverError: '', inValid: false}); this.setState({channelType: '', displayNameError: '', nameError: '', serverError: '', inValid: false});
}, }
getInitialState: function() { render() {
return {channelType: ''};
},
render: function() {
var displayNameError = null; var displayNameError = null;
var nameError = null; var nameError = null;
var serverError = null; var serverError = null;
@@ -124,11 +128,20 @@ module.exports = React.createClass({
} }
return ( return (
<div className='modal fade' id='new_channel' ref='modal' tabIndex='-1' role='dialog' aria-hidden='true'> <div
className='modal fade'
id='new_channel'
ref='modal'
tabIndex='-1'
role='dialog'
aria-hidden='true'>
<div className='modal-dialog'> <div className='modal-dialog'>
<div className='modal-content'> <div className='modal-content'>
<div className='modal-header'> <div className='modal-header'>
<button type='button' className='close' data-dismiss='modal'> <button
type='button'
className='close'
data-dismiss='modal'>
<span aria-hidden='true'>&times;</span> <span aria-hidden='true'>&times;</span>
<span className='sr-only'>Cancel</span> <span className='sr-only'>Cancel</span>
</button> </button>
@@ -138,23 +151,49 @@ module.exports = React.createClass({
<div className='modal-body'> <div className='modal-body'>
<div className={displayNameClass}> <div className={displayNameClass}>
<label className='control-label'>Display Name</label> <label className='control-label'>Display Name</label>
<input onKeyUp={this.displayNameKeyUp} type='text' ref='display_name' className='form-control' placeholder='Enter display name' maxLength='22' /> <input
onKeyUp={this.displayNameKeyUp}
type='text'
ref='display_name'
className='form-control'
placeholder='Enter display name'
maxLength='22' />
{displayNameError} {displayNameError}
</div> </div>
<div className={nameClass}> <div className={nameClass}>
<label className='control-label'>Handle</label> <label className='control-label'>Handle</label>
<input type='text' className='form-control' ref='channel_name' placeholder="lowercase alphanumeric's only" maxLength='22' /> <input
type='text'
className='form-control'
ref='channel_name'
placeholder="lowercase alphanumeric's only"
maxLength='22' />
{nameError} {nameError}
</div> </div>
<div className='form-group'> <div className='form-group'>
<label className='control-label'>Description</label> <label className='control-label'>Description</label>
<textarea className='form-control no-resize' ref='channel_desc' rows='3' placeholder='Description' maxLength='1024'></textarea> <textarea
className='form-control no-resize'
ref='channel_desc'
rows='3'
placeholder='Description'
maxLength='1024' />
</div> </div>
{serverError} {serverError}
</div> </div>
<div className='modal-footer'> <div className='modal-footer'>
<button type='button' className='btn btn-default' data-dismiss='modal'>Cancel</button> <button
<button onClick={this.handleSubmit} type='submit' className='btn btn-primary'>Create New {channelTerm}</button> type='button'
className='btn btn-default'
data-dismiss='modal' >
Cancel
</button>
<button
onClick={this.handleSubmit}
type='submit'
className='btn btn-primary' >
Create New {channelTerm}
</button>
</div> </div>
</form> </form>
</div> </div>
@@ -162,4 +201,4 @@ module.exports = React.createClass({
</div> </div>
); );
} }
}); }

Просмотреть файл

@@ -15,9 +15,17 @@ var utils = require('../utils/utils.jsx');
var PostInfo = require('./post_info.jsx'); var PostInfo = require('./post_info.jsx');
module.exports = React.createClass({ export default class Post extends React.Component {
displayName: 'Post', constructor(props) {
handleCommentClick: function(e) { super(props);
this.handleCommentClick = this.handleCommentClick.bind(this);
this.forceUpdateInfo = this.forceUpdateInfo.bind(this);
this.retryPost = this.retryPost.bind(this);
this.state = {};
}
handleCommentClick(e) {
e.preventDefault(); e.preventDefault();
var data = {}; var data = {};
@@ -33,31 +41,31 @@ module.exports = React.createClass({
type: ActionTypes.RECIEVED_SEARCH, type: ActionTypes.RECIEVED_SEARCH,
results: null results: null
}); });
}, }
forceUpdateInfo: function() { forceUpdateInfo() {
this.refs.info.forceUpdate(); this.refs.info.forceUpdate();
this.refs.header.forceUpdate(); this.refs.header.forceUpdate();
}, }
retryPost: function(e) { retryPost(e) {
e.preventDefault(); e.preventDefault();
var post = this.props.post; var post = this.props.post;
client.createPost(post, post.channel_id, client.createPost(post, post.channel_id,
function(data) { function success(data) {
AsyncClient.getPosts(); AsyncClient.getPosts();
var channel = ChannelStore.get(post.channel_id); var channel = ChannelStore.get(post.channel_id);
var member = ChannelStore.getMember(post.channel_id); var member = ChannelStore.getMember(post.channel_id);
member.msg_count = channel.total_msg_count; member.msg_count = channel.total_msg_count;
member.last_viewed_at = (new Date).getTime(); member.last_viewed_at = utils.getTimestamp();
ChannelStore.setChannelMember(member); ChannelStore.setChannelMember(member);
AppDispatcher.handleServerAction({ AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_POST, type: ActionTypes.RECIEVED_POST,
post: data post: data
}); });
}.bind(this), },
function(err) { function error() {
post.state = Constants.POST_FAILED; post.state = Constants.POST_FAILED;
PostStore.updatePendingPost(post); PostStore.updatePendingPost(post);
this.forceUpdate(); this.forceUpdate();
@@ -67,18 +75,15 @@ module.exports = React.createClass({
post.state = Constants.POST_LOADING; post.state = Constants.POST_LOADING;
PostStore.updatePendingPost(post); PostStore.updatePendingPost(post);
this.forceUpdate(); this.forceUpdate();
}, }
shouldComponentUpdate: function(nextProps) { shouldComponentUpdate(nextProps) {
if (!utils.areStatesEqual(nextProps.post, this.props.post)) { if (!utils.areStatesEqual(nextProps.post, this.props.post)) {
return true; return true;
} }
return false; return false;
}, }
getInitialState: function() { render() {
return { };
},
render: function() {
var post = this.props.post; var post = this.props.post;
var parentPost = this.props.parentPost; var parentPost = this.props.parentPost;
var posts = this.props.posts; var posts = this.props.posts;
@@ -89,19 +94,27 @@ module.exports = React.createClass({
} }
var commentCount = 0; var commentCount = 0;
var commentRootId = parentPost ? post.root_id : post.id; var commentRootId;
if (parentPost) {
commentRootId = post.root_id;
} else {
commentRootId = post.id;
}
for (var postId in posts) { for (var postId in posts) {
if (posts[postId].root_id == commentRootId) { if (posts[postId].root_id === commentRootId) {
commentCount += 1; commentCount += 1;
} }
} }
var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null; var rootUser;
if (this.props.sameRoot) {
var rootUser = this.props.sameRoot ? 'same--root' : 'other--root'; rootUser = 'same--root';
} else {
rootUser = 'other--root';
}
var postType = ''; var postType = '';
if (type != 'Post'){ if (type !== 'Post') {
postType = 'post--comment'; postType = 'post--comment';
} }
@@ -122,21 +135,60 @@ module.exports = React.createClass({
sameUserClass = 'same--user'; sameUserClass = 'same--user';
} }
var profilePic = null;
if (this.props.hideProfilePic) {
profilePic = (
<div className='post-profile-img__container'>
<img
className='post-profile-img'
src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp}
height='36'
width='36' />
</div>
);
}
return ( return (
<div> <div>
<div id={post.id} className={'post ' + sameUserClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss}> <div
{ !this.props.hideProfilePic ? id={post.id}
<div className='post-profile-img__container'> className={'post ' + sameUserClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss} >
<img className='post-profile-img' src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp} height='36' width='36' /> {profilePic}
</div>
: null }
<div className='post__content'> <div className='post__content'>
<PostHeader ref='header' post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} isLastComment={this.props.isLastComment} /> <PostHeader
<PostBody post={post} sameRoot={this.props.sameRoot} parentPost={parentPost} posts={posts} handleCommentClick={this.handleCommentClick} retryPost={this.retryPost} /> ref='header'
<PostInfo ref='info' post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} allowReply='true' /> post={post}
sameRoot={this.props.sameRoot}
commentCount={commentCount}
handleCommentClick={this.handleCommentClick}
isLastComment={this.props.isLastComment} />
<PostBody
post={post}
sameRoot={this.props.sameRoot}
parentPost={parentPost}
posts={posts}
handleCommentClick={this.handleCommentClick}
retryPost={this.retryPost} />
<PostInfo
ref='info'
post={post}
sameRoot={this.props.sameRoot}
commentCount={commentCount}
handleCommentClick={this.handleCommentClick}
allowReply='true' />
</div> </div>
</div> </div>
</div> </div>
); );
} }
}); }
Post.propTypes = {
post: React.PropTypes.object,
posts: React.PropTypes.object,
parentPost: React.PropTypes.object,
sameUser: React.PropTypes.bool,
sameRoot: React.PropTypes.bool,
hideProfilePic: React.PropTypes.bool,
isLastComment: React.PropTypes.bool
};

Просмотреть файл

@@ -1,7 +1,6 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
var client = require('../utils/client.jsx'); var client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx'); var AsyncClient = require('../utils/async_client.jsx');
var PostStore = require('../stores/post_store.jsx'); var PostStore = require('../stores/post_store.jsx');
@@ -10,36 +9,47 @@ var utils = require('../utils/utils.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
function getSearchTermStateFromStores() { export default class SearchBar extends React.Component {
var term = PostStore.getSearchTerm() || ''; constructor() {
return { super();
search_term: term this.mounted = false;
};
}
module.exports = React.createClass({ this.onListenerChange = this.onListenerChange.bind(this);
displayName: 'SearchBar', this.handleUserInput = this.handleUserInput.bind(this);
componentDidMount: function() { this.performSearch = this.performSearch.bind(this);
PostStore.addSearchTermChangeListener(this._onChange); this.handleSubmit = this.handleSubmit.bind(this);
},
componentWillUnmount: function() { this.state = this.getSearchTermStateFromStores();
PostStore.removeSearchTermChangeListener(this._onChange); }
}, getSearchTermStateFromStores() {
_onChange: function(doSearch, isMentionSearch) { var term = PostStore.getSearchTerm() || '';
if (this.isMounted()) { return {
var newState = getSearchTermStateFromStores(); searchTerm: term
};
}
componentDidMount() {
PostStore.addSearchTermChangeListener(this.onListenerChange);
this.mounted = true;
}
componentWillUnmount() {
PostStore.removeSearchTermChangeListener(this.onListenerChange);
this.mounted = false;
}
onListenerChange(doSearch, isMentionSearch) {
if (this.mounted) {
var newState = this.getSearchTermStateFromStores();
if (!utils.areStatesEqual(newState, this.state)) { if (!utils.areStatesEqual(newState, this.state)) {
this.setState(newState); this.setState(newState);
} }
if (doSearch) { if (doSearch) {
this.performSearch(newState.search_term, isMentionSearch); this.performSearch(newState.searchTerm, isMentionSearch);
} }
} }
}, }
clearFocus: function(e) { clearFocus() {
$('.search-bar__container').removeClass('focused'); $('.search-bar__container').removeClass('focused');
}, }
handleClose: function(e) { handleClose(e) {
e.preventDefault(); e.preventDefault();
AppDispatcher.handleServerAction({ AppDispatcher.handleServerAction({
@@ -58,23 +68,23 @@ module.exports = React.createClass({
type: ActionTypes.RECIEVED_POST_SELECTED, type: ActionTypes.RECIEVED_POST_SELECTED,
results: null results: null
}); });
}, }
handleUserInput: function(e) { handleUserInput(e) {
var term = e.target.value; var term = e.target.value;
PostStore.storeSearchTerm(term); PostStore.storeSearchTerm(term);
PostStore.emitSearchTermChange(false); PostStore.emitSearchTermChange(false);
this.setState({ search_term: term }); this.setState({searchTerm: term});
}, }
handleUserFocus: function(e) { handleUserFocus(e) {
e.target.select(); e.target.select();
$('.search-bar__container').addClass('focused'); $('.search-bar__container').addClass('focused');
}, }
performSearch: function(terms, isMentionSearch) { performSearch(terms, isMentionSearch) {
if (terms.length) { if (terms.length) {
this.setState({isSearching: true}); this.setState({isSearching: true});
client.search( client.search(
terms, terms,
function(data) { function success(data) {
this.setState({isSearching: false}); this.setState({isSearching: false});
if (utils.isMobile()) { if (utils.isMobile()) {
React.findDOMNode(this.refs.search).value = ''; React.findDOMNode(this.refs.search).value = '';
@@ -86,38 +96,50 @@ module.exports = React.createClass({
is_mention_search: isMentionSearch is_mention_search: isMentionSearch
}); });
}.bind(this), }.bind(this),
function(err) { function error(err) {
this.setState({isSearching: false}); this.setState({isSearching: false});
AsyncClient.dispatchError(err, "search"); AsyncClient.dispatchError(err, 'search');
}.bind(this) }.bind(this)
); );
} }
}, }
handleSubmit: function(e) { handleSubmit(e) {
e.preventDefault(); e.preventDefault();
this.performSearch(this.state.search_term.trim()); this.performSearch(this.state.searchTerm.trim());
}, }
getInitialState: function() { render() {
return getSearchTermStateFromStores(); var isSearching = null;
}, if (this.state.isSearching) {
render: function() { isSearching = <span className={'glyphicon glyphicon-refresh glyphicon-refresh-animate'}></span>;
}
return ( return (
<div> <div>
<div className="sidebar__collapse" onClick={this.handleClose}><span className="fa fa-angle-left"></span></div> <div
<span onClick={this.clearFocus} className="search__clear">Cancel</span> className='sidebar__collapse'
<form role="form" className="search__form relative-div" onSubmit={this.handleSubmit}> onClick={this.handleClose} >
<span className="glyphicon glyphicon-search sidebar__search-icon"></span> <span className='fa fa-angle-left'></span>
</div>
<span
className='search__clear'
onClick={this.clearFocus}>
Cancel
</span>
<form
role='form'
className='search__form relative-div'
onSubmit={this.handleSubmit}>
<span className='glyphicon glyphicon-search sidebar__search-icon'></span>
<input <input
type="text" type='text'
ref="search" ref='search'
className="form-control search-bar" className='form-control search-bar'
placeholder="Search" placeholder='Search'
value={this.state.search_term} value={this.state.searchTerm}
onFocus={this.handleUserFocus} onFocus={this.handleUserFocus}
onChange={this.handleUserInput} /> onChange={this.handleUserInput} />
{this.state.isSearching ? <span className={"glyphicon glyphicon-refresh glyphicon-refresh-animate"}></span> : null} {isSearching}
</form> </form>
</div> </div>
); );
} }
}); }

Просмотреть файл

@@ -1,33 +1,68 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
module.exports = React.createClass({ export default class SettingItemMax extends React.Component {
render: function() { render() {
var clientError = this.props.client_error ? <div className='form-group'><label className='col-sm-12 has-error'>{ this.props.client_error }</label></div> : null; var clientError = null;
var server_error = this.props.server_error ? <div className='form-group'><label className='col-sm-12 has-error'>{ this.props.server_error }</label></div> : null; if (this.props.client_error) {
var extraInfo = this.props.extraInfo ? this.props.extraInfo : null; clientError = (<div className='form-group'><label className='col-sm-12 has-error'>{this.props.client_error}</label></div>);
}
var serverError = null;
if (this.props.server_error) {
serverError = (<div className='form-group'><label className='col-sm-12 has-error'>{this.props.server_error}</label></div>);
}
var extraInfo = null;
if (this.props.extraInfo) {
extraInfo = this.props.extraInfo;
}
var submit = '';
if (this.props.submit) {
submit = (<a
className='btn btn-sm btn-primary'
href='#'
onClick={this.props.submit}>
Submit</a>);
}
var inputs = this.props.inputs; var inputs = this.props.inputs;
return ( return (
<ul className="section-max form-horizontal"> <ul className='section-max form-horizontal'>
<li className="col-sm-12 section-title">{this.props.title}</li> <li className='col-sm-12 section-title'>{this.props.title}</li>
<li className="col-sm-9 col-sm-offset-3"> <li className='col-sm-9 col-sm-offset-3'>
<ul className="setting-list"> <ul className='setting-list'>
<li className="setting-list-item"> <li className='setting-list-item'>
{inputs} {inputs}
{extraInfo} {extraInfo}
</li> </li>
<li className="setting-list-item"> <li className='setting-list-item'>
<hr /> <hr />
{ server_error } {serverError}
{ clientError } {clientError}
{ this.props.submit ? <a className="btn btn-sm btn-primary" href="#" onClick={this.props.submit}>Submit</a> : "" } {submit}
<a className="btn btn-sm theme" href="#" onClick={this.props.updateSection}>Cancel</a> <a
className='btn btn-sm theme'
href='#'
onClick={this.props.updateSection} >
Cancel
</a>
</li> </li>
</ul> </ul>
</li> </li>
</ul> </ul>
); );
} }
}); }
SettingItemMax.propTypes = {
inputs: React.PropTypes.array,
client_error: React.PropTypes.string,
server_error: React.PropTypes.string,
extraInfo: React.PropTypes.element,
updateSection: React.PropTypes.func,
submit: React.PropTypes.func,
title: React.PropTypes.string
};

Просмотреть файл

@@ -4,21 +4,24 @@
var utils = require('../utils/utils.jsx'); var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx'); var client = require('../utils/client.jsx');
module.exports = React.createClass({ export default class TeamSignupDisplayNamePage extends React.Component {
displayName: 'TeamSignupDisplayNamePage', constructor(props) {
propTypes: { super(props);
state: React.PropTypes.object,
updateParent: React.PropTypes.func this.submitBack = this.submitBack.bind(this);
}, this.submitNext = this.submitNext.bind(this);
submitBack: function(e) {
this.state = {};
}
submitBack(e) {
e.preventDefault(); e.preventDefault();
this.props.state.wizard = 'welcome'; this.props.state.wizard = 'welcome';
this.props.updateParent(this.props.state); this.props.updateParent(this.props.state);
}, }
submitNext: function(e) { submitNext(e) {
e.preventDefault(); e.preventDefault();
var displayName = this.refs.name.getDOMNode().value.trim(); var displayName = React.findDOMNode(this.refs.name).value.trim();
if (!displayName) { if (!displayName) {
this.setState({nameError: 'This field is required'}); this.setState({nameError: 'This field is required'});
return; return;
@@ -28,15 +31,12 @@ module.exports = React.createClass({
this.props.state.team.display_name = displayName; this.props.state.team.display_name = displayName;
this.props.state.team.name = utils.cleanUpUrlable(displayName); this.props.state.team.name = utils.cleanUpUrlable(displayName);
this.props.updateParent(this.props.state); this.props.updateParent(this.props.state);
}, }
getInitialState: function() { handleFocus(e) {
return {};
},
handleFocus: function(e) {
e.preventDefault(); e.preventDefault();
e.currentTarget.select(); e.currentTarget.select();
}, }
render: function() { render() {
client.track('signup', 'signup_team_02_name'); client.track('signup', 'signup_team_02_name');
var nameError = null; var nameError = null;
@@ -49,24 +49,48 @@ module.exports = React.createClass({
return ( return (
<div> <div>
<form> <form>
<img className='signup-team-logo' src='/static/images/logo.png' /> <img
className='signup-team-logo'
src='/static/images/logo.png' />
<h2>{utils.toTitleCase(strings.Team) + ' Name'}</h2> <h2>{utils.toTitleCase(strings.Team) + ' Name'}</h2>
<div className={nameDivClass}> <div className={nameDivClass}>
<div className='row'> <div className='row'>
<div className='col-sm-9'> <div className='col-sm-9'>
<input type='text' ref='name' className='form-control' placeholder='' maxLength='128' defaultValue={this.props.state.team.display_name} autoFocus={true} onFocus={this.handleFocus} /> <input
type='text'
ref='name'
className='form-control'
placeholder=''
maxLength='128'
defaultValue={this.props.state.team.display_name}
autoFocus={true}
onFocus={this.handleFocus} />
</div> </div>
</div> </div>
{nameError} {nameError}
</div> </div>
<div>{'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}</div> <div>{'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}</div>
<button type='submit' className='btn btn-primary margin--extra' onClick={this.submitNext}>Next<i className='glyphicon glyphicon-chevron-right'></i></button> <button
type='submit'
className='btn btn-primary margin--extra'
onClick={this.submitNext} >
Next<i className='glyphicon glyphicon-chevron-right'></i>
</button>
<div className='margin--extra'> <div className='margin--extra'>
<a href='#' onClick={this.submitBack}>Back to previous step</a> <a
href='#'
onClick={this.submitBack}>
Back to previous step
</a>
</div> </div>
</form> </form>
</div> </div>
); );
} }
}); }
TeamSignupDisplayNamePage.propTypes = {
state: React.PropTypes.object,
updateParent: React.PropTypes.func
};

Просмотреть файл

@@ -194,7 +194,7 @@ export default class UserSettingsGeneralTab extends React.Component {
this.props.updateSection(section); this.props.updateSection(section);
} }
handleClose() { handleClose() {
$(this.getDOMNode()).find('.form-control').each(function clearForms() { $(React.findDOMNode(this)).find('.form-control').each(function clearForms() {
this.value = ''; this.value = '';
}); });
@@ -230,7 +230,6 @@ export default class UserSettingsGeneralTab extends React.Component {
} }
var nameSection; var nameSection;
var self = this;
var inputs = []; var inputs = [];
if (this.props.activeSection === 'name') { if (this.props.activeSection === 'name') {
@@ -276,9 +275,9 @@ export default class UserSettingsGeneralTab extends React.Component {
server_error={serverError} server_error={serverError}
client_error={clientError} client_error={clientError}
updateSection={function clearSection(e) { updateSection={function clearSection(e) {
self.updateSection(''); this.updateSection('');
e.preventDefault(); e.preventDefault();
}} }.bind(this)}
/> />
); );
} else { } else {
@@ -297,8 +296,8 @@ export default class UserSettingsGeneralTab extends React.Component {
title='Full Name' title='Full Name'
describe={fullName} describe={fullName}
updateSection={function updateNameSection() { updateSection={function updateNameSection() {
self.updateSection('name'); this.updateSection('name');
}} }.bind(this)}
/> />
); );
} }
@@ -335,9 +334,9 @@ export default class UserSettingsGeneralTab extends React.Component {
server_error={serverError} server_error={serverError}
client_error={clientError} client_error={clientError}
updateSection={function clearSection(e) { updateSection={function clearSection(e) {
self.updateSection(''); this.updateSection('');
e.preventDefault(); e.preventDefault();
}} }.bind(this)}
/> />
); );
} else { } else {
@@ -346,8 +345,8 @@ export default class UserSettingsGeneralTab extends React.Component {
title='Nickname' title='Nickname'
describe={UserStore.getCurrentUser().nickname} describe={UserStore.getCurrentUser().nickname}
updateSection={function updateNicknameSection() { updateSection={function updateNicknameSection() {
self.updateSection('nickname'); this.updateSection('nickname');
}} }.bind(this)}
/> />
); );
} }
@@ -384,9 +383,9 @@ export default class UserSettingsGeneralTab extends React.Component {
server_error={serverError} server_error={serverError}
client_error={clientError} client_error={clientError}
updateSection={function clearSection(e) { updateSection={function clearSection(e) {
self.updateSection(''); this.updateSection('');
e.preventDefault(); e.preventDefault();
}} }.bind(this)}
/> />
); );
} else { } else {
@@ -395,8 +394,8 @@ export default class UserSettingsGeneralTab extends React.Component {
title='Username' title='Username'
describe={UserStore.getCurrentUser().username} describe={UserStore.getCurrentUser().username}
updateSection={function updateUsernameSection() { updateSection={function updateUsernameSection() {
self.updateSection('username'); this.updateSection('username');
}} }.bind(this)}
/> />
); );
} }
@@ -433,9 +432,9 @@ export default class UserSettingsGeneralTab extends React.Component {
server_error={serverError} server_error={serverError}
client_error={emailError} client_error={emailError}
updateSection={function clearSection(e) { updateSection={function clearSection(e) {
self.updateSection(''); this.updateSection('');
e.preventDefault(); e.preventDefault();
}} }.bind(this)}
/> />
); );
} else { } else {
@@ -444,8 +443,8 @@ export default class UserSettingsGeneralTab extends React.Component {
title='Email' title='Email'
describe={UserStore.getCurrentUser().email} describe={UserStore.getCurrentUser().email}
updateSection={function updateEmailSection() { updateSection={function updateEmailSection() {
self.updateSection('email'); this.updateSection('email');
}} }.bind(this)}
/> />
); );
} }
@@ -460,9 +459,9 @@ export default class UserSettingsGeneralTab extends React.Component {
server_error={serverError} server_error={serverError}
client_error={clientError} client_error={clientError}
updateSection={function clearSection(e) { updateSection={function clearSection(e) {
self.updateSection(''); this.updateSection('');
e.preventDefault(); e.preventDefault();
}} }.bind(this)}
picture={this.state.picture} picture={this.state.picture}
pictureChange={this.updatePicture} pictureChange={this.updatePicture}
submitActive={this.submitActive} submitActive={this.submitActive}
@@ -479,8 +478,8 @@ export default class UserSettingsGeneralTab extends React.Component {
title='Profile Picture' title='Profile Picture'
describe={minMessage} describe={minMessage}
updateSection={function updatePictureSection() { updateSection={function updatePictureSection() {
self.updateSection('picture'); this.updateSection('picture');
}} }.bind(this)}
/> />
); );
} }

Просмотреть файл

@@ -26,13 +26,13 @@ var ChannelMembersModal = require('../components/channel_members.jsx');
var ChannelInviteModal = require('../components/channel_invite_modal.jsx'); var ChannelInviteModal = require('../components/channel_invite_modal.jsx');
var TeamMembersModal = require('../components/team_members.jsx'); var TeamMembersModal = require('../components/team_members.jsx');
var DirectChannelModal = require('../components/more_direct_channels.jsx'); var DirectChannelModal = require('../components/more_direct_channels.jsx');
var ErrorBar = require('../components/error_bar.jsx') var ErrorBar = require('../components/error_bar.jsx');
var ChannelLoader = require('../components/channel_loader.jsx'); var ChannelLoader = require('../components/channel_loader.jsx');
var MentionList = require('../components/mention_list.jsx'); var MentionList = require('../components/mention_list.jsx');
var ChannelInfoModal = require('../components/channel_info_modal.jsx'); var ChannelInfoModal = require('../components/channel_info_modal.jsx');
var AccessHistoryModal = require('../components/access_history_modal.jsx'); var AccessHistoryModal = require('../components/access_history_modal.jsx');
var ActivityLogModal = require('../components/activity_log_modal.jsx'); var ActivityLogModal = require('../components/activity_log_modal.jsx');
var RemovedFromChannelModal = require('../components/removed_from_channel_modal.jsx') var RemovedFromChannelModal = require('../components/removed_from_channel_modal.jsx');
var FileUploadOverlay = require('../components/file_upload_overlay.jsx'); var FileUploadOverlay = require('../components/file_upload_overlay.jsx');
var AsyncClient = require('../utils/async_client.jsx'); var AsyncClient = require('../utils/async_client.jsx');
@@ -40,18 +40,18 @@ var AsyncClient = require('../utils/async_client.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
global.window.setup_channel_page = function(team_name, team_type, team_id, channel_name, channel_id) { function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
AsyncClient.getConfig(); AsyncClient.getConfig();
AppDispatcher.handleViewAction({ AppDispatcher.handleViewAction({
type: ActionTypes.CLICK_CHANNEL, type: ActionTypes.CLICK_CHANNEL,
name: channel_name, name: channelName,
id: channel_id id: channelId
}); });
AppDispatcher.handleViewAction({ AppDispatcher.handleViewAction({
type: ActionTypes.CLICK_TEAM, type: ActionTypes.CLICK_TEAM,
id: team_id id: teamId
}); });
// ChannelLoader must be rendered first // ChannelLoader must be rendered first
@@ -66,12 +66,14 @@ global.window.setup_channel_page = function(team_name, team_type, team_id, chann
); );
React.render( React.render(
<Navbar teamDisplayName={team_name} />, <Navbar teamDisplayName={teamName} />,
document.getElementById('navbar') document.getElementById('navbar')
); );
React.render( React.render(
<Sidebar teamDisplayName={team_name} teamType={team_type} />, <Sidebar
teamDisplayName={teamName}
teamType={teamType} />,
document.getElementById('sidebar-left') document.getElementById('sidebar-left')
); );
@@ -86,17 +88,17 @@ global.window.setup_channel_page = function(team_name, team_type, team_id, chann
); );
React.render( React.render(
<TeamSettingsModal teamDisplayName={team_name} />, <TeamSettingsModal teamDisplayName={teamName} />,
document.getElementById('team_settings_modal') document.getElementById('team_settings_modal')
); );
React.render( React.render(
<TeamMembersModal teamDisplayName={team_name} />, <TeamMembersModal teamDisplayName={teamName} />,
document.getElementById('team_members_modal') document.getElementById('team_members_modal')
); );
React.render( React.render(
<MemberInviteModal teamType={team_type} />, <MemberInviteModal teamType={teamType} />,
document.getElementById('invite_member_modal') document.getElementById('invite_member_modal')
); );
@@ -186,7 +188,9 @@ global.window.setup_channel_page = function(team_name, team_type, team_id, chann
); );
React.render( React.render(
<SidebarRightMenu teamDisplayName={team_name} teamType={team_type} />, <SidebarRightMenu
teamDisplayName={teamName}
teamType={teamType} />,
document.getElementById('sidebar-menu') document.getElementById('sidebar-menu')
); );
@@ -225,5 +229,6 @@ global.window.setup_channel_page = function(team_name, team_type, team_id, chann
overlayType='center' />, overlayType='center' />,
document.getElementById('file_upload_overlay') document.getElementById('file_upload_overlay')
); );
}
}; global.window.setup_channel_page = setupChannelPage;

Просмотреть файл

@@ -3,11 +3,11 @@
var FindTeam = require('../components/find_team.jsx'); var FindTeam = require('../components/find_team.jsx');
global.window.setup_find_team_page = function() { function setupFindTeamPage() {
React.render( React.render(
<FindTeam />, <FindTeam />,
document.getElementById('find-team') document.getElementById('find-team')
); );
}
}; global.window.setup_find_team_page = setupFindTeamPage;

Просмотреть файл

@@ -2,14 +2,15 @@
// See License.txt for license information. // See License.txt for license information.
var ChannelStore = require('../stores/channel_store.jsx'); var ChannelStore = require('../stores/channel_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
global.window.setup_home_page = function(teamURL) { function setupHomePage(teamURL) {
var last = ChannelStore.getLastVisitedName(); var last = ChannelStore.getLastVisitedName();
if (last == null || last.length === 0) { if (last == null || last.length === 0) {
window.location = teamURL + "/channels/" + Constants.DEFAULT_CHANNEL; window.location = teamURL + '/channels/' + Constants.DEFAULT_CHANNEL;
} else { } else {
window.location = teamURL + "/channels/" + last; window.location = teamURL + '/channels/' + last;
} }
} }
global.window.setup_home_page = setupHomePage;

Просмотреть файл

@@ -3,9 +3,14 @@
var Login = require('../components/login.jsx'); var Login = require('../components/login.jsx');
global.window.setup_login_page = function(team_display_name, team_name, auth_services) { function setupLoginPage(teamDisplayName, teamName, authServices) {
React.render( React.render(
<Login teamDisplayName={team_display_name} teamName={team_name} authServices={auth_services} />, <Login
teamDisplayName={teamDisplayName}
teamName={teamName}
authServices={authServices} />,
document.getElementById('login') document.getElementById('login')
); );
}; }
global.window.setup_login_page = setupLoginPage;

Просмотреть файл

@@ -3,17 +3,17 @@
var PasswordReset = require('../components/password_reset.jsx'); var PasswordReset = require('../components/password_reset.jsx');
global.window.setup_password_reset_page = function(is_reset, team_display_name, team_name, hash, data) { function setupPasswordResetPage(isReset, teamDisplayName, teamName, hash, data) {
React.render( React.render(
<PasswordReset <PasswordReset
isReset={is_reset} isReset={isReset}
teamDisplayName={team_display_name} teamDisplayName={teamDisplayName}
teamName={team_name} teamName={teamName}
hash={hash} hash={hash}
data={data} data={data}
/>, />,
document.getElementById('reset') document.getElementById('reset')
); );
}
}; global.window.setup_password_reset_page = setupPasswordResetPage;

Просмотреть файл

@@ -5,7 +5,7 @@ var SignupTeam = require('../components/signup_team.jsx');
var AsyncClient = require('../utils/async_client.jsx'); var AsyncClient = require('../utils/async_client.jsx');
global.window.setup_signup_team_page = function(authServices) { function setupSignupTeamPage(authServices) {
AsyncClient.getConfig(); AsyncClient.getConfig();
var services = JSON.parse(authServices); var services = JSON.parse(authServices);
@@ -14,4 +14,6 @@ global.window.setup_signup_team_page = function(authServices) {
<SignupTeam services={services} />, <SignupTeam services={services} />,
document.getElementById('signup-team') document.getElementById('signup-team')
); );
}; }
global.window.setup_signup_team_page = setupSignupTeamPage;

Просмотреть файл

@@ -1,11 +1,16 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
var SignupTeamComplete =require('../components/signup_team_complete.jsx'); var SignupTeamComplete = require('../components/signup_team_complete.jsx');
global.window.setup_signup_team_complete_page = function(email, data, hash) { function setupSignupTeamCompletePage(email, data, hash) {
React.render( React.render(
<SignupTeamComplete email={email} hash={hash} data={data}/>, <SignupTeamComplete
email={email}
hash={hash}
data={data}/>,
document.getElementById('signup-team-complete') document.getElementById('signup-team-complete')
); );
}; }
global.window.setup_signup_team_complete_page = setupSignupTeamCompletePage;

Просмотреть файл

@@ -3,9 +3,18 @@
var SignupUserComplete = require('../components/signup_user_complete.jsx'); var SignupUserComplete = require('../components/signup_user_complete.jsx');
global.window.setup_signup_user_complete_page = function(email, name, ui_name, id, data, hash, auth_services) { function setupSignupUserCompletePage(email, name, uiName, id, data, hash, authServices) {
React.render( React.render(
<SignupUserComplete teamId={id} teamName={name} teamDisplayName={ui_name} email={email} hash={hash} data={data} authServices={auth_services} />, <SignupUserComplete
teamId={id}
teamName={name}
teamDisplayName={uiName}
email={email}
hash={hash}
data={data}
authServices={authServices} />,
document.getElementById('signup-user-complete') document.getElementById('signup-user-complete')
); );
}; }
global.window.setup_signup_user_complete_page = setupSignupUserCompletePage;

Просмотреть файл

@@ -5,7 +5,10 @@ var EmailVerify = require('../components/email_verify.jsx');
global.window.setupVerifyPage = function setupVerifyPage(isVerified, teamURL, userEmail) { global.window.setupVerifyPage = function setupVerifyPage(isVerified, teamURL, userEmail) {
React.render( React.render(
<EmailVerify isVerified={isVerified} teamURL={teamURL} userEmail={userEmail} />, <EmailVerify
isVerified={isVerified}
teamURL={teamURL}
userEmail={userEmail} />,
document.getElementById('verify') document.getElementById('verify')
); );
}; };

Просмотреть файл

@@ -12,81 +12,70 @@ function getPrefix() {
// Also change model/utils.go ETAG_ROOT_VERSION // Also change model/utils.go ETAG_ROOT_VERSION
var BROWSER_STORE_VERSION = '.5'; var BROWSER_STORE_VERSION = '.5';
module.exports = { class BrowserStoreClass {
initialized: false, constructor() {
this.getItem = this.getItem.bind(this);
this.setItem = this.setItem.bind(this);
this.removeItem = this.removeItem.bind(this);
this.setGlobalItem = this.setGlobalItem.bind(this);
this.getGlobalItem = this.getGlobalItem.bind(this);
this.removeGlobalItem = this.removeGlobalItem.bind(this);
this.clear = this.clear.bind(this);
this.actionOnItemsWithPrefix = this.actionOnItemsWithPrefix.bind(this);
this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this);
initialize: function() {
var currentVersion = localStorage.getItem('local_storage_version'); var currentVersion = localStorage.getItem('local_storage_version');
if (currentVersion !== BROWSER_STORE_VERSION) { if (currentVersion !== BROWSER_STORE_VERSION) {
this.clear(); this.clear();
localStorage.setItem('local_storage_version', BROWSER_STORE_VERSION); localStorage.setItem('local_storage_version', BROWSER_STORE_VERSION);
} }
this.initialized = true; }
},
getItem: function(name, defaultValue) { getItem(name, defaultValue) {
return this.getGlobalItem(getPrefix() + name, defaultValue); return this.getGlobalItem(getPrefix() + name, defaultValue);
}, }
setItem: function(name, value) { setItem(name, value) {
this.setGlobalItem(getPrefix() + name, value); this.setGlobalItem(getPrefix() + name, value);
}, }
removeItem: function(name) {
if (!this.initialized) {
this.initialize();
}
removeItem(name) {
localStorage.removeItem(getPrefix() + name); localStorage.removeItem(getPrefix() + name);
}, }
setGlobalItem: function(name, value) {
if (!this.initialized) {
this.initialize();
}
setGlobalItem(name, value) {
localStorage.setItem(name, JSON.stringify(value)); localStorage.setItem(name, JSON.stringify(value));
}, }
getGlobalItem: function(name, defaultValue) {
if (!this.initialized) {
this.initialize();
}
getGlobalItem(name, defaultValue) {
var result = null; var result = null;
try { try {
result = JSON.parse(localStorage.getItem(name)); result = JSON.parse(localStorage.getItem(name));
} catch (err) {} } catch (err) {
result = null;
}
if (result === null && typeof defaultValue !== 'undefined') { if (result === null && typeof defaultValue !== 'undefined') {
result = defaultValue; result = defaultValue;
} }
return result; return result;
}, }
removeGlobalItem: function(name) {
if (!this.initialized) {
this.initialize();
}
removeGlobalItem(name) {
localStorage.removeItem(name); localStorage.removeItem(name);
}, }
clear: function() { clear() {
localStorage.clear(); localStorage.clear();
sessionStorage.clear(); sessionStorage.clear();
}, }
/** /**
* Preforms the given action on each item that has the given prefix * Preforms the given action on each item that has the given prefix
* Signature for action is action(key, value) * Signature for action is action(key, value)
*/ */
actionOnItemsWithPrefix: function(prefix, action) { actionOnItemsWithPrefix(prefix, action) {
if (!this.initialized) {
this.initialize();
}
var globalPrefix = getPrefix(); var globalPrefix = getPrefix();
var globalPrefixiLen = globalPrefix.length; var globalPrefixiLen = globalPrefix.length;
for (var key in localStorage) { for (var key in localStorage) {
@@ -95,9 +84,9 @@ module.exports = {
action(userkey, this.getGlobalItem(key)); action(userkey, this.getGlobalItem(key));
} }
} }
}, }
isLocalStorageSupported: function() { isLocalStorageSupported() {
try { try {
sessionStorage.setItem('testSession', '1'); sessionStorage.setItem('testSession', '1');
sessionStorage.removeItem('testSession'); sessionStorage.removeItem('testSession');
@@ -113,4 +102,7 @@ module.exports = {
return false; return false;
} }
} }
}; }
var BrowserStore = new BrowserStoreClass();
export default BrowserStore;

Просмотреть файл

@@ -3,7 +3,6 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var BrowserStore = require('../stores/browser_store.jsx'); var BrowserStore = require('../stores/browser_store.jsx');
@@ -12,45 +11,59 @@ var ActionTypes = Constants.ActionTypes;
var CHANGE_EVENT = 'change'; var CHANGE_EVENT = 'change';
var ConfigStore = assign({}, EventEmitter.prototype, { class ConfigStoreClass extends EventEmitter {
emitChange: function emitChange() { constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.getSetting = this.getSetting.bind(this);
this.getSettingAsBoolean = this.getSettingAsBoolean.bind(this);
this.updateStoredSettings = this.updateStoredSettings.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT); this.emit(CHANGE_EVENT);
}, }
addChangeListener: function addChangeListener(callback) { addChangeListener(callback) {
this.on(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
removeChangeListener: function removeChangeListener(callback) { removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.removeListener(CHANGE_EVENT, callback);
}, }
getSetting: function getSetting(key, defaultValue) { getSetting(key, defaultValue) {
return BrowserStore.getItem('config_' + key, defaultValue); return BrowserStore.getItem('config_' + key, defaultValue);
}, }
getSettingAsBoolean: function getSettingAsNumber(key, defaultValue) { getSettingAsBoolean(key, defaultValue) {
var value = ConfigStore.getSetting(key, defaultValue); var value = this.getSetting(key, defaultValue);
if (typeof value !== 'string') { if (typeof value !== 'string') {
return !!value; return Boolean(value);
} else {
return value === 'true';
} }
},
updateStoredSettings: function updateStoredSettings(settings) { return value === 'true';
for (var key in settings) { }
BrowserStore.setItem('config_' + key, settings[key]); updateStoredSettings(settings) {
for (let key in settings) {
if (settings.hasOwnProperty(key)) {
BrowserStore.setItem('config_' + key, settings[key]);
}
} }
} }
}); }
var ConfigStore = new ConfigStoreClass();
ConfigStore.dispatchToken = AppDispatcher.register(function registry(payload) { ConfigStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action; var action = payload.action;
switch (action.type) { switch (action.type) {
case ActionTypes.RECIEVED_CONFIG: case ActionTypes.RECIEVED_CONFIG:
ConfigStore.updateStoredSettings(action.settings); ConfigStore.updateStoredSettings(action.settings);
ConfigStore.emitChange(); ConfigStore.emitChange();
break; break;
default: default:
} }
}); });
module.exports = ConfigStore; export default ConfigStore;

Просмотреть файл

@@ -3,7 +3,6 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
@@ -12,43 +11,53 @@ var BrowserStore = require('../stores/browser_store.jsx');
var CHANGE_EVENT = 'change'; var CHANGE_EVENT = 'change';
var ErrorStore = assign({}, EventEmitter.prototype, { class ErrorStoreClass extends EventEmitter {
constructor() {
super();
emitChange: function() { this.emitChange = this.emitChange.bind(this);
this.emit(CHANGE_EVENT); this.addChangeListener = this.addChangeListener.bind(this);
}, this.removeChangeListener = this.removeChangeListener.bind(this);
this.handledError = this.handledError.bind(this);
this.getLastError = this.getLastError.bind(this);
this.storeLastError = this.storeLastError.bind(this);
}
addChangeListener: function(callback) { emitChange() {
this.on(CHANGE_EVENT, callback); this.emit(CHANGE_EVENT);
}, }
removeChangeListener: function(callback) { addChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
handledError: function() {
BrowserStore.removeItem("last_error");
},
getLastError: function() {
return BrowserStore.getItem('last_error');
},
_storeLastError: function(error) { removeChangeListener(callback) {
BrowserStore.setItem("last_error", error); this.removeListener(CHANGE_EVENT, callback);
}, }
}); handledError() {
BrowserStore.removeItem('last_error');
}
getLastError() {
return BrowserStore.getItem('last_error');
}
ErrorStore.dispatchToken = AppDispatcher.register(function(payload) { storeLastError(error) {
var action = payload.action; BrowserStore.setItem('last_error', error);
switch(action.type) { }
}
var ErrorStore = new ErrorStoreClass();
ErrorStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action;
switch (action.type) {
case ActionTypes.RECIEVED_ERROR: case ActionTypes.RECIEVED_ERROR:
ErrorStore._storeLastError(action.err); ErrorStore.storeLastError(action.err);
ErrorStore.emitChange(); ErrorStore.emitChange();
break; break;
default: default:
} }
}); });
module.exports = ErrorStore; export default ErrorStore;

Просмотреть файл

@@ -3,7 +3,6 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ChannelStore = require('../stores/channel_store.jsx'); var ChannelStore = require('../stores/channel_store.jsx');
var BrowserStore = require('../stores/browser_store.jsx'); var BrowserStore = require('../stores/browser_store.jsx');
@@ -18,109 +17,169 @@ var SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
var MENTION_DATA_CHANGE_EVENT = 'mention_data_change'; var MENTION_DATA_CHANGE_EVENT = 'mention_data_change';
var ADD_MENTION_EVENT = 'add_mention'; var ADD_MENTION_EVENT = 'add_mention';
var PostStore = assign({}, EventEmitter.prototype, { class PostStoreClass extends EventEmitter {
emitChange: function emitChange() { constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.emitSearchChange = this.emitSearchChange.bind(this);
this.addSearchChangeListener = this.addSearchChangeListener.bind(this);
this.removeSearchChangeListener = this.removeSearchChangeListener.bind(this);
this.emitSearchTermChange = this.emitSearchTermChange.bind(this);
this.addSearchTermChangeListener = this.addSearchTermChangeListener.bind(this);
this.removeSearchTermChangeListener = this.removeSearchTermChangeListener.bind(this);
this.emitSelectedPostChange = this.emitSelectedPostChange.bind(this);
this.addSelectedPostChangeListener = this.addSelectedPostChangeListener.bind(this);
this.removeSelectedPostChangeListener = this.removeSelectedPostChangeListener.bind(this);
this.emitMentionDataChange = this.emitMentionDataChange.bind(this);
this.addMentionDataChangeListener = this.addMentionDataChangeListener.bind(this);
this.removeMentionDataChangeListener = this.removeMentionDataChangeListener.bind(this);
this.emitAddMention = this.emitAddMention.bind(this);
this.addAddMentionListener = this.addAddMentionListener.bind(this);
this.removeAddMentionListener = this.removeAddMentionListener.bind(this);
this.getCurrentPosts = this.getCurrentPosts.bind(this);
this.storePosts = this.storePosts.bind(this);
this.pStorePosts = this.pStorePosts.bind(this);
this.getPosts = this.getPosts.bind(this);
this.storePost = this.storePost.bind(this);
this.pStorePost = this.pStorePost.bind(this);
this.removePost = this.removePost.bind(this);
this.storePendingPost = this.storePendingPost.bind(this);
this.pStorePendingPosts = this.pStorePendingPosts.bind(this);
this.getPendingPosts = this.getPendingPosts.bind(this);
this.storeUnseenDeletedPost = this.storeUnseenDeletedPost.bind(this);
this.storeUnseenDeletedPosts = this.storeUnseenDeletedPosts.bind(this);
this.getUnseenDeletedPosts = this.getUnseenDeletedPosts.bind(this);
this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this);
this.removePendingPost = this.removePendingPost.bind(this);
this.pRemovePendingPost = this.pRemovePendingPost.bind(this);
this.clearPendingPosts = this.clearPendingPosts.bind(this);
this.updatePendingPost = this.updatePendingPost.bind(this);
this.storeSearchResults = this.storeSearchResults.bind(this);
this.getSearchResults = this.getSearchResults.bind(this);
this.getIsMentionSearch = this.getIsMentionSearch.bind(this);
this.storeSelectedPost = this.storeSelectedPost.bind(this);
this.getSelectedPost = this.getSelectedPost.bind(this);
this.storeSearchTerm = this.storeSearchTerm.bind(this);
this.getSearchTerm = this.getSearchTerm.bind(this);
this.getEmptyDraft = this.getEmptyDraft.bind(this);
this.storeCurrentDraft = this.storeCurrentDraft.bind(this);
this.getCurrentDraft = this.getCurrentDraft.bind(this);
this.storeDraft = this.storeDraft.bind(this);
this.getDraft = this.getDraft.bind(this);
this.storeCommentDraft = this.storeCommentDraft.bind(this);
this.getCommentDraft = this.getCommentDraft.bind(this);
this.clearDraftUploads = this.clearDraftUploads.bind(this);
this.clearCommentDraftUploads = this.clearCommentDraftUploads.bind(this);
this.storeLatestUpdate = this.storeLatestUpdate.bind(this);
this.getLatestUpdate = this.getLatestUpdate.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT); this.emit(CHANGE_EVENT);
}, }
addChangeListener: function addChangeListener(callback) { addChangeListener(callback) {
this.on(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
removeChangeListener: function removeChangeListener(callback) { removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.removeListener(CHANGE_EVENT, callback);
}, }
emitSearchChange: function emitSearchChange() { emitSearchChange() {
this.emit(SEARCH_CHANGE_EVENT); this.emit(SEARCH_CHANGE_EVENT);
}, }
addSearchChangeListener: function addSearchChangeListener(callback) { addSearchChangeListener(callback) {
this.on(SEARCH_CHANGE_EVENT, callback); this.on(SEARCH_CHANGE_EVENT, callback);
}, }
removeSearchChangeListener: function removeSearchChangeListener(callback) { removeSearchChangeListener(callback) {
this.removeListener(SEARCH_CHANGE_EVENT, callback); this.removeListener(SEARCH_CHANGE_EVENT, callback);
}, }
emitSearchTermChange: function emitSearchTermChange(doSearch, isMentionSearch) { emitSearchTermChange(doSearch, isMentionSearch) {
this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch); this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch);
}, }
addSearchTermChangeListener: function addSearchTermChangeListener(callback) { addSearchTermChangeListener(callback) {
this.on(SEARCH_TERM_CHANGE_EVENT, callback); this.on(SEARCH_TERM_CHANGE_EVENT, callback);
}, }
removeSearchTermChangeListener: function removeSearchTermChangeListener(callback) { removeSearchTermChangeListener(callback) {
this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback); this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback);
}, }
emitSelectedPostChange: function emitSelectedPostChange(fromSearch) { emitSelectedPostChange(fromSearch) {
this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch); this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch);
}, }
addSelectedPostChangeListener: function addSelectedPostChangeListener(callback) { addSelectedPostChangeListener(callback) {
this.on(SELECTED_POST_CHANGE_EVENT, callback); this.on(SELECTED_POST_CHANGE_EVENT, callback);
}, }
removeSelectedPostChangeListener: function removeSelectedPostChangeListener(callback) { removeSelectedPostChangeListener(callback) {
this.removeListener(SELECTED_POST_CHANGE_EVENT, callback); this.removeListener(SELECTED_POST_CHANGE_EVENT, callback);
}, }
emitMentionDataChange: function emitMentionDataChange(id, mentionText) { emitMentionDataChange(id, mentionText) {
this.emit(MENTION_DATA_CHANGE_EVENT, id, mentionText); this.emit(MENTION_DATA_CHANGE_EVENT, id, mentionText);
}, }
addMentionDataChangeListener: function addMentionDataChangeListener(callback) { addMentionDataChangeListener(callback) {
this.on(MENTION_DATA_CHANGE_EVENT, callback); this.on(MENTION_DATA_CHANGE_EVENT, callback);
}, }
removeMentionDataChangeListener: function removeMentionDataChangeListener(callback) { removeMentionDataChangeListener(callback) {
this.removeListener(MENTION_DATA_CHANGE_EVENT, callback); this.removeListener(MENTION_DATA_CHANGE_EVENT, callback);
}, }
emitAddMention: function emitAddMention(id, username) { emitAddMention(id, username) {
this.emit(ADD_MENTION_EVENT, id, username); this.emit(ADD_MENTION_EVENT, id, username);
}, }
addAddMentionListener: function addAddMentionListener(callback) { addAddMentionListener(callback) {
this.on(ADD_MENTION_EVENT, callback); this.on(ADD_MENTION_EVENT, callback);
}, }
removeAddMentionListener: function removeAddMentionListener(callback) { removeAddMentionListener(callback) {
this.removeListener(ADD_MENTION_EVENT, callback); this.removeListener(ADD_MENTION_EVENT, callback);
}, }
getCurrentPosts: function getCurrentPosts() { getCurrentPosts() {
var currentId = ChannelStore.getCurrentId(); var currentId = ChannelStore.getCurrentId();
if (currentId != null) { if (currentId != null) {
return this.getPosts(currentId); return this.getPosts(currentId);
} }
return null; return null;
}, }
storePosts: function storePosts(channelId, newPostList) { storePosts(channelId, newPostList) {
if (isPostListNull(newPostList)) { if (isPostListNull(newPostList)) {
return; return;
} }
var postList = makePostListNonNull(PostStore.getPosts(channelId)); var postList = makePostListNonNull(this.getPosts(channelId));
for (var pid in newPostList.posts) { for (let pid in newPostList.posts) {
var np = newPostList.posts[pid]; if (newPostList.posts.hasOwnProperty(pid)) {
if (np.delete_at === 0) { var np = newPostList.posts[pid];
postList.posts[pid] = np; if (np.delete_at === 0) {
if (postList.order.indexOf(pid) === -1) { postList.posts[pid] = np;
postList.order.push(pid); if (postList.order.indexOf(pid) === -1) {
} postList.order.push(pid);
} else { }
if (pid in postList.posts) { } else {
delete postList.posts[pid]; if (pid in postList.posts) {
} delete postList.posts[pid];
}
var index = postList.order.indexOf(pid); var index = postList.order.indexOf(pid);
if (index !== -1) { if (index !== -1) {
postList.order.splice(index, 1); postList.order.splice(index, 1);
}
} }
} }
} }
@@ -146,19 +205,19 @@ var PostStore = assign({}, EventEmitter.prototype, {
this.storeLatestUpdate(channelId, latestUpdate); this.storeLatestUpdate(channelId, latestUpdate);
this.pStorePosts(channelId, postList); this.pStorePosts(channelId, postList);
this.emitChange(); this.emitChange();
}, }
pStorePosts: function pStorePosts(channelId, posts) { pStorePosts(channelId, posts) {
BrowserStore.setItem('posts_' + channelId, posts); BrowserStore.setItem('posts_' + channelId, posts);
}, }
getPosts: function getPosts(channelId) { getPosts(channelId) {
return BrowserStore.getItem('posts_' + channelId); return BrowserStore.getItem('posts_' + channelId);
}, }
storePost: function(post) { storePost(post) {
this.pStorePost(post); this.pStorePost(post);
this.emitChange(); this.emitChange();
}, }
pStorePost: function(post) { pStorePost(post) {
var postList = PostStore.getPosts(post.channel_id); var postList = this.getPosts(post.channel_id);
postList = makePostListNonNull(postList); postList = makePostListNonNull(postList);
if (post.pending_post_id !== '') { if (post.pending_post_id !== '') {
@@ -173,9 +232,9 @@ var PostStore = assign({}, EventEmitter.prototype, {
} }
this.pStorePosts(post.channel_id, postList); this.pStorePosts(post.channel_id, postList);
}, }
removePost: function(postId, channelId) { removePost(postId, channelId) {
var postList = PostStore.getPosts(channelId); var postList = this.getPosts(channelId);
if (isPostListNull(postList)) { if (isPostListNull(postList)) {
return; return;
} }
@@ -190,8 +249,8 @@ var PostStore = assign({}, EventEmitter.prototype, {
} }
this.pStorePosts(channelId, postList); this.pStorePosts(channelId, postList);
}, }
storePendingPost: function(post) { storePendingPost(post) {
post.state = Constants.POST_LOADING; post.state = Constants.POST_LOADING;
var postList = this.getPendingPosts(post.channel_id); var postList = this.getPendingPosts(post.channel_id);
@@ -199,10 +258,10 @@ var PostStore = assign({}, EventEmitter.prototype, {
postList.posts[post.pending_post_id] = post; postList.posts[post.pending_post_id] = post;
postList.order.unshift(post.pending_post_id); postList.order.unshift(post.pending_post_id);
this._storePendingPosts(post.channel_id, postList); this.pStorePendingPosts(post.channel_id, postList);
this.emitChange(); this.emitChange();
}, }
_storePendingPosts: function(channelId, postList) { pStorePendingPosts(channelId, postList) {
var posts = postList.posts; var posts = postList.posts;
// sort failed posts to the bottom // sort failed posts to the bottom
@@ -225,11 +284,11 @@ var PostStore = assign({}, EventEmitter.prototype, {
}); });
BrowserStore.setItem('pending_posts_' + channelId, postList); BrowserStore.setItem('pending_posts_' + channelId, postList);
}, }
getPendingPosts: function(channelId) { getPendingPosts(channelId) {
return BrowserStore.getItem('pending_posts_' + channelId); return BrowserStore.getItem('pending_posts_' + channelId);
}, }
storeUnseenDeletedPost: function(post) { storeUnseenDeletedPost(post) {
var posts = this.getUnseenDeletedPosts(post.channel_id); var posts = this.getUnseenDeletedPosts(post.channel_id);
if (!posts) { if (!posts) {
@@ -241,21 +300,21 @@ var PostStore = assign({}, EventEmitter.prototype, {
posts[post.id] = post; posts[post.id] = post;
this.storeUnseenDeletedPosts(post.channel_id, posts); this.storeUnseenDeletedPosts(post.channel_id, posts);
}, }
storeUnseenDeletedPosts: function(channelId, posts) { storeUnseenDeletedPosts(channelId, posts) {
BrowserStore.setItem('deleted_posts_' + channelId, posts); BrowserStore.setItem('deleted_posts_' + channelId, posts);
}, }
getUnseenDeletedPosts: function(channelId) { getUnseenDeletedPosts(channelId) {
return BrowserStore.getItem('deleted_posts_' + channelId); return BrowserStore.getItem('deleted_posts_' + channelId);
}, }
clearUnseenDeletedPosts: function(channelId) { clearUnseenDeletedPosts(channelId) {
BrowserStore.setItem('deleted_posts_' + channelId, {}); BrowserStore.setItem('deleted_posts_' + channelId, {});
}, }
removePendingPost: function(channelId, pendingPostId) { removePendingPost(channelId, pendingPostId) {
this._removePendingPost(channelId, pendingPostId); this.pRemovePendingPost(channelId, pendingPostId);
this.emitChange(); this.emitChange();
}, }
_removePendingPost: function(channelId, pendingPostId) { pRemovePendingPost(channelId, pendingPostId) {
var postList = this.getPendingPosts(channelId); var postList = this.getPendingPosts(channelId);
postList = makePostListNonNull(postList); postList = makePostListNonNull(postList);
@@ -267,14 +326,14 @@ var PostStore = assign({}, EventEmitter.prototype, {
postList.order.splice(index, 1); postList.order.splice(index, 1);
} }
this._storePendingPosts(channelId, postList); this.pStorePendingPosts(channelId, postList);
}, }
clearPendingPosts: function() { clearPendingPosts() {
BrowserStore.actionOnItemsWithPrefix('pending_posts_', function clearPending(key) { BrowserStore.actionOnItemsWithPrefix('pending_posts_', function clearPending(key) {
BrowserStore.removeItem(key); BrowserStore.removeItem(key);
}); });
}, }
updatePendingPost: function(post) { updatePendingPost(post) {
var postList = this.getPendingPosts(post.channel_id); var postList = this.getPendingPosts(post.channel_id);
postList = makePostListNonNull(postList); postList = makePostListNonNull(postList);
@@ -283,112 +342,114 @@ var PostStore = assign({}, EventEmitter.prototype, {
} }
postList.posts[post.pending_post_id] = post; postList.posts[post.pending_post_id] = post;
this._storePendingPosts(post.channel_id, postList); this.pStorePendingPosts(post.channel_id, postList);
this.emitChange(); this.emitChange();
}, }
storeSearchResults: function storeSearchResults(results, isMentionSearch) { storeSearchResults(results, isMentionSearch) {
BrowserStore.setItem('search_results', results); BrowserStore.setItem('search_results', results);
BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch)); BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch));
}, }
getSearchResults: function getSearchResults() { getSearchResults() {
return BrowserStore.getItem('search_results'); return BrowserStore.getItem('search_results');
}, }
getIsMentionSearch: function getIsMentionSearch() { getIsMentionSearch() {
return BrowserStore.getItem('is_mention_search'); return BrowserStore.getItem('is_mention_search');
}, }
storeSelectedPost: function storeSelectedPost(postList) { storeSelectedPost(postList) {
BrowserStore.setItem('select_post', postList); BrowserStore.setItem('select_post', postList);
}, }
getSelectedPost: function getSelectedPost() { getSelectedPost() {
return BrowserStore.getItem('select_post'); return BrowserStore.getItem('select_post');
}, }
storeSearchTerm: function storeSearchTerm(term) { storeSearchTerm(term) {
BrowserStore.setItem('search_term', term); BrowserStore.setItem('search_term', term);
}, }
getSearchTerm: function getSearchTerm() { getSearchTerm() {
return BrowserStore.getItem('search_term'); return BrowserStore.getItem('search_term');
}, }
getEmptyDraft: function getEmptyDraft(draft) { getEmptyDraft() {
return {message: '', uploadsInProgress: [], previews: []}; return {message: '', uploadsInProgress: [], previews: []};
}, }
storeCurrentDraft: function storeCurrentDraft(draft) { storeCurrentDraft(draft) {
var channelId = ChannelStore.getCurrentId(); var channelId = ChannelStore.getCurrentId();
BrowserStore.setItem('draft_' + channelId, draft); BrowserStore.setItem('draft_' + channelId, draft);
}, }
getCurrentDraft: function getCurrentDraft() { getCurrentDraft() {
var channelId = ChannelStore.getCurrentId(); var channelId = ChannelStore.getCurrentId();
return PostStore.getDraft(channelId); return this.getDraft(channelId);
}, }
storeDraft: function storeDraft(channelId, draft) { storeDraft(channelId, draft) {
BrowserStore.setItem('draft_' + channelId, draft); BrowserStore.setItem('draft_' + channelId, draft);
}, }
getDraft: function getDraft(channelId) { getDraft(channelId) {
return BrowserStore.getItem('draft_' + channelId, PostStore.getEmptyDraft()); return BrowserStore.getItem('draft_' + channelId, this.getEmptyDraft());
}, }
storeCommentDraft: function storeCommentDraft(parentPostId, draft) { storeCommentDraft(parentPostId, draft) {
BrowserStore.setItem('comment_draft_' + parentPostId, draft); BrowserStore.setItem('comment_draft_' + parentPostId, draft);
}, }
getCommentDraft: function getCommentDraft(parentPostId) { getCommentDraft(parentPostId) {
return BrowserStore.getItem('comment_draft_' + parentPostId, PostStore.getEmptyDraft()); return BrowserStore.getItem('comment_draft_' + parentPostId, this.getEmptyDraft());
}, }
clearDraftUploads: function clearDraftUploads() { clearDraftUploads() {
BrowserStore.actionOnItemsWithPrefix('draft_', function clearUploads(key, value) { BrowserStore.actionOnItemsWithPrefix('draft_', function clearUploads(key, value) {
if (value) { if (value) {
value.uploadsInProgress = []; value.uploadsInProgress = [];
BrowserStore.setItem(key, value); BrowserStore.setItem(key, value);
} }
}); });
}, }
clearCommentDraftUploads: function clearCommentDraftUploads() { clearCommentDraftUploads() {
BrowserStore.actionOnItemsWithPrefix('comment_draft_', function clearUploads(key, value) { BrowserStore.actionOnItemsWithPrefix('comment_draft_', function clearUploads(key, value) {
if (value) { if (value) {
value.uploadsInProgress = []; value.uploadsInProgress = [];
BrowserStore.setItem(key, value); BrowserStore.setItem(key, value);
} }
}); });
}, }
storeLatestUpdate: function(channelId, time) { storeLatestUpdate(channelId, time) {
BrowserStore.setItem('latest_post_' + channelId, time); BrowserStore.setItem('latest_post_' + channelId, time);
}, }
getLatestUpdate: function(channelId) { getLatestUpdate(channelId) {
return BrowserStore.getItem('latest_post_' + channelId, 0); return BrowserStore.getItem('latest_post_' + channelId, 0);
} }
}); }
var PostStore = new PostStoreClass();
PostStore.dispatchToken = AppDispatcher.register(function registry(payload) { PostStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action; var action = payload.action;
switch (action.type) { switch (action.type) {
case ActionTypes.RECIEVED_POSTS: case ActionTypes.RECIEVED_POSTS:
PostStore.storePosts(action.id, makePostListNonNull(action.post_list)); PostStore.storePosts(action.id, makePostListNonNull(action.post_list));
break; break;
case ActionTypes.RECIEVED_POST: case ActionTypes.RECIEVED_POST:
PostStore.pStorePost(action.post); PostStore.pStorePost(action.post);
PostStore.emitChange(); PostStore.emitChange();
break; break;
case ActionTypes.RECIEVED_SEARCH: case ActionTypes.RECIEVED_SEARCH:
PostStore.storeSearchResults(action.results, action.is_mention_search); PostStore.storeSearchResults(action.results, action.is_mention_search);
PostStore.emitSearchChange(); PostStore.emitSearchChange();
break; break;
case ActionTypes.RECIEVED_SEARCH_TERM: case ActionTypes.RECIEVED_SEARCH_TERM:
PostStore.storeSearchTerm(action.term); PostStore.storeSearchTerm(action.term);
PostStore.emitSearchTermChange(action.do_search, action.is_mention_search); PostStore.emitSearchTermChange(action.do_search, action.is_mention_search);
break; break;
case ActionTypes.RECIEVED_POST_SELECTED: case ActionTypes.RECIEVED_POST_SELECTED:
PostStore.storeSelectedPost(action.post_list); PostStore.storeSelectedPost(action.post_list);
PostStore.emitSelectedPostChange(action.from_search); PostStore.emitSelectedPostChange(action.from_search);
break; break;
case ActionTypes.RECIEVED_MENTION_DATA: case ActionTypes.RECIEVED_MENTION_DATA:
PostStore.emitMentionDataChange(action.id, action.mention_text); PostStore.emitMentionDataChange(action.id, action.mention_text);
break; break;
case ActionTypes.RECIEVED_ADD_MENTION: case ActionTypes.RECIEVED_ADD_MENTION:
PostStore.emitAddMention(action.id, action.username); PostStore.emitAddMention(action.id, action.username);
break; break;
default: default:
} }
}); });
module.exports = PostStore; export default PostStore;
function makePostListNonNull(pl) { function makePostListNonNull(pl) {
var postList = pl; var postList = pl;

Просмотреть файл

@@ -2,10 +2,8 @@
// See License.txt for license information. // See License.txt for license information.
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var UserStore = require('./user_store.jsx') var UserStore = require('./user_store.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var client = require('../utils/client.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
@@ -14,14 +12,24 @@ var CHANGE_EVENT = 'change';
var conn; var conn;
var SocketStore = assign({}, EventEmitter.prototype, { class SocketStoreClass extends EventEmitter {
initialize: function() { constructor() {
super();
this.initialize = this.initialize.bind(this);
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.sendMessage = this.sendMessage.bind(this);
this.initialize();
}
initialize() {
if (!UserStore.getCurrentId()) { if (!UserStore.getCurrentId()) {
return; return;
} }
var self = this; this.setMaxListeners(0);
self.setMaxListeners(0);
if (window.WebSocket && !conn) { if (window.WebSocket && !conn) {
var protocol = 'ws://'; var protocol = 'ws://';
@@ -29,24 +37,24 @@ var SocketStore = assign({}, EventEmitter.prototype, {
protocol = 'wss://'; protocol = 'wss://';
} }
var connUrl = protocol + location.host + '/api/v1/websocket'; var connUrl = protocol + location.host + '/api/v1/websocket';
console.log('connecting to ' + connUrl); console.log('connecting to ' + connUrl); //eslint-disable-line no-console
conn = new WebSocket(connUrl); conn = new WebSocket(connUrl);
conn.onclose = function closeConn(evt) { conn.onclose = function closeConn(evt) {
console.log('websocket closed'); console.log('websocket closed'); //eslint-disable-line no-console
console.log(evt); console.log(evt); //eslint-disable-line no-console
conn = null; conn = null;
setTimeout( setTimeout(
function reconnect() { function reconnect() {
self.initialize(); this.initialize();
}, }.bind(this),
3000 3000
); );
}; }.bind(this);
conn.onerror = function connError(evt) { conn.onerror = function connError(evt) {
console.log('websocket error'); console.log('websocket error'); //eslint-disable-line no-console
console.log(evt); console.log(evt); //eslint-disable-line no-console
}; };
conn.onmessage = function connMessage(evt) { conn.onmessage = function connMessage(evt) {
@@ -56,17 +64,17 @@ var SocketStore = assign({}, EventEmitter.prototype, {
}); });
}; };
} }
}, }
emitChange: function(msg) { emitChange(msg) {
this.emit(CHANGE_EVENT, msg); this.emit(CHANGE_EVENT, msg);
}, }
addChangeListener: function(callback) { addChangeListener(callback) {
this.on(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
removeChangeListener: function(callback) { removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.removeListener(CHANGE_EVENT, callback);
}, }
sendMessage: function(msg) { sendMessage(msg) {
if (conn && conn.readyState === WebSocket.OPEN) { if (conn && conn.readyState === WebSocket.OPEN) {
conn.send(JSON.stringify(msg)); conn.send(JSON.stringify(msg));
} else if (!conn || conn.readyState === WebSocket.Closed) { } else if (!conn || conn.readyState === WebSocket.Closed) {
@@ -74,19 +82,20 @@ var SocketStore = assign({}, EventEmitter.prototype, {
this.initialize(); this.initialize();
} }
} }
}); }
SocketStore.dispatchToken = AppDispatcher.register(function(payload) { var SocketStore = new SocketStoreClass();
SocketStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action; var action = payload.action;
switch (action.type) { switch (action.type) {
case ActionTypes.RECIEVED_MSG: case ActionTypes.RECIEVED_MSG:
SocketStore.emitChange(action.msg); SocketStore.emitChange(action.msg);
break; break;
default: default:
} }
}); });
SocketStore.initialize(); export default SocketStore;
module.exports = SocketStore;

Просмотреть файл

@@ -3,7 +3,6 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
@@ -19,21 +18,38 @@ function getWindowLocationOrigin() {
return utils.getWindowLocationOrigin(); return utils.getWindowLocationOrigin();
} }
var TeamStore = assign({}, EventEmitter.prototype, { class TeamStoreClass extends EventEmitter {
emitChange: function() { constructor() {
super();
this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.get = this.get.bind(this);
this.getByName = this.getByName.bind(this);
this.getAll = this.getAll.bind(this);
this.setCurrentId = this.setCurrentId.bind(this);
this.getCurrentId = this.getCurrentId.bind(this);
this.getCurrent = this.getCurrent.bind(this);
this.getCurrentTeamUrl = this.getCurrentTeamUrl.bind(this);
this.storeTeam = this.storeTeam.bind(this);
this.pStoreTeams = this.pStoreTeams.bind(this);
this.pGetTeams = this.pGetTeams.bind(this);
}
emitChange() {
this.emit(CHANGE_EVENT); this.emit(CHANGE_EVENT);
}, }
addChangeListener: function(callback) { addChangeListener(callback) {
this.on(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
removeChangeListener: function(callback) { removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.removeListener(CHANGE_EVENT, callback);
}, }
get: function(id) { get(id) {
var c = this.pGetTeams(); var c = this.pGetTeams();
return c[id]; return c[id];
}, }
getByName: function(name) { getByName(name) {
var t = this.pGetTeams(); var t = this.pGetTeams();
for (var id in t) { for (var id in t) {
@@ -43,64 +59,65 @@ var TeamStore = assign({}, EventEmitter.prototype, {
} }
return null; return null;
}, }
getAll: function() { getAll() {
return this.pGetTeams(); return this.pGetTeams();
}, }
setCurrentId: function(id) { setCurrentId(id) {
if (id === null) { if (id === null) {
BrowserStore.removeItem('current_team_id'); BrowserStore.removeItem('current_team_id');
} else { } else {
BrowserStore.setItem('current_team_id', id); BrowserStore.setItem('current_team_id', id);
} }
}, }
getCurrentId: function() { getCurrentId() {
return BrowserStore.getItem('current_team_id'); return BrowserStore.getItem('current_team_id');
}, }
getCurrent: function() { getCurrent() {
var currentId = TeamStore.getCurrentId(); var currentId = this.getCurrentId();
if (currentId !== null) { if (currentId !== null) {
return this.get(currentId); return this.get(currentId);
} }
return null; return null;
}, }
getCurrentTeamUrl: function() { getCurrentTeamUrl() {
if (this.getCurrent()) { if (this.getCurrent()) {
return getWindowLocationOrigin() + '/' + this.getCurrent().name; return getWindowLocationOrigin() + '/' + this.getCurrent().name;
} }
return null; return null;
}, }
storeTeam: function(team) { storeTeam(team) {
var teams = this.pGetTeams(); var teams = this.pGetTeams();
teams[team.id] = team; teams[team.id] = team;
this.pStoreTeams(teams); this.pStoreTeams(teams);
}, }
pStoreTeams: function(teams) { pStoreTeams(teams) {
BrowserStore.setItem('user_teams', teams); BrowserStore.setItem('user_teams', teams);
}, }
pGetTeams: function() { pGetTeams() {
return BrowserStore.getItem('user_teams', {}); return BrowserStore.getItem('user_teams', {});
} }
}); }
var TeamStore = new TeamStoreClass();
TeamStore.dispatchToken = AppDispatcher.register(function registry(payload) { TeamStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action; var action = payload.action;
switch (action.type) { switch (action.type) {
case ActionTypes.CLICK_TEAM:
TeamStore.setCurrentId(action.id);
TeamStore.emitChange();
break;
case ActionTypes.CLICK_TEAM: case ActionTypes.RECIEVED_TEAM:
TeamStore.setCurrentId(action.id); TeamStore.storeTeam(action.team);
TeamStore.emitChange(); TeamStore.emitChange();
break; break;
case ActionTypes.RECIEVED_TEAM: default:
TeamStore.storeTeam(action.team);
TeamStore.emitChange();
break;
default:
} }
}); });
module.exports = TeamStore; export default TeamStore;

Просмотреть файл

@@ -3,7 +3,6 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var client = require('../utils/client.jsx'); var client = require('../utils/client.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
@@ -16,64 +15,114 @@ var CHANGE_EVENT_AUDITS = 'change_audits';
var CHANGE_EVENT_TEAMS = 'change_teams'; var CHANGE_EVENT_TEAMS = 'change_teams';
var CHANGE_EVENT_STATUSES = 'change_statuses'; var CHANGE_EVENT_STATUSES = 'change_statuses';
var UserStore = assign({}, EventEmitter.prototype, { class UserStoreClass extends EventEmitter {
constructor() {
super();
gCurrentId: null, this.emitChange = this.emitChange.bind(this);
this.addChangeListener = this.addChangeListener.bind(this);
this.removeChangeListener = this.removeChangeListener.bind(this);
this.emitSessionsChange = this.emitSessionsChange.bind(this);
this.addSessionsChangeListener = this.addSessionsChangeListener.bind(this);
this.removeSessionsChangeListener = this.removeSessionsChangeListener.bind(this);
this.emitAuditsChange = this.emitAuditsChange.bind(this);
this.addAuditsChangeListener = this.addAuditsChangeListener.bind(this);
this.removeAuditsChangeListener = this.removeAuditsChangeListener.bind(this);
this.emitTeamsChange = this.emitTeamsChange.bind(this);
this.addTeamsChangeListener = this.addTeamsChangeListener.bind(this);
this.removeTeamsChangeListener = this.removeTeamsChangeListener.bind(this);
this.emitStatusesChange = this.emitStatusesChange.bind(this);
this.addStatusesChangeListener = this.addStatusesChangeListener.bind(this);
this.removeStatusesChangeListener = this.removeStatusesChangeListener.bind(this);
this.setCurrentId = this.setCurrentId.bind(this);
this.getCurrentId = this.getCurrentId.bind(this);
this.getCurrentUser = this.getCurrentUser.bind(this);
this.setCurrentUser = this.setCurrentUser.bind(this);
this.getLastEmail = this.getLastEmail.bind(this);
this.setLastEmail = this.setLastEmail.bind(this);
this.removeCurrentUser = this.removeCurrentUser.bind(this);
this.hasProfile = this.hasProfile.bind(this);
this.getProfile = this.getProfile.bind(this);
this.getProfileByUsername = this.getProfileByUsername.bind(this);
this.getProfilesUsernameMap = this.getProfilesUsernameMap.bind(this);
this.getProfiles = this.getProfiles.bind(this);
this.getActiveOnlyProfiles = this.getActiveOnlyProfiles.bind(this);
this.saveProfile = this.saveProfile.bind(this);
this.pStoreProfiles = this.pStoreProfiles.bind(this);
this.pGetProfiles = this.pGetProfiles.bind(this);
this.pGetProfilesUsernameMap = this.pGetProfilesUsernameMap.bind(this);
this.setSessions = this.setSessions.bind(this);
this.getSessions = this.getSessions.bind(this);
this.setAudits = this.setAudits.bind(this);
this.getAudits = this.getAudits.bind(this);
this.setTeams = this.setTeams.bind(this);
this.getTeams = this.getTeams.bind(this);
this.getCurrentMentionKeys = this.getCurrentMentionKeys.bind(this);
this.getLastVersion = this.getLastVersion.bind(this);
this.setLastVersion = this.setLastVersion.bind(this);
this.setStatuses = this.setStatuses.bind(this);
this.pSetStatuses = this.pSetStatuses.bind(this);
this.setStatus = this.setStatus.bind(this);
this.getStatuses = this.getStatuses.bind(this);
this.getStatus = this.getStatus.bind(this);
emitChange: function(userId) { this.gCurrentId = null;
}
emitChange(userId) {
this.emit(CHANGE_EVENT, userId); this.emit(CHANGE_EVENT, userId);
}, }
addChangeListener: function(callback) { addChangeListener(callback) {
this.on(CHANGE_EVENT, callback); this.on(CHANGE_EVENT, callback);
}, }
removeChangeListener: function(callback) { removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback); this.removeListener(CHANGE_EVENT, callback);
}, }
emitSessionsChange: function() { emitSessionsChange() {
this.emit(CHANGE_EVENT_SESSIONS); this.emit(CHANGE_EVENT_SESSIONS);
}, }
addSessionsChangeListener: function(callback) { addSessionsChangeListener(callback) {
this.on(CHANGE_EVENT_SESSIONS, callback); this.on(CHANGE_EVENT_SESSIONS, callback);
}, }
removeSessionsChangeListener: function(callback) { removeSessionsChangeListener(callback) {
this.removeListener(CHANGE_EVENT_SESSIONS, callback); this.removeListener(CHANGE_EVENT_SESSIONS, callback);
}, }
emitAuditsChange: function() { emitAuditsChange() {
this.emit(CHANGE_EVENT_AUDITS); this.emit(CHANGE_EVENT_AUDITS);
}, }
addAuditsChangeListener: function(callback) { addAuditsChangeListener(callback) {
this.on(CHANGE_EVENT_AUDITS, callback); this.on(CHANGE_EVENT_AUDITS, callback);
}, }
removeAuditsChangeListener: function(callback) { removeAuditsChangeListener(callback) {
this.removeListener(CHANGE_EVENT_AUDITS, callback); this.removeListener(CHANGE_EVENT_AUDITS, callback);
}, }
emitTeamsChange: function() { emitTeamsChange() {
this.emit(CHANGE_EVENT_TEAMS); this.emit(CHANGE_EVENT_TEAMS);
}, }
addTeamsChangeListener: function(callback) { addTeamsChangeListener(callback) {
this.on(CHANGE_EVENT_TEAMS, callback); this.on(CHANGE_EVENT_TEAMS, callback);
}, }
removeTeamsChangeListener: function(callback) { removeTeamsChangeListener(callback) {
this.removeListener(CHANGE_EVENT_TEAMS, callback); this.removeListener(CHANGE_EVENT_TEAMS, callback);
}, }
emitStatusesChange: function() { emitStatusesChange() {
this.emit(CHANGE_EVENT_STATUSES); this.emit(CHANGE_EVENT_STATUSES);
}, }
addStatusesChangeListener: function(callback) { addStatusesChangeListener(callback) {
this.on(CHANGE_EVENT_STATUSES, callback); this.on(CHANGE_EVENT_STATUSES, callback);
}, }
removeStatusesChangeListener: function(callback) { removeStatusesChangeListener(callback) {
this.removeListener(CHANGE_EVENT_STATUSES, callback); this.removeListener(CHANGE_EVENT_STATUSES, callback);
}, }
setCurrentId: function(id) { setCurrentId(id) {
this.gCurrentId = id; this.gCurrentId = id;
if (id == null) { if (id == null) {
BrowserStore.removeGlobalItem('current_user_id'); BrowserStore.removeGlobalItem('current_user_id');
} else { } else {
BrowserStore.setGlobalItem('current_user_id', id); BrowserStore.setGlobalItem('current_user_id', id);
} }
}, }
getCurrentId: function(skipFetch) { getCurrentId(skipFetch) {
var currentId = this.gCurrentId; var currentId = this.gCurrentId;
if (currentId == null) { if (currentId == null) {
@@ -93,46 +142,45 @@ var UserStore = assign({}, EventEmitter.prototype, {
} }
return currentId; return currentId;
}, }
getCurrentUser: function() { getCurrentUser() {
if (this.getCurrentId() == null) { if (this.getCurrentId() == null) {
return null; return null;
} }
return this._getProfiles()[this.getCurrentId()]; return this.pGetProfiles()[this.getCurrentId()];
}, }
setCurrentUser: function(user) { setCurrentUser(user) {
this.setCurrentId(user.id); this.setCurrentId(user.id);
this.saveProfile(user); this.saveProfile(user);
}, }
getLastEmail: function() { getLastEmail() {
return BrowserStore.getItem('last_email', ''); return BrowserStore.getItem('last_email', '');
}, }
setLastEmail: function(email) { setLastEmail(email) {
BrowserStore.setItem('last_email', email); BrowserStore.setItem('last_email', email);
}, }
removeCurrentUser: function() { removeCurrentUser() {
this.setCurrentId(null); this.setCurrentId(null);
}, }
hasProfile: function(userId) { hasProfile(userId) {
return this._getProfiles()[userId] != null; return this.pGetProfiles()[userId] != null;
}, }
getProfile: function(userId) { getProfile(userId) {
return this._getProfiles()[userId]; return this.pGetProfiles()[userId];
}, }
getProfileByUsername: function(username) { getProfileByUsername(username) {
return this._getProfilesUsernameMap()[username]; return this.pGetProfilesUsernameMap()[username];
}, }
getProfilesUsernameMap: function() { getProfilesUsernameMap() {
return this._getProfilesUsernameMap(); return this.pGetProfilesUsernameMap();
}, }
getProfiles: function() { getProfiles() {
return this.pGetProfiles();
return this._getProfiles(); }
}, getActiveOnlyProfiles() {
getActiveOnlyProfiles: function() {
var active = {}; var active = {};
var current = this._getProfiles(); var current = this.pGetProfiles();
for (var key in current) { for (var key in current) {
if (current[key].delete_at === 0) { if (current[key].delete_at === 0) {
@@ -141,45 +189,47 @@ var UserStore = assign({}, EventEmitter.prototype, {
} }
return active; return active;
}, }
saveProfile: function(profile) { saveProfile(profile) {
var ps = this._getProfiles(); var ps = this.pGetProfiles();
ps[profile.id] = profile; ps[profile.id] = profile;
this._storeProfiles(ps); this.pStoreProfiles(ps);
}, }
_storeProfiles: function(profiles) { pStoreProfiles(profiles) {
BrowserStore.setItem('profiles', profiles); BrowserStore.setItem('profiles', profiles);
var profileUsernameMap = {}; var profileUsernameMap = {};
for (var id in profiles) { for (var id in profiles) {
profileUsernameMap[profiles[id].username] = profiles[id]; if (profiles.hasOwnProperty(id)) {
profileUsernameMap[profiles[id].username] = profiles[id];
}
} }
BrowserStore.setItem('profileUsernameMap', profileUsernameMap); BrowserStore.setItem('profileUsernameMap', profileUsernameMap);
}, }
_getProfiles: function() { pGetProfiles() {
return BrowserStore.getItem('profiles', {}); return BrowserStore.getItem('profiles', {});
}, }
_getProfilesUsernameMap: function() { pGetProfilesUsernameMap() {
return BrowserStore.getItem('profileUsernameMap', {}); return BrowserStore.getItem('profileUsernameMap', {});
}, }
setSessions: function(sessions) { setSessions(sessions) {
BrowserStore.setItem('sessions', sessions); BrowserStore.setItem('sessions', sessions);
}, }
getSessions: function() { getSessions() {
return BrowserStore.getItem('sessions', {loading: true}); return BrowserStore.getItem('sessions', {loading: true});
}, }
setAudits: function(audits) { setAudits(audits) {
BrowserStore.setItem('audits', audits); BrowserStore.setItem('audits', audits);
}, }
getAudits: function() { getAudits() {
return BrowserStore.getItem('audits', {loading: true}); return BrowserStore.getItem('audits', {loading: true});
}, }
setTeams: function(teams) { setTeams(teams) {
BrowserStore.setItem('teams', teams); BrowserStore.setItem('teams', teams);
}, }
getTeams: function() { getTeams() {
return BrowserStore.getItem('teams', []); return BrowserStore.getItem('teams', []);
}, }
getCurrentMentionKeys: function() { getCurrentMentionKeys() {
var user = this.getCurrentUser(); var user = this.getCurrentUser();
var keys = []; var keys = [];
@@ -205,74 +255,76 @@ var UserStore = assign({}, EventEmitter.prototype, {
} }
return keys; return keys;
}, }
getLastVersion: function() { getLastVersion() {
return BrowserStore.getItem('last_version', ''); return BrowserStore.getItem('last_version', '');
}, }
setLastVersion: function(version) { setLastVersion(version) {
BrowserStore.setItem('last_version', version); BrowserStore.setItem('last_version', version);
}, }
setStatuses: function(statuses) { setStatuses(statuses) {
this._setStatuses(statuses); this.pSetStatuses(statuses);
this.emitStatusesChange(); this.emitStatusesChange();
}, }
_setStatuses: function(statuses) { pSetStatuses(statuses) {
BrowserStore.setItem('statuses', statuses); BrowserStore.setItem('statuses', statuses);
}, }
setStatus: function(userId, status) { setStatus(userId, status) {
var statuses = this.getStatuses(); var statuses = this.getStatuses();
statuses[userId] = status; statuses[userId] = status;
this._setStatuses(statuses); this.pSetStatuses(statuses);
this.emitStatusesChange(); this.emitStatusesChange();
}, }
getStatuses: function() { getStatuses() {
return BrowserStore.getItem('statuses', {}); return BrowserStore.getItem('statuses', {});
}, }
getStatus: function(id) { getStatus(id) {
return this.getStatuses()[id]; return this.getStatuses()[id];
} }
}); }
UserStore.dispatchToken = AppDispatcher.register(function(payload) { var UserStore = new UserStoreClass();
UserStore.setMaxListeners(0);
UserStore.dispatchToken = AppDispatcher.register(function registry(payload) {
var action = payload.action; var action = payload.action;
switch (action.type) { switch (action.type) {
case ActionTypes.RECIEVED_PROFILES: case ActionTypes.RECIEVED_PROFILES:
for (var id in action.profiles) { for (var id in action.profiles) {
// profiles can have incomplete data, so don't overwrite current user // profiles can have incomplete data, so don't overwrite current user
if (id === UserStore.getCurrentId()) { if (id === UserStore.getCurrentId()) {
continue; continue;
}
var profile = action.profiles[id];
UserStore.saveProfile(profile);
UserStore.emitChange(profile.id);
} }
break; var profile = action.profiles[id];
case ActionTypes.RECIEVED_ME: UserStore.saveProfile(profile);
UserStore.setCurrentUser(action.me); UserStore.emitChange(profile.id);
UserStore.emitChange(action.me.id); }
break; break;
case ActionTypes.RECIEVED_SESSIONS: case ActionTypes.RECIEVED_ME:
UserStore.setSessions(action.sessions); UserStore.setCurrentUser(action.me);
UserStore.emitSessionsChange(); UserStore.emitChange(action.me.id);
break; break;
case ActionTypes.RECIEVED_AUDITS: case ActionTypes.RECIEVED_SESSIONS:
UserStore.setAudits(action.audits); UserStore.setSessions(action.sessions);
UserStore.emitAuditsChange(); UserStore.emitSessionsChange();
break; break;
case ActionTypes.RECIEVED_TEAMS: case ActionTypes.RECIEVED_AUDITS:
UserStore.setTeams(action.teams); UserStore.setAudits(action.audits);
UserStore.emitTeamsChange(); UserStore.emitAuditsChange();
break; break;
case ActionTypes.RECIEVED_STATUSES: case ActionTypes.RECIEVED_TEAMS:
UserStore._setStatuses(action.statuses); UserStore.setTeams(action.teams);
UserStore.emitStatusesChange(); UserStore.emitTeamsChange();
break; break;
case ActionTypes.RECIEVED_STATUSES:
UserStore.pSetStatuses(action.statuses);
UserStore.emitStatusesChange();
break;
default: default:
} }
}); });
UserStore.setMaxListeners(0);
global.window.UserStore = UserStore; global.window.UserStore = UserStore;
module.exports = UserStore; export default UserStore;