diff --git a/client/src/index.html b/client/src/index.html index 2987871c..8f3f12dc 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -1,8 +1,13 @@ + + + IRC + + diff --git a/client/src/js/actions/server.js b/client/src/js/actions/server.js index 25926b8f..2c42750d 100644 --- a/client/src/js/actions/server.js +++ b/client/src/js/actions/server.js @@ -9,13 +9,15 @@ var serverActions = Reflux.createActions([ 'load' ]); -serverActions.connect.preEmit = function(server, nick, username, tls, name) { +serverActions.connect.preEmit = function(server, nick, opts) { socket.send('connect', { server: server, nick: nick, - username: username, - tls: tls || false, - name: name || server + username: opts.username || nick, + password: opts.password, + realname: opts.realname || nick, + tls: opts.tls || false, + name: opts.name || server }); }; diff --git a/client/src/js/components/Connect.jsx b/client/src/js/components/Connect.jsx index d34ea21f..257e2f10 100644 --- a/client/src/js/components/Connect.jsx +++ b/client/src/js/components/Connect.jsx @@ -5,18 +5,31 @@ var serverActions = require('../actions/server'); var channelActions = require('../actions/channel'); var Connect = React.createClass({ + getInitialState: function() { + return { + showOptionals: false + }; + }, + handleSubmit: function(e) { e.preventDefault(); - var name = e.target.name.value.trim(); var address = e.target.address.value.trim(); - var ssl = e.target.ssl.checked; var nick = e.target.nick.value.trim(); - var username = e.target.username.value.trim(); var channels = _.filter(_.map(e.target.channels.value.split(','), _.trim)); + var opts = { + name: e.target.name.value.trim(), + ssl: e.target.ssl.checked + }; - if (address.indexOf('.') > 0 && nick && username) { - serverActions.connect(address, nick, username, ssl, name); + if (this.state.showOptionals) { + opts.realname = e.target.realname.value.trim(); + opts.username = e.target.username.value.trim(); + opts.password = e.target.password.value.trim(); + } + + if (address.indexOf('.') > 0 && nick) { + serverActions.connect(address, nick, opts); if (channels.length > 0) { channelActions.join(channels, address); @@ -24,17 +37,36 @@ var Connect = React.createClass({ } }, + handleShowClick: function() { + this.setState({ showOptionals: !this.state.showOptionals}); + }, + render: function() { + var optionals = null; + + if (this.state.showOptionals) { + optionals = ( +
+ + + +
+ ); + } + return (

Connect

- - - + + {optionals} +

+ + +

diff --git a/client/src/js/components/MessageBox.jsx b/client/src/js/components/MessageBox.jsx index 36f5235d..ac5b2c3f 100644 --- a/client/src/js/components/MessageBox.jsx +++ b/client/src/js/components/MessageBox.jsx @@ -34,6 +34,7 @@ var MessageBox = React.createClass({ render: function() { var tab = this.state.selectedTab; var dest = tab.channel || tab.server; + var style = {} var messages = _.map(messageStore.getMessages(tab.server, dest), function(message) { var messageClass = 'message'; @@ -50,9 +51,13 @@ var MessageBox = React.createClass({

); }); - + + if (!tab.channel || tab.channel[0] !== '#') { + style.right = 0; + } + return ( -
{messages}
+
{messages}
); } }); diff --git a/client/src/js/components/TabList.jsx b/client/src/js/components/TabList.jsx index 4dca37b0..45b00381 100644 --- a/client/src/js/components/TabList.jsx +++ b/client/src/js/components/TabList.jsx @@ -71,7 +71,7 @@ var TabList = React.createClass({ {tabs}
- +
); diff --git a/client/src/style.css b/client/src/style.css index 7f52987f..6e793d03 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -12,7 +12,6 @@ body { input { font: 16px Roboto, sans-serif; border: none; - border-top: 1px solid #DDD; outline: none; } @@ -81,12 +80,17 @@ p { text-align: center; } -.side-buttons button { - background: #333; - color: #FFF; +.side-buttons i { + color: #999; margin: 5px; - height: 40px; - width: 100px; + line-height: 40px; + width: 40px; + cursor: pointer; + font-size: 20px; +} + +.side-buttons i:hover { + color: #FFF; } .connect { @@ -136,12 +140,25 @@ p { .connect-form input[type="checkbox"] { display: inline-block; - margin: 15px 10px; - margin-left: 0; - vertical-align: center; + margin-right: 10px; + vertical-align: middle; +} + +.connect-form i { + float: right; + cursor: pointer; + color: #999; + padding: 10px 5px; + font-size: 24px; +} + +.connect-form i:hover { + color: #000; } .connect-form label { + display: inline-block; + padding: 10px 0; color: #333; } @@ -235,6 +252,7 @@ p { width: 100%; height: 100%; padding: 15px; + border-top: 1px solid #DDD; } .userlist { diff --git a/irc.go b/irc.go index 53159186..d04f91d4 100644 --- a/irc.go +++ b/irc.go @@ -67,6 +67,7 @@ type IRC struct { Host string TLS bool TLSConfig *tls.Config + Password string Username string Realname string } @@ -117,6 +118,9 @@ func (i *IRC) Connect(address string) error { i.reader = bufio.NewReader(i.conn) + if i.Password != "" { + i.Pass(i.Password) + } i.Nick(i.nick) i.User(i.Username, i.Realname) @@ -143,6 +147,22 @@ func (i *IRC) User(username, realname string) { i.writef("USER %s 0 * :%s", username, realname) } +func (i *IRC) Oper(name, password string) { + i.Write("OPER " + name + " " + password) +} + +func (i *IRC) Mode(target, modes, params string) { + i.Write(strings.TrimRight("MODE "+target+" "+modes+" "+params, " ")) +} + +func (i *IRC) Quit() { + go func() { + i.ready.Wait() + i.write("QUIT") + i.conn.Close() + }() +} + func (i *IRC) Join(channels ...string) { i.Write("JOIN " + strings.Join(channels, ",")) } @@ -151,6 +171,18 @@ func (i *IRC) Part(channels ...string) { i.Write("PART " + strings.Join(channels, ",")) } +func (i *IRC) Topic(channel string) { + i.Write("TOPIC " + channel) +} + +func (i *IRC) Invite(nick, channel string) { + i.Write("INVITE " + nick + " " + channel) +} + +func (i *IRC) Kick(channel string, users ...string) { + i.Write("KICK " + channel + " " + strings.Join(users, ",")) +} + func (i *IRC) Privmsg(target, msg string) { i.Writef("PRIVMSG %s :%s", target, msg) } @@ -159,22 +191,10 @@ func (i *IRC) Notice(target, msg string) { i.Writef("NOTICE %s :%s", target, msg) } -func (i *IRC) Topic(channel string) { - i.Write("TOPIC " + channel) -} - func (i *IRC) Whois(nick string) { i.Write("WHOIS " + nick) } -func (i *IRC) Quit() { - go func() { - i.ready.Wait() - i.write("QUIT") - i.conn.Close() - }() -} - func (i *IRC) GetNick() string { i.nickLock.Lock() defer i.nickLock.Unlock() diff --git a/json_types.go b/json_types.go index d7001dcc..76559fd0 100644 --- a/json_types.go +++ b/json_types.go @@ -15,11 +15,13 @@ type WSResponse struct { } type Connect struct { + Name string `json:"name"` Server string `json:"server"` TLS bool `json:"tls"` - Name string `json:"name,omitempty"` + Password string `json:"password"` Nick string `json:"nick"` Username string `json:"username"` + Realname string `json:"realname"` } type Nick struct { diff --git a/storage/user.go b/storage/user.go index 6d28d12b..2b5d4050 100644 --- a/storage/user.go +++ b/storage/user.go @@ -8,9 +8,10 @@ import ( ) type Server struct { + Name string `json:"name"` Address string `json:"address"` TLS bool `json:"tls"` - Name string `json:"name"` + Password string `json:"password,omitempty"` Nick string `json:"nick"` Username string `json:"username"` Realname string `json:"realname"` diff --git a/websocket_handler.go b/websocket_handler.go index 2d9a90cf..1dc18751 100644 --- a/websocket_handler.go +++ b/websocket_handler.go @@ -75,6 +75,8 @@ func handleWS(ws *websocket.Conn) { irc := NewIRC(data.Nick, data.Username) irc.TLS = data.TLS + irc.Password = data.Password + irc.Realname = data.Realname if err := irc.Connect(data.Server); err != nil { session.sendError(err, irc.Host) @@ -85,11 +87,13 @@ func handleWS(ws *websocket.Conn) { go handleMessages(irc, session) session.user.AddServer(storage.Server{ + Name: data.Name, Address: irc.Host, TLS: data.TLS, - Name: data.Name, + Password: data.Password, Nick: data.Nick, Username: data.Username, + Realname: data.Realname, }) } } else {