Render chat
This commit is contained in:
parent
4ef13d6a18
commit
f3f3858663
|
@ -1,4 +1,5 @@
|
|||
module.exports = function(grunt) {
|
||||
var components = "";
|
||||
var files = [
|
||||
"./lib/**/*.js",
|
||||
"./client/js/shout.js"
|
||||
|
@ -14,7 +15,10 @@ module.exports = function(grunt) {
|
|||
uglify: {
|
||||
js: {
|
||||
files: {
|
||||
"client/js/components.min.js": ["client/components/*.js"]
|
||||
"client/js/components.min.js": [
|
||||
"client/components/*.js",
|
||||
"client/components/jquery/*.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/*!
|
||||
* tabcomplete
|
||||
* http://github.com/erming/tabcomplete
|
||||
* v1.3.1
|
||||
*/
|
||||
(function($) {
|
||||
var keys = {
|
||||
backspace: 8,
|
||||
tab: 9,
|
||||
up: 38,
|
||||
down: 40
|
||||
};
|
||||
|
||||
$.tabcomplete = {};
|
||||
$.tabcomplete.defaultOptions = {
|
||||
after: "",
|
||||
arrowKeys: false,
|
||||
caseSensitive: false,
|
||||
hint: "placeholder",
|
||||
minLength: 1
|
||||
};
|
||||
|
||||
$.fn.tab = // Alias
|
||||
$.fn.tabcomplete = function(args, options) {
|
||||
if (this.length > 1) {
|
||||
return this.each(function() {
|
||||
$(this).tabcomplete(args, options);
|
||||
});
|
||||
}
|
||||
|
||||
// Only enable the plugin on <input> and <textarea> elements.
|
||||
var tag = this.prop("tagName");
|
||||
if (tag != "INPUT" && tag != "TEXTAREA") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default options.
|
||||
options = $.extend(
|
||||
$.tabcomplete.defaultOptions,
|
||||
options
|
||||
);
|
||||
|
||||
// Remove any leftovers.
|
||||
// This allows us to override the plugin if necessary.
|
||||
this.unbind(".tabcomplete");
|
||||
this.prev(".hint").remove();
|
||||
|
||||
var self = this;
|
||||
var backspace = false;
|
||||
var i = -1;
|
||||
var words = [];
|
||||
var last = "";
|
||||
|
||||
var hint = $.noop;
|
||||
|
||||
// Determine what type of hinting to use.
|
||||
switch (options.hint) {
|
||||
case "placeholder":
|
||||
hint = placeholder;
|
||||
break;
|
||||
|
||||
case "select":
|
||||
hint = select;
|
||||
break;
|
||||
}
|
||||
|
||||
this.on("input.tabcomplete", function() {
|
||||
var input = self.val();
|
||||
var word = input.split(/ |\n/).pop();
|
||||
|
||||
// Reset iteration.
|
||||
i = -1;
|
||||
last = "";
|
||||
words = [];
|
||||
|
||||
// Check for matches if the current word is the last word.
|
||||
if (self[0].selectionStart == input.length
|
||||
&& word.length) {
|
||||
if (typeof args === "function") {
|
||||
// If the user supplies a function, invoke it
|
||||
// and keep the result.
|
||||
words = args(word);
|
||||
} else {
|
||||
// Otherwise, call the .match() function.
|
||||
words = match(word, args, options.caseSensitive);
|
||||
}
|
||||
|
||||
// Append 'after' to each word.
|
||||
if (options.after) {
|
||||
words = $.map(words, function(w) { return w + options.after; });
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the number of matching words with the 'match' event.
|
||||
self.trigger("match", words.length);
|
||||
|
||||
if (options.hint) {
|
||||
if (!(options.hint == "select" && backspace) && word.length >= options.minLength) {
|
||||
// Show hint.
|
||||
hint.call(self, words[0]);
|
||||
} else {
|
||||
// Clear hinting.
|
||||
// This call is needed when using backspace.
|
||||
hint.call(self, "");
|
||||
}
|
||||
}
|
||||
|
||||
if (backspace) {
|
||||
backspace = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.on("keydown.tabcomplete", function(e) {
|
||||
var key = e.which;
|
||||
if (key == keys.tab
|
||||
|| (options.arrowKeys && (key == keys.up || key == keys.down))) {
|
||||
|
||||
// Don't lose focus on tab click.
|
||||
e.preventDefault();
|
||||
|
||||
// Iterate the matches with tab and the up and down keys by incrementing
|
||||
// or decrementing the 'i' variable.
|
||||
if (key != keys.up) {
|
||||
i++;
|
||||
} else {
|
||||
if (i == -1) return;
|
||||
if (i == 0) {
|
||||
// Jump to the last word.
|
||||
i = words.length - 1;
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// Get next match.
|
||||
var word = words[i % words.length];
|
||||
if (!word) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value = self.val();
|
||||
last = last || value.split(/ |\n/).pop();
|
||||
|
||||
// Return if the 'minLength' requirement isn't met.
|
||||
if (last.length < options.minLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update element with the completed text.
|
||||
var text = value.substr(0, self[0].selectionStart - last.length) + word;
|
||||
self.val(text);
|
||||
|
||||
// Put the cursor at the end after completion.
|
||||
// This isn't strictly necessary, but solves an issue with
|
||||
// Internet Explorer.
|
||||
if (options.hint == "select") {
|
||||
self[0].selectionStart = text.length;
|
||||
}
|
||||
|
||||
// Remember the word until next time.
|
||||
last = word;
|
||||
|
||||
// Emit event.
|
||||
self.trigger("tabcomplete", last);
|
||||
|
||||
if (options.hint) {
|
||||
// Turn off any additional hinting.
|
||||
hint.call(self, "");
|
||||
}
|
||||
} else if (e.which == keys.backspace) {
|
||||
// Remember that backspace was pressed. This is used
|
||||
// by the 'input' event.
|
||||
backspace = true;
|
||||
|
||||
// Reset iteration.
|
||||
i = -1;
|
||||
last = "";
|
||||
}
|
||||
});
|
||||
|
||||
if (options.hint) {
|
||||
// If enabled, turn on hinting.
|
||||
hint.call(this, "");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Simple matching.
|
||||
// Filter the array and return the items that begins with 'word'.
|
||||
function match(word, array, caseSensitive) {
|
||||
return $.grep(
|
||||
array,
|
||||
function(w) {
|
||||
if (caseSensitive) {
|
||||
return !w.indexOf(word);
|
||||
} else {
|
||||
return !w.toLowerCase().indexOf(word.toLowerCase());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Show placeholder text.
|
||||
// This works by creating a copy of the input and placing it behind
|
||||
// the real input.
|
||||
function placeholder(word) {
|
||||
var input = this;
|
||||
var clone = input.prev(".hint");
|
||||
|
||||
input.css({
|
||||
backgroundColor: "transparent",
|
||||
position: "relative",
|
||||
});
|
||||
|
||||
// Lets create a clone of the input if it does
|
||||
// not already exist.
|
||||
if (!clone.length) {
|
||||
input.wrap(
|
||||
$("<div>").css({position: "relative", height: input.css("height")})
|
||||
);
|
||||
clone = input
|
||||
.clone()
|
||||
.attr("tabindex", -1)
|
||||
.removeAttr("id name placeholder")
|
||||
.addClass("hint")
|
||||
.insertBefore(input);
|
||||
clone.css({
|
||||
position: "absolute",
|
||||
});
|
||||
}
|
||||
|
||||
var hint = "";
|
||||
if (typeof word !== "undefined") {
|
||||
var value = input.val();
|
||||
hint = value + word.substr(value.split(/ |\n/).pop().length);
|
||||
}
|
||||
|
||||
clone.val(hint);
|
||||
}
|
||||
|
||||
// Hint by selecting part of the suggested word.
|
||||
function select(word) {
|
||||
var input = this;
|
||||
var value = input.val();
|
||||
if (word) {
|
||||
input.val(
|
||||
value
|
||||
+ word.substr(value.split(/ |\n/).pop().length)
|
||||
);
|
||||
|
||||
// Select hint.
|
||||
input[0].selectionStart = value.length;
|
||||
}
|
||||
}
|
||||
})(jQuery);
|
|
@ -61,14 +61,14 @@ button {
|
|||
background: #323841;
|
||||
color: #fff;
|
||||
}
|
||||
#channels {
|
||||
#networks {
|
||||
min-height: 100%;
|
||||
padding: 30px 40px 80px;
|
||||
}
|
||||
#channels .network + .network {
|
||||
#networks .network + .network {
|
||||
margin-top: 30px;
|
||||
}
|
||||
#channels .chan {
|
||||
#networks .chan {
|
||||
display: block;
|
||||
margin: 1px -10px;
|
||||
padding: 6px 10px 8px;
|
||||
|
@ -77,12 +77,12 @@ button {
|
|||
transition: all .2s;
|
||||
width: 160px;
|
||||
}
|
||||
#channels .chan:first-child {
|
||||
#networks .chan:first-child {
|
||||
color: #84d1ff;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#channels .badge {
|
||||
#networks .badge {
|
||||
background: rgba(255, 255, 255, .06);
|
||||
border-radius: 3px;
|
||||
color: #afb6c0;
|
||||
|
@ -93,6 +93,9 @@ button {
|
|||
right: 10px;
|
||||
transition: all .1s;
|
||||
}
|
||||
#networks .badge:empty {
|
||||
display: none;
|
||||
}
|
||||
#footer {
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
|
@ -163,17 +166,10 @@ button {
|
|||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
#chat form {
|
||||
bottom: 0;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 180px;
|
||||
}
|
||||
#chat button:hover {
|
||||
opacity: .6;
|
||||
}
|
||||
#chat .chat {
|
||||
#chat .window {
|
||||
bottom: 40px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
|
@ -220,17 +216,30 @@ button {
|
|||
}
|
||||
#messages .from {
|
||||
background: #f9f9f9;
|
||||
color: #33b0f7;
|
||||
color: #ddd;
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
width: 134px;
|
||||
}
|
||||
#messages .from button {
|
||||
color: #33b0f7;
|
||||
}
|
||||
#messages .text {
|
||||
padding-left: 10px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
#messages .type {
|
||||
color: #ccc;
|
||||
display: none;
|
||||
}
|
||||
#messages .join .type,
|
||||
#messages .part .type,
|
||||
#messages .mode .type,
|
||||
#messages .nick .type,
|
||||
#messages .kick .type,
|
||||
#messages .quit .type,
|
||||
#messages .quit .type {
|
||||
display: inline;
|
||||
}
|
||||
#meta {
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
|
@ -244,6 +253,9 @@ button {
|
|||
#meta .count {
|
||||
color: #ccc;
|
||||
}
|
||||
#meta .type {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
#users {
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
|
@ -256,7 +268,14 @@ button {
|
|||
display: block;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
#input {
|
||||
#form {
|
||||
bottom: 0;
|
||||
height: 40px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 180px;
|
||||
}
|
||||
#form input {
|
||||
border: 0;
|
||||
border-top: 1px solid #e9ecef;
|
||||
height: 100%;
|
||||
|
|
|
@ -18,20 +18,7 @@
|
|||
<body>
|
||||
|
||||
<aside id="sidebar">
|
||||
<div id="channels">
|
||||
<section class="network">
|
||||
<button class="chan">
|
||||
Network
|
||||
</button>
|
||||
<button class="chan active">
|
||||
#channel
|
||||
</button>
|
||||
<button class="chan">
|
||||
<span class="badge">16</span>
|
||||
#chan
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
<div id="networks"></div>
|
||||
<footer id="footer">
|
||||
<button id="connect" class="active"></button>
|
||||
<button id="settings"></button>
|
||||
|
@ -44,52 +31,18 @@
|
|||
<h1>#channel</h1>
|
||||
</header>
|
||||
<div id="windows">
|
||||
<div id="chat">
|
||||
<div class="chat">
|
||||
<div id="messages">
|
||||
<div class="msg">
|
||||
<span class="time">00:00</span>
|
||||
<span class="from">
|
||||
<button>foo</button>
|
||||
</span>
|
||||
<span class="text">
|
||||
<em class="type">join</em>
|
||||
</span>
|
||||
</div>
|
||||
<div class="msg">
|
||||
<span class="time">00:00</span>
|
||||
<span class="from">
|
||||
<button>foo</button>
|
||||
</span>
|
||||
<span class="text">
|
||||
<em class="type"></em>
|
||||
Hello, world!
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div id="meta">
|
||||
<h1>#channel</h1>
|
||||
<div class="count">2 users</div>
|
||||
</div>
|
||||
<div id="users">
|
||||
<button>foo</button>
|
||||
<button>bar</button>
|
||||
</div>
|
||||
</aside>
|
||||
<form action="">
|
||||
<input id="submit" tabindex="-1" type="submit">
|
||||
<input id="input">
|
||||
</form>
|
||||
</div>
|
||||
<div id="chat"></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">
|
||||
<section class="network" data-id="{{id}}">
|
||||
{{partial "channels"}}
|
||||
</section>
|
||||
{{/each}}
|
||||
|
@ -97,19 +50,35 @@
|
|||
|
||||
<script type="text/html" class="channels">
|
||||
{{#each channels}}
|
||||
<button class="chan">
|
||||
<button class="chan" data-id="{{id}}" data-type="{{type}}">
|
||||
<span class="badge"></span>
|
||||
Network
|
||||
{{name}}
|
||||
</button>
|
||||
{{/each}}
|
||||
</script>
|
||||
|
||||
<script type="text/html" class="chat">
|
||||
<div class="window">
|
||||
<div id="messages">
|
||||
{{partial "messages"}}
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
{{partial "users"}}
|
||||
</aside>
|
||||
</script>
|
||||
|
||||
<script type="text/html" class="users">
|
||||
<div id="meta">
|
||||
<h1>{{name}}</h1>
|
||||
<div class="count">
|
||||
{{users.length}}
|
||||
users
|
||||
{{#if users.length}}
|
||||
{{users.length}} users
|
||||
{{else}}
|
||||
<span class="type">
|
||||
{{type}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="users">
|
||||
|
@ -121,12 +90,16 @@
|
|||
|
||||
<script type="text/html" class="messages">
|
||||
{{#each messages}}
|
||||
<div class="msg">
|
||||
<div class="msg {{type}}">
|
||||
<span class="time">
|
||||
{{time}}
|
||||
</span>
|
||||
<span class="from">
|
||||
{{#if from}}
|
||||
<button>{{from}}</button>
|
||||
{{else}}
|
||||
//
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="text">
|
||||
<em class="type">{{type}}</em>
|
||||
|
@ -138,7 +111,7 @@
|
|||
</div>
|
||||
|
||||
<script src="js/components.min.js"></script>
|
||||
<script src="js/shout.js"></script>
|
||||
<script src="js/chat.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,200 @@
|
|||
$(function() {
|
||||
var socket = io();
|
||||
var commands = [
|
||||
"/ame",
|
||||
"/amsg",
|
||||
"/close",
|
||||
"/connect",
|
||||
"/deop",
|
||||
"/devoice",
|
||||
"/disconnect",
|
||||
"/invite",
|
||||
"/join",
|
||||
"/kick",
|
||||
"/leave",
|
||||
"/mode",
|
||||
"/msg",
|
||||
"/nick",
|
||||
"/notice",
|
||||
"/op",
|
||||
"/part",
|
||||
"/partall",
|
||||
"/query",
|
||||
"/quit",
|
||||
"/raw",
|
||||
"/say",
|
||||
"/send",
|
||||
"/server",
|
||||
"/slap",
|
||||
"/topic",
|
||||
"/voice",
|
||||
"/whoami",
|
||||
"/whois"
|
||||
];
|
||||
|
||||
var chat = $("#chat");
|
||||
var networks = $("#networks");
|
||||
|
||||
var channels = [];
|
||||
var activeChannel = null;
|
||||
|
||||
var tpl = [];
|
||||
function render(name, data) {
|
||||
tpl[name] = tpl[name] || Handlebars.compile($("#templates ." + name).html());
|
||||
return tpl[name](data);
|
||||
}
|
||||
|
||||
socket.on("auth", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
socket.on("init", function(data) {
|
||||
networks.empty()
|
||||
channels = $.map(data.networks, function(n) {
|
||||
return n.channels;
|
||||
});
|
||||
networks.append(
|
||||
render("networks", {
|
||||
networks: data.networks
|
||||
})
|
||||
);
|
||||
networks.find(".chan")
|
||||
.eq(0)
|
||||
.trigger("click");
|
||||
});
|
||||
|
||||
socket.on("join", function(data) {
|
||||
channels.push(data.chan);
|
||||
var network = networks
|
||||
.find(".network[data-id='" + data.network + "']")
|
||||
.eq(0);
|
||||
network.append(
|
||||
render("channels", {
|
||||
channels: [data.chan]
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("msg", function(data) {
|
||||
var chan = find(data.chan);
|
||||
if (typeof chan !== "undefined") {
|
||||
chan.messages.push(data.msg);
|
||||
if (isActive(chan)) {
|
||||
chat.find("#messages").append(
|
||||
render("messages", {
|
||||
messages: [data.msg]
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("network", function(data) {
|
||||
networks.append(
|
||||
render("networks", {
|
||||
networks: [data.network]
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("nick", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
socket.on("part", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
socket.on("quit", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
socket.on("users", function(data) {
|
||||
var chan = find(data.chan);
|
||||
if (typeof chan !== "undefined") {
|
||||
chan.users = data.users;
|
||||
if (isActive(chan)) {
|
||||
chat.find(".sidebar")
|
||||
.html(render("users", chan));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
networks.on("click", ".chan", function() {
|
||||
var id = $(this).data("id");
|
||||
var chan = find(id);
|
||||
if (typeof chan !== "undefined") {
|
||||
activeChannel = chan;
|
||||
chat.html(
|
||||
render("chat", chan)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var input = $("#input").tab(complete, {
|
||||
hint: false
|
||||
});
|
||||
|
||||
var form = $("#form").on("submit", function(e) {
|
||||
e.preventDefault();
|
||||
var value = input.val();
|
||||
input.val("");
|
||||
socket.emit("input", {
|
||||
// ..
|
||||
});
|
||||
});
|
||||
|
||||
function isActive(chan) {
|
||||
return activeChannel !== null && chan == activeChannel;
|
||||
}
|
||||
|
||||
function find(id) {
|
||||
return $.grep(channels, function(c) {
|
||||
return c.id == id;
|
||||
})[0];
|
||||
}
|
||||
|
||||
function complete(word) {
|
||||
return $.grep(
|
||||
commands,
|
||||
function(w) {
|
||||
return !w.toLowerCase().indexOf(word.toLowerCase());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function escape(text) {
|
||||
var e = {
|
||||
"<": "<",
|
||||
">": ">"
|
||||
};
|
||||
return text.replace(/[<>]/g, function (c) {
|
||||
return e[c];
|
||||
});
|
||||
}
|
||||
|
||||
Handlebars.registerHelper(
|
||||
"partial", function(id) {
|
||||
return new Handlebars.SafeString(render(id, this));
|
||||
}
|
||||
);
|
||||
|
||||
Handlebars.registerHelper(
|
||||
"uri", function(text) {
|
||||
var urls = [];
|
||||
text = URI.withinString(text, function(url) {
|
||||
urls.push(url);
|
||||
return "$(" + (urls.length - 1) + ")";
|
||||
});
|
||||
text = escape(text);
|
||||
for (var i in urls) {
|
||||
var url = escape(urls[i]);
|
||||
text = text.replace(
|
||||
"$(" + i + ")",
|
||||
"<a href='" + url.replace(/^www/, "//www") + "' target='_blank'>" + url + "</a>"
|
||||
);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
);
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -1,116 +0,0 @@
|
|||
$(function() {
|
||||
new Shout();
|
||||
});
|
||||
|
||||
function Shout() {
|
||||
var client = this;
|
||||
var socket = io();
|
||||
var events = [
|
||||
"auth",
|
||||
"init",
|
||||
"join",
|
||||
"msg",
|
||||
"network",
|
||||
"nick",
|
||||
"part",
|
||||
"quit",
|
||||
"users"
|
||||
].forEach(function(e) {
|
||||
client[e].call(client, socket);
|
||||
});
|
||||
}
|
||||
|
||||
Shout.prototype.auth = function(socket) {
|
||||
socket.on("auth", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.init = function(socket) {
|
||||
socket.on("init", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.join = function(socket) {
|
||||
socket.on("join", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.msg = function(socket) {
|
||||
socket.on("msg", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.network = function(socket) {
|
||||
socket.on("network", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.nick = function(socket) {
|
||||
socket.on("nick", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.part = function(socket) {
|
||||
socket.on("part", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.quit = function(socket) {
|
||||
socket.on("quit", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
Shout.prototype.users = function(socket) {
|
||||
socket.on("users", function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
var tpl = [];
|
||||
function render(name, data) {
|
||||
tpl[name] = tpl[name] || Handlebars.compile($("#templates ." + name).html());
|
||||
return tpl[name](data);
|
||||
}
|
||||
|
||||
function escape(text) {
|
||||
var e = {
|
||||
"<": "<",
|
||||
">": ">"
|
||||
};
|
||||
return text.replace(/[<>]/g, function (c) {
|
||||
return e[c];
|
||||
});
|
||||
}
|
||||
|
||||
Handlebars.registerHelper(
|
||||
"partial", function(id) {
|
||||
return new Handlebars.SafeString(render(id, this));
|
||||
}
|
||||
);
|
||||
|
||||
Handlebars.registerHelper(
|
||||
"uri", function(text) {
|
||||
var urls = [];
|
||||
text = URI.withinString(text, function(url) {
|
||||
urls.push(url);
|
||||
return "$(" + (urls.length - 1) + ")";
|
||||
});
|
||||
text = escape(text);
|
||||
for (var i in urls) {
|
||||
var url = escape(urls[i]);
|
||||
text = text.replace(
|
||||
"$(" + i + ")",
|
||||
"<a href='" + url.replace(/^www/, "//www") + "' target='_blank'>" + url + "</a>"
|
||||
);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
);
|
|
@ -17,7 +17,7 @@ function Chan(attr) {
|
|||
name: "",
|
||||
messages: [],
|
||||
users: []
|
||||
}));
|
||||
}, attr));
|
||||
}
|
||||
|
||||
Chan.prototype.sortUsers = function() {
|
||||
|
|
|
@ -3,12 +3,13 @@ var Msg = require("../../models/msg");
|
|||
module.exports = function(irc, network) {
|
||||
var client = this;
|
||||
irc.on("errors", function(data) {
|
||||
var lobby = network.channels[0];
|
||||
var msg = new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
from: "*",
|
||||
text: data.message,
|
||||
});
|
||||
client.emit("msg", {
|
||||
chan: lobby.id,
|
||||
msg: msg
|
||||
});
|
||||
if (!network.connected) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var _ = require("lodash");
|
||||
var Chan = require("../../models/chan");
|
||||
var Msg = require("../../models/msg");
|
||||
var User = require("../../models/user");
|
||||
|
||||
|
@ -29,7 +30,7 @@ module.exports = function(irc, network) {
|
|||
});
|
||||
chan.messages.push(msg);
|
||||
client.emit("msg", {
|
||||
id: chan.id,
|
||||
chan: chan.id,
|
||||
msg: msg
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var _ = require("lodash");
|
||||
var Msg = require("../../models/msg");
|
||||
|
||||
module.exports = function(irc, network) {
|
||||
var client = this;
|
||||
|
|
|
@ -3,18 +3,17 @@ var Msg = require("../../models/msg");
|
|||
module.exports = function(irc, network) {
|
||||
var client = this;
|
||||
irc.on("motd", function(data) {
|
||||
var lobby = network.channels[0];
|
||||
data.motd.forEach(function(text) {
|
||||
var msg = new Msg({
|
||||
type: Msg.Type.MOTD,
|
||||
from: "*",
|
||||
text: text
|
||||
});
|
||||
lobby.messages.push(msg);
|
||||
client.emit("msg", {
|
||||
chan: lobby.id,
|
||||
msg: msg
|
||||
});
|
||||
});
|
||||
//var lobby = network.channels[0];
|
||||
//data.motd.forEach(function(text) {
|
||||
// var msg = new Msg({
|
||||
// type: Msg.Type.MOTD,
|
||||
// text: text
|
||||
// });
|
||||
// lobby.messages.push(msg);
|
||||
// client.emit("msg", {
|
||||
// chan: lobby.id,
|
||||
// msg: msg
|
||||
// });
|
||||
//});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@ module.exports = function(irc, network) {
|
|||
if (data["new"] == irc.me) {
|
||||
var lobby = network.channels[0];
|
||||
var msg = new Msg({
|
||||
from: "*",
|
||||
text: "You're now known as " + data["new"],
|
||||
});
|
||||
chan.messages.push(msg);
|
||||
|
|
|
@ -4,9 +4,9 @@ module.exports = function(irc, network) {
|
|||
var client = this;
|
||||
irc.on("notice", function(data) {
|
||||
var lobby = network.channels[0];
|
||||
var from = data.from || "*";
|
||||
var from = data.from || "";
|
||||
if (data.to == "*" || data.from.indexOf(".") !== -1) {
|
||||
from = "*";
|
||||
from = "";
|
||||
}
|
||||
var msg = new Msg({
|
||||
type: Msg.Type.NOTICE,
|
||||
|
|
|
@ -7,7 +7,6 @@ module.exports = function(irc, network) {
|
|||
irc.write("PING " + network.host);
|
||||
var lobby = network.channels[0];
|
||||
var msg = new Msg({
|
||||
from: "*",
|
||||
text: "You're now known as " + data
|
||||
});
|
||||
lobby.messages.push(msg);
|
||||
|
|
|
@ -29,7 +29,7 @@ module.exports = function(irc, network) {
|
|||
var i = 0;
|
||||
for (var k in data) {
|
||||
var key = prefix[k];
|
||||
if (!key || data[k].toString() == "") {
|
||||
if (!key || data[k].toString() === "") {
|
||||
continue;
|
||||
}
|
||||
var msg = new Msg({
|
||||
|
|
34
lib/shout.js
34
lib/shout.js
|
@ -49,9 +49,7 @@ module.exports = function() {
|
|||
sockets = io(http().use(http.static("client")).listen(config.port || 9000));
|
||||
sockets.on("connection", function(socket) {
|
||||
if (config.public) {
|
||||
var client = new Client({sockets: sockets});
|
||||
init(socket, client);
|
||||
connect(client, {host: "irc.rizon.net"});
|
||||
auth.call(socket);
|
||||
} else {
|
||||
init(socket);
|
||||
}
|
||||
|
@ -66,13 +64,29 @@ function init(socket, client) {
|
|||
socket.on("input", function(data) { input(client, data); });
|
||||
socket.join(client.id);
|
||||
socket.emit("init", {
|
||||
init: client.networks
|
||||
networks: client.networks
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function auth() {
|
||||
function auth(data) {
|
||||
var socket = this;
|
||||
if (config.public) {
|
||||
// Temporary:
|
||||
var client = clients[0];
|
||||
if (clients.length === 0) {
|
||||
var client = new Client({sockets: sockets});
|
||||
clients.push(client);
|
||||
connect(client, {
|
||||
host: "irc.freenode.org"
|
||||
});
|
||||
}
|
||||
init(socket, client);
|
||||
} else {
|
||||
if (false) {
|
||||
// ..
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connect(client, args) {
|
||||
|
@ -80,25 +94,35 @@ function connect(client, args) {
|
|||
host: args.host,
|
||||
port: args.port || 6667
|
||||
};
|
||||
|
||||
var stream = args.tls ? tls.connect(options) : net.connect(options);
|
||||
stream.on("error", function(e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
var irc = slate(stream);
|
||||
irc.nick("shout");
|
||||
irc.user("shout", "Shout User");
|
||||
|
||||
client.nick = "shout";
|
||||
|
||||
var network = new Network({
|
||||
host: options.host,
|
||||
irc: irc
|
||||
});
|
||||
|
||||
client.networks.push(network);
|
||||
client.emit("network", {
|
||||
network: network
|
||||
});
|
||||
|
||||
events.forEach(function(plugin) {
|
||||
require("./plugins/irc-events/" + plugin).apply(client, [irc, network]);
|
||||
});
|
||||
|
||||
irc.on("welcome", function() {
|
||||
irc.join("#shout-test");
|
||||
});
|
||||
}
|
||||
|
||||
function input(client, data) {
|
||||
|
|
Loading…
Reference in New Issue