]> git.zarvox.org Git - imoo.git/commitdiff
frontend: many things
authorDrew Fisher <drew.m.fisher@gmail.com>
Sat, 17 May 2014 07:20:15 +0000 (00:20 -0700)
committerDrew Fisher <drew.m.fisher@gmail.com>
Sun, 18 May 2014 05:26:03 +0000 (22:26 -0700)
- Allow switching between tabs with click
- Sending messages works and appends to chat log
- Make IMs received propagate to conversation tabs

reactornado/dispatcher.js
reactornado/widgets.js

index 46677579a2b627dc32a1cb1e51c114e692d1f019..b22b0d6d1e7d31a356426ffcb66957f2e00a31c7 100644 (file)
@@ -53,12 +53,7 @@ var Dispatcher = {
         }
 
         if (method == "recv_im") {
-            window.conversations[bid].visible = true;
-            window.conversations[bid].messages.push({
-                message: params.message,
-                timestamp: params.timestamp,
-                sender: "them"
-            });
+            window.reactor.refs.conversations.handleRecvIm(params);
         } else if (method == "buddy_typing_state") {
             window.conversations[bid].type_state = params.state;
         }
index a1dafc4ca9cd58edc570b0f7c68de84d9ad8f20e..cb3e32507192bd01cd2e07b5e5c69126aee95a46 100644 (file)
@@ -89,7 +89,8 @@ var ConversationTab = React.createClass({
         if (this.props.active) {
             classname = classname + " conv-active";
         }
-        return <li className={classname}>{this.props.buddy}</li>;
+        var label = this.props.buddy.display_name;
+        return <li className={classname} onClick={this.props.onClick}>{this.props.buddy.display_name}</li>;
     }
 });
 
@@ -97,7 +98,12 @@ var ConversationTabBar = React.createClass({
     render: function() {
         var tabs = [];
         for (var i = 0 ; i < this.props.tabs.length ; i++) {
-            tabs.push(ConversationTab(this.props.tabs[i]));
+            tabs.push(ConversationTab({
+                key: "tab" + i,
+                onClick: this.props.onTabSwitch.bind(null, i),
+                buddy: this.props.tabs[i],
+                active: (this.props.focused_tab == i)
+            }));
         }
         return <ul className="conv-tabbar">{ tabs }</ul>;
     }
@@ -112,7 +118,7 @@ var ConversationTextEntry = React.createClass({
         if (e && e.keyCode == 13) {
             // TODO: do this only if Shift not currently pressed? (awkward...)
             e.preventDefault();
-            // TODO: do something with this.state.text - window.Dispatcher.send_im?
+            this.props.onSendMessage(this.state.text);
             this.setState(this.getInitialState());
         }
         // TODO: close window when Escape pressed?
@@ -128,36 +134,117 @@ var ConversationTabContent = React.createClass({
         var messages = [];
         for (var i = 0 ; i < this.props.messages.length ; i++) {
             var msg = this.props.messages[i];
+            var sender = ((msg.direction == "outgoing") ? "me" : this.props.buddy.display_name) + ":";
+            var senderclass = "sender " + msg.direction;
             var msgclass = "msg " + msg.direction;
-            messages.push(<p>
+            var msgkey = "msg" + i;
+            messages.push(<p key={msgkey}>
                 <span className="timestamp">{msg.timestamp}</span>
-                <span className="sender">{msg.sender}</span>
+                <span className={senderclass}>{sender}</span>
                 <span className={msgclass}>{msg.text}</span>
                 </p>);
         }
         return <div className="conv-tab-content">
                 <div className="conv-log">{ messages }</div>
-                <ConversationTextEntry />
+                <ConversationTextEntry onSendMessage={this.props.onSendMessage}/>
                </div>;
     }
 });
 
 var Conversations = React.createClass({
+    getInitialState: function() {
+        return {
+            focused_tab: -1,  // this is zero-indexed, so -1 means "no tab"
+            conversations: []
+        };
+    },
+    handleTabSwitch: function(focusedTabIndex) {
+        console.log("Switching to tab " + focusedTabIndex);
+        this.setState({ focused_tab: focusedTabIndex,
+                        conversations: this.state.conversations
+        });
+    },
+    handleSendMessage: function(message) {
+        // 1) Dispatch IM to buddy
+        var active_convs = this.state.conversations.filter(function(obj) { return obj.visible; });
+        var conv = active_convs[this.state.focused_tab];
+        var contact = window.blist[conv.buddy.id];
+        var params = {
+            proto: contact.proto,
+            account: contact.account,
+            buddy: contact.buddy,
+            message: message
+        };
+        console.log("sending im:", params);
+        window.Dispatcher.send_msg("conversations", "send_im", params);
+        // 2) Append IM to sent messages.  Later, I might want to hold off on this until I get the ack
+        //    from the server, but for now, this will give the most responsive UI.
+        var now = new Date();
+        // TODO: extract this datetime-formatting thing to some other module
+        // TODO: zero-pad these for values < 10
+        var timestamp = "" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
+        conv.messages.push({
+            direction: "outgoing",
+            timestamp: timestamp,
+            text: message
+        });
+        // It's awkward trying to deep copy the entire messages array.  I am a
+        // bad person and am mutating this.state directly, so when done
+        // changing state, call forceUpdate()
+        this.forceUpdate();
+    },
+    getConversation: function(proto, account, buddy) {
+        // Helper function to get a particular entry in the conversations list.
+        // If a conversation already exists, it finds it.
+        // Otherwise, it creates a new one for the specified buddy.
+        var bid = proto + ":" + account + ":" + buddy;
+        for (var i = 0 ; i < this.state.conversations.length ; i++) {
+            if (this.state.conversations[i].buddy.id == bid) {
+                return this.state.conversations[i];
+            }
+        }
+        // None found, construct a new one.
+        var entry = {
+                visible: true,
+                buddy: {id: bid, display_name: buddy},
+                messages: []
+        };
+        this.state.conversations.push(entry);
+        this.forceUpdate();
+        return entry;
+    },
+    handleRecvIm: function(params) {
+        var bid = params.proto + ":" + params.account + ":" + params.buddy;
+        if (this.state.conversations[bid] === undefined) {
+            this.state.conversations[bid] = {
+                visible: true,
+                buddy: {id: bid, display_name: params.buddy},
+                messages: []
+            };
+        }
+        this.getConversation(params.proto, params.account, params.buddy).messages.push({
+            direction: "incoming",
+            timestamp: params.timestamp,
+            text: params.message
+        });
+        this.forceUpdate();
+    },
     render: function() {
-        // TODO: pull data from this.state and provide a method to handle
-        // dispatcher-sent messages
-        var conv_tabs = [ {"active": true, "buddy": "Drew Fisher"},
-                          {"active": false, "buddy": "Kate Harrison"},
-                          {"active": false, "buddy": "Matt Mullins"}
-               ];
-        var active_pane_messages = [ {"direction": "incoming",
-                               "sender": "nobody",
-                               "timestamp": "10:41",
-                               "text": "this is a test message"
-                              } ];
+        var active_convs = this.state.conversations.filter(function(obj) { return obj.visible; });
+
+        // conv_tabs is just an Array of strings with the tab title
+        var conv_tabs = active_convs.map(function(obj) { return obj.buddy; });
+
+        var active_pane_messages = [];
+        var active_buddy = null;
+        if (this.state.focused_tab >= 0 && this.state.focused_tab < active_convs.length) {
+            active_pane_messages = active_convs[this.state.focused_tab].messages;
+            active_buddy = active_convs[this.state.focused_tab].buddy;
+        }
+
         return <div className="conversations">
-                <ConversationTabBar tabs={conv_tabs} />
-                <ConversationTabContent messages={active_pane_messages} />
+                <ConversationTabBar onTabSwitch={this.handleTabSwitch} focused_tab={this.state.focused_tab} tabs={conv_tabs} />
+                <ConversationTabContent onSendMessage={this.handleSendMessage} buddy={active_buddy} messages={active_pane_messages} />
                </div>;
     }
 });