Initial pass on MessageBox rendered with React Infinite and js line wrapping, fix line wrapping bug, disable browser line wrapping

This commit is contained in:
khlieng 2015-02-15 23:27:00 +01:00
parent 3042ed5ec6
commit 6e223c172f
6 changed files with 128 additions and 24 deletions

View File

@ -8,7 +8,8 @@ var messageActions = Reflux.createActions([
'add', 'add',
'broadcast', 'broadcast',
'inform', 'inform',
'command' 'command',
'setWrapWidth'
]); ]);
messageActions.send.preEmit = function(message, to, server) { messageActions.send.preEmit = function(message, to, server) {

View File

@ -1,42 +1,70 @@
var React = require('react'); var React = require('react');
var Reflux = require('reflux'); var Reflux = require('reflux');
var _ = require('lodash'); var _ = require('lodash');
var Infinite = require('react-infinite');
var util = require('../util'); var util = require('../util');
var messageStore = require('../stores/message'); var messageStore = require('../stores/message');
var messageLineStore = require('../stores/messageLine');
var selectedTabStore = require('../stores/selectedTab'); var selectedTabStore = require('../stores/selectedTab');
var messageActions = require('../actions/message');
var MessageBox = React.createClass({ var MessageBox = React.createClass({
mixins: [ mixins: [
Reflux.connect(messageStore, 'messages'), Reflux.connect(messageLineStore, 'lines'),
Reflux.connect(selectedTabStore, 'selectedTab') Reflux.connect(selectedTabStore, 'selectedTab')
], ],
getInitialState: function() { getInitialState: function() {
return { return {
messages: messageStore.getState(), lines: messageLineStore.getState(),
selectedTab: selectedTabStore.getState() selectedTab: selectedTabStore.getState(),
height: window.innerHeight - 100
}; };
}, },
componentDidMount: function() {
window.addEventListener('resize', this.handleResize);
},
componentWillUnmount: function() {
window.removeEventListener('resize', this.handleResize);
},
componentWillUpdate: function() { componentWillUpdate: function() {
var el = this.getDOMNode(); var el = this.refs.list.getDOMNode();
this.autoScroll = el.scrollTop + el.offsetHeight === el.scrollHeight; this.autoScroll = el.scrollTop + el.offsetHeight === el.scrollHeight;
}, },
componentDidUpdate: function() { componentDidUpdate: function() {
this.updateWidth();
if (this.autoScroll) { if (this.autoScroll) {
var el = this.getDOMNode(); var el = this.refs.list.getDOMNode();
el.scrollTop = el.scrollHeight; el.scrollTop = el.scrollHeight;
} }
}, },
handleResize: function() {
this.updateWidth();
this.setState({ height: window.innerHeight - 100 });
},
updateWidth: function() {
var width = this.refs.list.getDOMNode().firstChild.offsetWidth;
if (this.width !== width) {
this.width = width;
messageActions.setWrapWidth(width);
}
},
render: function() { render: function() {
var tab = this.state.selectedTab; var tab = this.state.selectedTab;
var dest = tab.channel || tab.server; var dest = tab.channel || tab.server;
var style = {} var style = {}
var messages = _.map(messageStore.getMessages(tab.server, dest), function(message) { /*var messages = _.map(messageStore.getMessages(tab.server, dest), function(message) {
var messageClass = 'message'; var messageClass = 'message';
if (message.type) { if (message.type) {
@ -46,18 +74,26 @@ var MessageBox = React.createClass({
return ( return (
<p className={messageClass}> <p className={messageClass}>
<span className="message-time">{util.timestamp(message.time)}</span> <span className="message-time">{util.timestamp(message.time)}</span>
{ message.from ? <span className="message-sender">{message.from}</span> : null } { message.from ? <span className="message-sender"> {message.from}</span> : null }
{message.message} {' ' + message.message}
</p> </p>
); );
}); });*/
if (!tab.channel || tab.channel[0] !== '#') { if (!tab.channel || tab.channel[0] !== '#') {
style.right = 0; style.right = 0;
} }
var lines = _.map(this.state.lines, function(line) {
return <p className="message">{line}</p>;
});
return ( return (
<div className="messagebox" style={style}>{messages}</div> <div className="messagebox" style={style}>
<Infinite ref="list" containerHeight={this.state.height} elementHeight={24}>
{lines}
</Infinite>
</div>
); );
} }
}); });

View File

@ -0,0 +1,63 @@
var Reflux = require('reflux');
var _ = require('lodash');
var util = require('../util');
var messageStore = require('./message');
var selectedTabStore = require('./selectedTab');
var messageActions = require('../actions/message');
var width = window.innerWidth;
var charWidth = util.stringWidth(' ', '16px Ubuntu Mono');
var tab = selectedTabStore.getState();
var messages;
var lines;
wrap();
function wrap() {
messages = messageStore.getMessages(tab.server, tab.channel || tab.server);
lines = util.wrap(_.map(messages, function(message) {
var line = util.timestamp(message.time);
if (message.from) {
line += ' ' + message.from;
}
line += ' ' + message.message;
return line;
}), width, charWidth);
}
var messageLineStore = Reflux.createStore({
init: function() {
this.listenTo(messageActions.setWrapWidth, 'setWrapWidth');
this.listenTo(messageStore, 'messagesChanged');
this.listenTo(selectedTabStore, 'selectedTabChanged');
},
setWrapWidth: function(w) {
width = w;
wrap();
this.trigger(lines);
},
messagesChanged: function() {
wrap();
this.trigger(lines);
},
selectedTabChanged: function(selectedTab) {
tab = selectedTab;
wrap();
this.trigger(lines);
},
getState: function() {
return lines;
}
});
module.exports = messageLineStore;

View File

@ -55,8 +55,8 @@ var selectedTabStore = Reflux.createStore({
userAdded: function(user, server, channel) { userAdded: function(user, server, channel) {
// Update the selected channel incase the casing is different // Update the selected channel incase the casing is different
if (server === selectedTab.server && if (server === selectedTab.server &&
channel.toLowerCase() === selectedTab.channel.toLowerCase() && user === serverStore.getNick(server) &&
user === serverStore.getNick(server)) { channel.toLowerCase() === selectedTab.channel.toLowerCase()) {
selectedTab.channel = channel; selectedTab.channel = channel;
selectedTab.name = channel; selectedTab.name = channel;
this.trigger(selectedTab); this.trigger(selectedTab);

View File

@ -37,13 +37,12 @@ exports.wrap = function(lines, width, charWidth) {
if (wordCount !== 1) { if (wordCount !== 1) {
wrapped.push(line); wrapped.push(line);
line = word;
lineWidth = word.length * charWidth;
wordCount = 1;
if (i !== wlen - 1) { if (i !== wlen - 1) {
line += ' '; line = word + ' ';
lineWidth += charWidth; lineWidth = (word.length + 1) * charWidth;
wordCount = 1;
} else {
wrapped.push(word);
} }
} else { } else {
wrapped.push(word); wrapped.push(word);

View File

@ -207,19 +207,24 @@ p {
top: 50px; top: 50px;
bottom: 50px; bottom: 50px;
right: 200px; right: 200px;
padding: 15px; /*padding: 15px;*/
overflow: auto;
z-index: 1; z-index: 1;
} }
.messagebox > div {
padding: 10px 15px;
overflow: auto !important;
}
.message { .message {
margin-bottom: 5px; white-space: nowrap;
/*margin-bottom: 5px;
padding-left: 55px; padding-left: 55px;
text-indent: -55px; text-indent: -55px;*/
} }
.message span { .message span {
margin-right: 15px; /*margin-right: 15px;*/
} }
.message-info { .message-info {