diff --git a/client/css/style.css b/client/css/style.css index cb3d324a..b2defc9a 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -222,6 +222,9 @@ button { #sidebar .chan.channel:before, #chat .channel .title:before { content: "\f0f6"; /* http://fontawesome.io/icon/file-text-o/ */ } +#sidebar .chan.special:before, +#chat .channel .title:before { content: "\f03a"; /* http://fontawesome.io/icon/list/ */ } + #footer .sign-in:before { content: "\f023"; /* http://fontawesome.io/icon/lock/ */ } #footer .connect:before { content: "\f067"; /* http://fontawesome.io/icon/plus/ */ } #footer .settings:before { content: "\f013"; /* http://fontawesome.io/icon/cog/ */ } @@ -750,6 +753,10 @@ button { right: 180px; } +#chat .special { + bottom: -47px; +} + #viewport.rt .chat { right: 0; } @@ -769,11 +776,13 @@ button { } #chat .lobby .chat, +#chat .special .chat, #chat .query .chat { right: 0; } #chat .lobby .sidebar, +#chat .special .sidebar, #chat .query .sidebar { display: none; } @@ -876,6 +885,11 @@ button { } #loading a, +#chat .special .time, +#chat .special .from { + display: none; +} + #chat a { color: #50a656; } @@ -941,6 +955,46 @@ button { overflow: hidden; } +#chat .msg.channel_list_loading .text { + color: #999; + font-style: italic; + padding-left: 20px; +} + +#chat .msg.channel_list_truncated .text { + color: #f00; + padding-left: 20px; +} + +#chat table.channel-list { + margin: 5px 10px; + width: calc(100% - 30px); +} + +#chat table.channel-list th, +#chat table.channel-list td { + padding: 5px; + vertical-align: top; + border-bottom: #eee 1px solid; +} + +#chat table.channel-list .channel, +#chat table.channel-list .topic { + text-align: left; +} + +#chat table.channel-list .users { + text-align: center; +} + +#chat table.channel-list td.channel .inline-channel { + color: #428bca; +} + +#chat table.channel-list td { + color: #555; +} + #chat.hide-join .join, #chat.hide-mode .mode, #chat.hide-motd .motd, diff --git a/client/js/lounge.js b/client/js/lounge.js index b537541a..b8008858 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -243,6 +243,7 @@ $(function() { "action", "whois", "ctcp", + "channel_list", ].indexOf(type) !== -1) { data.msg.template = "actions/" + type; template = "msg_action"; @@ -601,7 +602,7 @@ $(function() { output += render("contextmenu_divider"); output += render("contextmenu_item", { class: "close", - text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("query") ? "Close" : "Leave", + text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("channel") ? "Leave" : "Close", data: target.data("target") }); } diff --git a/client/views/actions/channel_list.tpl b/client/views/actions/channel_list.tpl new file mode 100644 index 00000000..8fab73d0 --- /dev/null +++ b/client/views/actions/channel_list.tpl @@ -0,0 +1,18 @@ + + + + + + + + + + {{#each channels}} + + + + + + {{/each}} + +
ChannelUsersTopic
{{{parse channel}}}{{num_users}}{{{parse topic}}}
diff --git a/src/client.js b/src/client.js index e682dfad..28c4da3d 100644 --- a/src/client.js +++ b/src/client.js @@ -29,6 +29,7 @@ var events = [ "quit", "topic", "welcome", + "list", "whois" ]; var inputs = [ diff --git a/src/models/chan.js b/src/models/chan.js index e64ac8ac..750e798a 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -6,7 +6,8 @@ module.exports = Chan; Chan.Type = { CHANNEL: "channel", LOBBY: "lobby", - QUERY: "query" + QUERY: "query", + SPECIAL: "special", }; var id = 0; diff --git a/src/plugins/irc-events/list.js b/src/plugins/irc-events/list.js new file mode 100644 index 00000000..66c482a1 --- /dev/null +++ b/src/plugins/irc-events/list.js @@ -0,0 +1,57 @@ +var Chan = require("../../models/chan"); +var Msg = require("../../models/msg"); + +module.exports = function(irc, network) { + var client = this; + var chanCache = {}; + var MAX_CHANS = 1000; + + irc.on("channel list start", function() { + chanCache[network.id] = []; + + updateListStatus(new Msg({ + text: "Loading channel list, this can take a moment...", + type: "channel_list_loading" + })); + }); + + irc.on("channel list", function(channels) { + Array.prototype.push.apply(chanCache[network.id], channels); + }); + + irc.on("channel list end", function() { + updateListStatus(new Msg({ + type: "channel_list", + channels: chanCache[network.id].slice(0, MAX_CHANS) + })); + + if (chanCache[network.id].length > MAX_CHANS) { + updateListStatus(new Msg({ + type: "channel_list_truncated", + text: "Channel list is too large: truncated to " + MAX_CHANS + " channels." + })); + } + + chanCache[network.id] = []; + }); + + function updateListStatus(msg) { + var chan = network.getChannel("Channel List"); + if (typeof chan === "undefined") { + chan = new Chan({ + type: Chan.Type.SPECIAL, + name: "Channel List" + }); + network.channels.push(chan); + client.emit("join", { + network: network.id, + chan: chan + }); + } + + client.emit("msg", { + chan: chan.id, + msg: msg + }); + } +};