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 (
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 {