Added window management
This commit is contained in:
parent
a1d5f52875
commit
cb663777b4
|
@ -0,0 +1,117 @@
|
|||
/*!
|
||||
* jQuery Cookie Plugin v1.4.1
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2013 Klaus Hartl
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// CommonJS
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
|
||||
var pluses = /\+/g;
|
||||
|
||||
function encode(s) {
|
||||
return config.raw ? s : encodeURIComponent(s);
|
||||
}
|
||||
|
||||
function decode(s) {
|
||||
return config.raw ? s : decodeURIComponent(s);
|
||||
}
|
||||
|
||||
function stringifyCookieValue(value) {
|
||||
return encode(config.json ? JSON.stringify(value) : String(value));
|
||||
}
|
||||
|
||||
function parseCookieValue(s) {
|
||||
if (s.indexOf('"') === 0) {
|
||||
// This is a quoted cookie as according to RFC2068, unescape...
|
||||
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
try {
|
||||
// Replace server-side written pluses with spaces.
|
||||
// If we can't decode the cookie, ignore it, it's unusable.
|
||||
// If we can't parse the cookie, ignore it, it's unusable.
|
||||
s = decodeURIComponent(s.replace(pluses, ' '));
|
||||
return config.json ? JSON.parse(s) : s;
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function read(s, converter) {
|
||||
var value = config.raw ? s : parseCookieValue(s);
|
||||
return $.isFunction(converter) ? converter(value) : value;
|
||||
}
|
||||
|
||||
var config = $.cookie = function (key, value, options) {
|
||||
|
||||
// Write
|
||||
|
||||
if (value !== undefined && !$.isFunction(value)) {
|
||||
options = $.extend({}, config.defaults, options);
|
||||
|
||||
if (typeof options.expires === 'number') {
|
||||
var days = options.expires, t = options.expires = new Date();
|
||||
t.setTime(+t + days * 864e+5);
|
||||
}
|
||||
|
||||
return (document.cookie = [
|
||||
encode(key), '=', stringifyCookieValue(value),
|
||||
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||
options.path ? '; path=' + options.path : '',
|
||||
options.domain ? '; domain=' + options.domain : '',
|
||||
options.secure ? '; secure' : ''
|
||||
].join(''));
|
||||
}
|
||||
|
||||
// Read
|
||||
|
||||
var result = key ? undefined : {};
|
||||
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all. Also prevents odd result when
|
||||
// calling $.cookie().
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
|
||||
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var name = decode(parts.shift());
|
||||
var cookie = parts.join('=');
|
||||
|
||||
if (key && key === name) {
|
||||
// If second argument (value) is a function it's a converter...
|
||||
result = read(cookie, value);
|
||||
break;
|
||||
}
|
||||
|
||||
// Prevent storing a cookie that we couldn't decode.
|
||||
if (!key && (cookie = read(cookie)) !== undefined) {
|
||||
result[name] = cookie;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
config.defaults = {};
|
||||
|
||||
$.removeCookie = function (key, options) {
|
||||
if ($.cookie(key) === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must not alter options, thus extending a fresh object...
|
||||
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
|
||||
return !$.cookie(key);
|
||||
};
|
||||
|
||||
}));
|
|
@ -29,6 +29,10 @@ h2 {
|
|||
line-height: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
color: #2c3e50;
|
||||
font: 300 48px Lato, sans-serif;
|
||||
}
|
||||
button {
|
||||
background: 0;
|
||||
border: none;
|
||||
|
@ -36,12 +40,20 @@ button {
|
|||
outline: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
margin: 10% auto;
|
||||
max-width: 480px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 0 30px;
|
||||
}
|
||||
#sidebar {
|
||||
background: #262c36;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -64,6 +76,7 @@ button {
|
|||
color: #fff;
|
||||
}
|
||||
#networks {
|
||||
display: none;
|
||||
min-height: 100%;
|
||||
padding: 30px 40px 80px;
|
||||
}
|
||||
|
@ -109,10 +122,10 @@ button {
|
|||
font: 18px Octicons;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
#connect:before {
|
||||
#footer #btn-1:before {
|
||||
content: "\f085";
|
||||
}
|
||||
#settings:before {
|
||||
#footer #btn-2:before {
|
||||
content: "\f02f";
|
||||
}
|
||||
#main {
|
||||
|
@ -157,11 +170,15 @@ button {
|
|||
content: "\f05e";
|
||||
}
|
||||
#windows {
|
||||
bottom: 0;
|
||||
bottom: 40px;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
#windows > div {
|
||||
display: none;
|
||||
}
|
||||
#chat {
|
||||
font: 13px Consolas, monospace;
|
||||
height: 100%;
|
||||
|
@ -172,7 +189,7 @@ button {
|
|||
opacity: .6;
|
||||
}
|
||||
#chat .window {
|
||||
bottom: 40px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
|
@ -193,6 +210,7 @@ button {
|
|||
}
|
||||
#messages {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -226,6 +244,7 @@ button {
|
|||
text-align: right;
|
||||
width: 134px;
|
||||
}
|
||||
#messages a,
|
||||
#messages .from button {
|
||||
color: #33b0f7;
|
||||
}
|
||||
|
@ -312,7 +331,7 @@ button {
|
|||
height: 40px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 180px;
|
||||
right: 0px;
|
||||
}
|
||||
#form input {
|
||||
border: 0;
|
||||
|
@ -323,9 +342,11 @@ button {
|
|||
padding: 0 12px;
|
||||
width: 100%;
|
||||
}
|
||||
#submit {
|
||||
margin-left: -999px;
|
||||
#form #submit {
|
||||
height: 0;
|
||||
margin-left: -9999px;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
<aside id="sidebar">
|
||||
<div id="networks"></div>
|
||||
<footer id="footer">
|
||||
<button id="connect" class="active"></button>
|
||||
<button id="settings"></button>
|
||||
<button id="btn-1" data-target="#connect"></button>
|
||||
<button id="btn-2" data-target="#settings"></button>
|
||||
</footer>
|
||||
</aside>
|
||||
<div id="main">
|
||||
|
@ -32,17 +32,31 @@
|
|||
</header>
|
||||
<div id="windows">
|
||||
<div id="chat"></div>
|
||||
<div id="connect" class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1>Connect</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settings" class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1>Settings</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="form" action="">
|
||||
<input id="submit" tabindex="-1" type="submit">
|
||||
<input id="input">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="templates">
|
||||
<script type="text/html" class="networks">
|
||||
{{#each networks}}
|
||||
<section class="network" data-id="{{id}}">
|
||||
<section id="network-{{id}}" class="network">
|
||||
{{partial "channels"}}
|
||||
</section>
|
||||
{{/each}}
|
||||
|
@ -50,7 +64,7 @@
|
|||
|
||||
<script type="text/html" class="channels">
|
||||
{{#each channels}}
|
||||
<button class="chan" data-id="{{id}}" data-type="{{type}}">
|
||||
<button id="chan-{{id}}" class="chan" data-type="{{type}}">
|
||||
<span class="badge"></span>
|
||||
{{name}}
|
||||
</button>
|
||||
|
@ -82,7 +96,7 @@
|
|||
{{/if}}
|
||||
<div id="users">
|
||||
{{#each users}}
|
||||
<button>{{mode}}{{name}}</button>
|
||||
<button class="user">{{mode}}{{name}}</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</script>
|
||||
|
@ -95,7 +109,7 @@
|
|||
</span>
|
||||
<span class="from">
|
||||
{{#if from}}
|
||||
<button>{{from}}</button>
|
||||
<button class="user">{{from}}</button>
|
||||
{{else}}
|
||||
//
|
||||
{{/if}}
|
||||
|
|
|
@ -31,11 +31,12 @@ $(function() {
|
|||
"/whois"
|
||||
];
|
||||
|
||||
var sidebar = $("#sidebar");
|
||||
var chat = $("#chat");
|
||||
var networks = $("#networks");
|
||||
|
||||
var networks = $("#networks");
|
||||
var channels = [];
|
||||
var activeChannel = null;
|
||||
var active = null;
|
||||
|
||||
var tpl = [];
|
||||
function render(name, data) {
|
||||
|
@ -56,16 +57,19 @@ $(function() {
|
|||
render("networks", {
|
||||
networks: data.networks
|
||||
})
|
||||
);
|
||||
networks.find(".chan")
|
||||
.eq(0)
|
||||
.trigger("click");
|
||||
).fadeIn();
|
||||
var active = $($.cookie("active"));
|
||||
if (active.length === 0) {
|
||||
active = networks.find(".chan").eq(0);
|
||||
}
|
||||
active.trigger("click");
|
||||
});
|
||||
|
||||
socket.on("join", function(data) {
|
||||
channels.push(data.chan);
|
||||
var id = data.network;
|
||||
var network = networks
|
||||
.find(".network[data-id='" + data.network + "']")
|
||||
.find("#network-" + id)
|
||||
.eq(0);
|
||||
network.append(
|
||||
render("channels", {
|
||||
|
@ -83,9 +87,7 @@ $(function() {
|
|||
chan.messages.push(data.msg);
|
||||
if (isActive(chan)) {
|
||||
chat.find("#messages").append(
|
||||
render("messages", {
|
||||
messages: [data.msg]
|
||||
})
|
||||
render("messages", {messages: [data.msg]})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +101,9 @@ $(function() {
|
|||
networks: [data.network]
|
||||
})
|
||||
);
|
||||
networks.find(".chan")
|
||||
.last()
|
||||
.trigger("click");
|
||||
});
|
||||
|
||||
socket.on("nick", function(data) {
|
||||
|
@ -106,7 +111,8 @@ $(function() {
|
|||
});
|
||||
|
||||
socket.on("part", function(data) {
|
||||
networks.find(".chan[data-id='" + data.chan + "']")
|
||||
var id = data.chan;
|
||||
networks.find("#chan-" + id)
|
||||
.remove()
|
||||
.end()
|
||||
.find(".chan")
|
||||
|
@ -115,7 +121,8 @@ $(function() {
|
|||
});
|
||||
|
||||
socket.on("quit", function(data) {
|
||||
networks.find(".network[data-id='" + data.network + "']")
|
||||
var id = data.network;
|
||||
networks.find("#network-" + id)
|
||||
.remove()
|
||||
.end()
|
||||
.find(".chan")
|
||||
|
@ -128,8 +135,7 @@ $(function() {
|
|||
if (typeof chan !== "undefined") {
|
||||
chan.users = data.users;
|
||||
if (isActive(chan)) {
|
||||
chat.find(".sidebar")
|
||||
.html(render("users", chan));
|
||||
chat.find(".sidebar").html(render("users", chan));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -143,30 +149,40 @@ $(function() {
|
|||
var value = input.val();
|
||||
input.val("");
|
||||
socket.emit("input", {
|
||||
target: chat.data("target"),
|
||||
target: active.id || -1,
|
||||
text: value
|
||||
});
|
||||
});
|
||||
|
||||
networks.on("click", ".chan", function() {
|
||||
var self = $(this);
|
||||
var id = self.data("id");
|
||||
if (self.hasClass("active")) {
|
||||
return;
|
||||
}
|
||||
sidebar.on("click", "button:not(.active)", function() {
|
||||
var btn = $(this);
|
||||
var id = "#" + btn.attr("id");
|
||||
|
||||
chat.data("target", id);
|
||||
networks.find(".active").removeClass("active");
|
||||
self.addClass("active");
|
||||
$.cookie("active", id);
|
||||
|
||||
var chan = find(id);
|
||||
sidebar.find(".active").removeClass("active");
|
||||
btn.addClass("active");
|
||||
|
||||
active = null;
|
||||
if (btn.hasClass("chan")) {
|
||||
var chan = find(id.replace("#chan-", ""));
|
||||
if (typeof chan !== "undefined") {
|
||||
activeChannel = chan;
|
||||
active = chan;
|
||||
chat.fadeIn();
|
||||
chat.siblings().hide();
|
||||
chat.html(render("chat", chan));
|
||||
chat.find(".window")
|
||||
.sticky()
|
||||
.scrollBottom();
|
||||
}
|
||||
} else {
|
||||
chat.empty();
|
||||
var target = $(btn.data("target"));
|
||||
if (target.length !== 0) {
|
||||
target.fadeIn();
|
||||
target.siblings().hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chat.on("input", "#search", function() {
|
||||
|
@ -181,8 +197,19 @@ $(function() {
|
|||
});
|
||||
});
|
||||
|
||||
chat.on("click", ".user", function() {
|
||||
var user = $(this).text();
|
||||
if (user.indexOf("#") !== -1) {
|
||||
return;
|
||||
}
|
||||
socket.emit("input", {
|
||||
target: active.id || -1,
|
||||
text: "/whois " + user
|
||||
});
|
||||
});
|
||||
|
||||
function isActive(chan) {
|
||||
return activeChannel !== null && chan == activeChannel;
|
||||
return active !== null && chan == active;
|
||||
}
|
||||
|
||||
function find(id) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,10 +1,20 @@
|
|||
var _ = require("lodash");
|
||||
|
||||
module.exports = function(network, chan, cmd, args) {
|
||||
if (cmd != "part") {
|
||||
if (cmd != "part" && cmd != "leave" && cmd != "close") {
|
||||
return;
|
||||
}
|
||||
var client = this;
|
||||
if (chan.type == "query") {
|
||||
network.channels = _.without(network.channels, chan);
|
||||
client.emit("part", {
|
||||
chan: chan.id
|
||||
});
|
||||
} else {
|
||||
var irc = network.irc;
|
||||
if (args.length === 0) {
|
||||
args.push(chan.name);
|
||||
}
|
||||
irc.part(args);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,10 +4,11 @@ var Msg = require("../../models/msg");
|
|||
|
||||
module.exports = function(irc, network) {
|
||||
var client = this;
|
||||
irc.on("whois", function(data) {
|
||||
if (!data) {
|
||||
irc.on("whois", function(err, data) {
|
||||
if (data === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chan = _.findWhere(network.channels, {name: data.nickname});
|
||||
if (typeof chan === "undefined") {
|
||||
chan = new Chan({
|
||||
|
@ -20,6 +21,7 @@ module.exports = function(irc, network) {
|
|||
chan: chan
|
||||
});
|
||||
}
|
||||
|
||||
var prefix = {
|
||||
hostname: "from",
|
||||
realname: "is",
|
||||
|
|
|
@ -89,6 +89,7 @@ function input(client, data) {
|
|||
args
|
||||
]);
|
||||
} catch (err) {
|
||||
console.log(err.stack);
|
||||
// ..
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue