Render chat
This commit is contained in:
parent
4ef13d6a18
commit
f3f3858663
@ -1,4 +1,5 @@
|
|||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
var components = "";
|
||||||
var files = [
|
var files = [
|
||||||
"./lib/**/*.js",
|
"./lib/**/*.js",
|
||||||
"./client/js/shout.js"
|
"./client/js/shout.js"
|
||||||
@ -14,7 +15,10 @@ module.exports = function(grunt) {
|
|||||||
uglify: {
|
uglify: {
|
||||||
js: {
|
js: {
|
||||||
files: {
|
files: {
|
||||||
"client/js/components.min.js": ["client/components/*.js"]
|
"client/js/components.min.js": [
|
||||||
|
"client/components/*.js",
|
||||||
|
"client/components/jquery/*.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
256
client/components/jquery/tabcomplete.js
vendored
Normal file
256
client/components/jquery/tabcomplete.js
vendored
Normal file
@ -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;
|
background: #323841;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
#channels {
|
#networks {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: 30px 40px 80px;
|
padding: 30px 40px 80px;
|
||||||
}
|
}
|
||||||
#channels .network + .network {
|
#networks .network + .network {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
#channels .chan {
|
#networks .chan {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 1px -10px;
|
margin: 1px -10px;
|
||||||
padding: 6px 10px 8px;
|
padding: 6px 10px 8px;
|
||||||
@ -77,12 +77,12 @@ button {
|
|||||||
transition: all .2s;
|
transition: all .2s;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
#channels .chan:first-child {
|
#networks .chan:first-child {
|
||||||
color: #84d1ff;
|
color: #84d1ff;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
#channels .badge {
|
#networks .badge {
|
||||||
background: rgba(255, 255, 255, .06);
|
background: rgba(255, 255, 255, .06);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: #afb6c0;
|
color: #afb6c0;
|
||||||
@ -93,6 +93,9 @@ button {
|
|||||||
right: 10px;
|
right: 10px;
|
||||||
transition: all .1s;
|
transition: all .1s;
|
||||||
}
|
}
|
||||||
|
#networks .badge:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
#footer {
|
#footer {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
line-height: 80px;
|
line-height: 80px;
|
||||||
@ -163,17 +166,10 @@ button {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
#chat form {
|
|
||||||
bottom: 0;
|
|
||||||
height: 40px;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 180px;
|
|
||||||
}
|
|
||||||
#chat button:hover {
|
#chat button:hover {
|
||||||
opacity: .6;
|
opacity: .6;
|
||||||
}
|
}
|
||||||
#chat .chat {
|
#chat .window {
|
||||||
bottom: 40px;
|
bottom: 40px;
|
||||||
left: 0;
|
left: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -220,17 +216,30 @@ button {
|
|||||||
}
|
}
|
||||||
#messages .from {
|
#messages .from {
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
color: #33b0f7;
|
color: #ddd;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
width: 134px;
|
width: 134px;
|
||||||
}
|
}
|
||||||
|
#messages .from button {
|
||||||
|
color: #33b0f7;
|
||||||
|
}
|
||||||
#messages .text {
|
#messages .text {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
}
|
}
|
||||||
#messages .type {
|
#messages .type {
|
||||||
color: #ccc;
|
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 {
|
#meta {
|
||||||
border-bottom: 1px solid #e9ecef;
|
border-bottom: 1px solid #e9ecef;
|
||||||
@ -244,6 +253,9 @@ button {
|
|||||||
#meta .count {
|
#meta .count {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
#meta .type {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
#users {
|
#users {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -256,7 +268,14 @@ button {
|
|||||||
display: block;
|
display: block;
|
||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
}
|
}
|
||||||
#input {
|
#form {
|
||||||
|
bottom: 0;
|
||||||
|
height: 40px;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 180px;
|
||||||
|
}
|
||||||
|
#form input {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-top: 1px solid #e9ecef;
|
border-top: 1px solid #e9ecef;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -18,20 +18,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<aside id="sidebar">
|
<aside id="sidebar">
|
||||||
<div id="channels">
|
<div id="networks"></div>
|
||||||
<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>
|
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<button id="connect" class="active"></button>
|
<button id="connect" class="active"></button>
|
||||||
<button id="settings"></button>
|
<button id="settings"></button>
|
||||||
@ -44,52 +31,18 @@
|
|||||||
<h1>#channel</h1>
|
<h1>#channel</h1>
|
||||||
</header>
|
</header>
|
||||||
<div id="windows">
|
<div id="windows">
|
||||||
<div id="chat">
|
<div id="chat"></div>
|
||||||
<div class="chat">
|
<form id="form" action="">
|
||||||
<div id="messages">
|
<input id="submit" tabindex="-1" type="submit">
|
||||||
<div class="msg">
|
<input id="input">
|
||||||
<span class="time">00:00</span>
|
</form>
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="templates">
|
<div id="templates">
|
||||||
<script type="text/html" class="networks">
|
<script type="text/html" class="networks">
|
||||||
{{#each networks}}
|
{{#each networks}}
|
||||||
<section class="network">
|
<section class="network" data-id="{{id}}">
|
||||||
{{partial "channels"}}
|
{{partial "channels"}}
|
||||||
</section>
|
</section>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
@ -97,19 +50,35 @@
|
|||||||
|
|
||||||
<script type="text/html" class="channels">
|
<script type="text/html" class="channels">
|
||||||
{{#each channels}}
|
{{#each channels}}
|
||||||
<button class="chan">
|
<button class="chan" data-id="{{id}}" data-type="{{type}}">
|
||||||
<span class="badge"></span>
|
<span class="badge"></span>
|
||||||
Network
|
{{name}}
|
||||||
</button>
|
</button>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</script>
|
</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">
|
<script type="text/html" class="users">
|
||||||
<div id="meta">
|
<div id="meta">
|
||||||
<h1>{{name}}</h1>
|
<h1>{{name}}</h1>
|
||||||
<div class="count">
|
<div class="count">
|
||||||
{{users.length}}
|
{{#if users.length}}
|
||||||
users
|
{{users.length}} users
|
||||||
|
{{else}}
|
||||||
|
<span class="type">
|
||||||
|
{{type}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="users">
|
<div id="users">
|
||||||
@ -121,12 +90,16 @@
|
|||||||
|
|
||||||
<script type="text/html" class="messages">
|
<script type="text/html" class="messages">
|
||||||
{{#each messages}}
|
{{#each messages}}
|
||||||
<div class="msg">
|
<div class="msg {{type}}">
|
||||||
<span class="time">
|
<span class="time">
|
||||||
{{time}}
|
{{time}}
|
||||||
</span>
|
</span>
|
||||||
<span class="from">
|
<span class="from">
|
||||||
|
{{#if from}}
|
||||||
<button>{{from}}</button>
|
<button>{{from}}</button>
|
||||||
|
{{else}}
|
||||||
|
//
|
||||||
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
<span class="text">
|
<span class="text">
|
||||||
<em class="type">{{type}}</em>
|
<em class="type">{{type}}</em>
|
||||||
@ -138,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/components.min.js"></script>
|
<script src="js/components.min.js"></script>
|
||||||
<script src="js/shout.js"></script>
|
<script src="js/chat.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
200
client/js/chat.js
Normal file
200
client/js/chat.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
2
client/js/components.min.js
vendored
2
client/js/components.min.js
vendored
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: "",
|
name: "",
|
||||||
messages: [],
|
messages: [],
|
||||||
users: []
|
users: []
|
||||||
}));
|
}, attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Chan.prototype.sortUsers = function() {
|
Chan.prototype.sortUsers = function() {
|
||||||
|
@ -3,12 +3,13 @@ var Msg = require("../../models/msg");
|
|||||||
module.exports = function(irc, network) {
|
module.exports = function(irc, network) {
|
||||||
var client = this;
|
var client = this;
|
||||||
irc.on("errors", function(data) {
|
irc.on("errors", function(data) {
|
||||||
|
var lobby = network.channels[0];
|
||||||
var msg = new Msg({
|
var msg = new Msg({
|
||||||
type: Msg.Type.ERROR,
|
type: Msg.Type.ERROR,
|
||||||
from: "*",
|
|
||||||
text: data.message,
|
text: data.message,
|
||||||
});
|
});
|
||||||
client.emit("msg", {
|
client.emit("msg", {
|
||||||
|
chan: lobby.id,
|
||||||
msg: msg
|
msg: msg
|
||||||
});
|
});
|
||||||
if (!network.connected) {
|
if (!network.connected) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
var Chan = require("../../models/chan");
|
||||||
var Msg = require("../../models/msg");
|
var Msg = require("../../models/msg");
|
||||||
var User = require("../../models/user");
|
var User = require("../../models/user");
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ module.exports = function(irc, network) {
|
|||||||
});
|
});
|
||||||
chan.messages.push(msg);
|
chan.messages.push(msg);
|
||||||
client.emit("msg", {
|
client.emit("msg", {
|
||||||
id: chan.id,
|
chan: chan.id,
|
||||||
msg: msg
|
msg: msg
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
var Msg = require("../../models/msg");
|
||||||
|
|
||||||
module.exports = function(irc, network) {
|
module.exports = function(irc, network) {
|
||||||
var client = this;
|
var client = this;
|
||||||
|
@ -3,18 +3,17 @@ var Msg = require("../../models/msg");
|
|||||||
module.exports = function(irc, network) {
|
module.exports = function(irc, network) {
|
||||||
var client = this;
|
var client = this;
|
||||||
irc.on("motd", function(data) {
|
irc.on("motd", function(data) {
|
||||||
var lobby = network.channels[0];
|
//var lobby = network.channels[0];
|
||||||
data.motd.forEach(function(text) {
|
//data.motd.forEach(function(text) {
|
||||||
var msg = new Msg({
|
// var msg = new Msg({
|
||||||
type: Msg.Type.MOTD,
|
// type: Msg.Type.MOTD,
|
||||||
from: "*",
|
// text: text
|
||||||
text: text
|
// });
|
||||||
});
|
// lobby.messages.push(msg);
|
||||||
lobby.messages.push(msg);
|
// client.emit("msg", {
|
||||||
client.emit("msg", {
|
// chan: lobby.id,
|
||||||
chan: lobby.id,
|
// msg: msg
|
||||||
msg: msg
|
// });
|
||||||
});
|
//});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,6 @@ module.exports = function(irc, network) {
|
|||||||
if (data["new"] == irc.me) {
|
if (data["new"] == irc.me) {
|
||||||
var lobby = network.channels[0];
|
var lobby = network.channels[0];
|
||||||
var msg = new Msg({
|
var msg = new Msg({
|
||||||
from: "*",
|
|
||||||
text: "You're now known as " + data["new"],
|
text: "You're now known as " + data["new"],
|
||||||
});
|
});
|
||||||
chan.messages.push(msg);
|
chan.messages.push(msg);
|
||||||
|
@ -4,9 +4,9 @@ module.exports = function(irc, network) {
|
|||||||
var client = this;
|
var client = this;
|
||||||
irc.on("notice", function(data) {
|
irc.on("notice", function(data) {
|
||||||
var lobby = network.channels[0];
|
var lobby = network.channels[0];
|
||||||
var from = data.from || "*";
|
var from = data.from || "";
|
||||||
if (data.to == "*" || data.from.indexOf(".") !== -1) {
|
if (data.to == "*" || data.from.indexOf(".") !== -1) {
|
||||||
from = "*";
|
from = "";
|
||||||
}
|
}
|
||||||
var msg = new Msg({
|
var msg = new Msg({
|
||||||
type: Msg.Type.NOTICE,
|
type: Msg.Type.NOTICE,
|
||||||
|
@ -7,7 +7,6 @@ module.exports = function(irc, network) {
|
|||||||
irc.write("PING " + network.host);
|
irc.write("PING " + network.host);
|
||||||
var lobby = network.channels[0];
|
var lobby = network.channels[0];
|
||||||
var msg = new Msg({
|
var msg = new Msg({
|
||||||
from: "*",
|
|
||||||
text: "You're now known as " + data
|
text: "You're now known as " + data
|
||||||
});
|
});
|
||||||
lobby.messages.push(msg);
|
lobby.messages.push(msg);
|
||||||
|
@ -29,7 +29,7 @@ module.exports = function(irc, network) {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
for (var k in data) {
|
for (var k in data) {
|
||||||
var key = prefix[k];
|
var key = prefix[k];
|
||||||
if (!key || data[k].toString() == "") {
|
if (!key || data[k].toString() === "") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var msg = new Msg({
|
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 = io(http().use(http.static("client")).listen(config.port || 9000));
|
||||||
sockets.on("connection", function(socket) {
|
sockets.on("connection", function(socket) {
|
||||||
if (config.public) {
|
if (config.public) {
|
||||||
var client = new Client({sockets: sockets});
|
auth.call(socket);
|
||||||
init(socket, client);
|
|
||||||
connect(client, {host: "irc.rizon.net"});
|
|
||||||
} else {
|
} else {
|
||||||
init(socket);
|
init(socket);
|
||||||
}
|
}
|
||||||
@ -66,13 +64,29 @@ function init(socket, client) {
|
|||||||
socket.on("input", function(data) { input(client, data); });
|
socket.on("input", function(data) { input(client, data); });
|
||||||
socket.join(client.id);
|
socket.join(client.id);
|
||||||
socket.emit("init", {
|
socket.emit("init", {
|
||||||
init: client.networks
|
networks: client.networks
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function auth() {
|
function auth(data) {
|
||||||
var socket = this;
|
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) {
|
function connect(client, args) {
|
||||||
@ -80,25 +94,35 @@ function connect(client, args) {
|
|||||||
host: args.host,
|
host: args.host,
|
||||||
port: args.port || 6667
|
port: args.port || 6667
|
||||||
};
|
};
|
||||||
|
|
||||||
var stream = args.tls ? tls.connect(options) : net.connect(options);
|
var stream = args.tls ? tls.connect(options) : net.connect(options);
|
||||||
stream.on("error", function(e) {
|
stream.on("error", function(e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
var irc = slate(stream);
|
var irc = slate(stream);
|
||||||
irc.nick("shout");
|
irc.nick("shout");
|
||||||
irc.user("shout", "Shout User");
|
irc.user("shout", "Shout User");
|
||||||
|
|
||||||
client.nick = "shout";
|
client.nick = "shout";
|
||||||
|
|
||||||
var network = new Network({
|
var network = new Network({
|
||||||
host: options.host,
|
host: options.host,
|
||||||
irc: irc
|
irc: irc
|
||||||
});
|
});
|
||||||
|
|
||||||
client.networks.push(network);
|
client.networks.push(network);
|
||||||
client.emit("network", {
|
client.emit("network", {
|
||||||
network: network
|
network: network
|
||||||
});
|
});
|
||||||
|
|
||||||
events.forEach(function(plugin) {
|
events.forEach(function(plugin) {
|
||||||
require("./plugins/irc-events/" + plugin).apply(client, [irc, network]);
|
require("./plugins/irc-events/" + plugin).apply(client, [irc, network]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
irc.on("welcome", function() {
|
||||||
|
irc.join("#shout-test");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function input(client, data) {
|
function input(client, data) {
|
||||||
|
Loading…
Reference in New Issue
Block a user