Comparing version 1.0.0-alpha2 to 1.0.0-alpha3
@@ -6,2 +6,4 @@ $(function() { | ||
var commands = [ | ||
"/ame", | ||
"/amsg", | ||
"/close", | ||
@@ -12,2 +14,3 @@ "/connect", | ||
"/disconnect", | ||
"/invite", | ||
"/join", | ||
@@ -22,2 +25,3 @@ "/kick", | ||
"/part", | ||
"/partall", | ||
"/query", | ||
@@ -29,2 +33,3 @@ "/quit", | ||
"/server", | ||
"/slap", | ||
"/topic", | ||
@@ -61,11 +66,11 @@ "/voice", | ||
.last() | ||
.find(".messages") | ||
.scrollGlue({speed: 400}) | ||
.find(".chat") | ||
.sticky({speed: 400, overflow: "auto"}) | ||
.end() | ||
.find(".input") | ||
.tabComplete(commands); | ||
.tabComplete(commands, {hint: false}); | ||
$("#network-" + data.id) | ||
.append(render("channels", {channels: [data.chan]})) | ||
.find(".channel") | ||
.find("a") | ||
.last() | ||
@@ -85,3 +90,3 @@ .trigger("click"); | ||
.find(".input") | ||
.tabComplete(commands) | ||
.tabComplete(commands, {hint: false}) | ||
.end() | ||
@@ -91,22 +96,11 @@ .find(".hidden") | ||
.show(); | ||
chat.find(".messages") | ||
.scrollGlue({speed: 400}) | ||
chat.find(".chat") | ||
.sticky({speed: 400, overflow: "auto"}) | ||
.end(); | ||
var networks = $("#networks") | ||
.html(render("networks", {networks: data.networks})); | ||
var target = null; | ||
if (location.hash) { | ||
var id = location.hash; | ||
target = sidebar | ||
.find("button[data-target='" + id + "']"); | ||
} else { | ||
target = sidebar | ||
.find("#networks") | ||
.find("button") | ||
.last() | ||
} | ||
target.trigger("click"); | ||
.html(render("networks", {networks: data.networks})) | ||
.find("a") | ||
.last() | ||
.trigger("click"); | ||
break; | ||
@@ -129,11 +123,11 @@ | ||
var z = 1; | ||
sidebar.on("click", "button", function() { | ||
var button = $(this); | ||
var target = button.data("target"); | ||
sidebar.on("click", "a", function(e) { | ||
e.preventDefault(); | ||
var link = $(this); | ||
var target = link.attr("href"); | ||
if (!target) { | ||
return; | ||
} | ||
location.hash = target; | ||
sidebar.find(".active").removeClass("active"); | ||
button.addClass("active") | ||
link.addClass("active") | ||
.find(".badge") | ||
@@ -143,3 +137,7 @@ .removeClass("highlight") | ||
var window = $(target) | ||
.siblings() | ||
.removeClass("active") | ||
.end() | ||
.css("z-index", z++) | ||
.addClass("active") | ||
.find("input") | ||
@@ -149,6 +147,38 @@ .focus(); | ||
sidebar.on("click", "#menu .btn", function() { | ||
$("#menu").toggleClass("visible"); | ||
sidebar.on("click", ".close", function() { | ||
var channel = $(this).closest("a"); | ||
var id = parseInt(channel.attr("id").split("-")[1]); | ||
var cmd = "/close"; | ||
if (channel.hasClass("lobby")) { | ||
cmd = "/quit"; | ||
var server = channel | ||
.clone() | ||
.remove("span") | ||
.text() | ||
.trim(); | ||
if (!confirm("Disconnect from " + server + "?")) { | ||
return false; | ||
} | ||
} | ||
socket.emit("input", { | ||
id: id, | ||
text: cmd, | ||
}); | ||
channel.css({ | ||
transition: "none", | ||
opacity: .4 | ||
}); | ||
return false; | ||
}); | ||
var viewport = $("#viewport"); | ||
chat.on("click", ".lt, .rt", function() { | ||
var btn = $(this); | ||
viewport.toggleClass(btn.attr("class")); | ||
}); | ||
chat.on("focus", ".input", function() { | ||
viewport.removeClass(); | ||
}); | ||
chat.on("append", ".messages", function() { | ||
@@ -173,3 +203,4 @@ var messages = $(this); | ||
chat.on("click", ".user", function() { | ||
chat.on("click", ".user", function(e) { | ||
e.preventDefault(); | ||
var user = $(this); | ||
@@ -188,6 +219,7 @@ var id = user.closest(".window").find(".form").data("target"); | ||
chat.on("focus", ".input", function() { | ||
$(this).closest(".window").find(".messages").scrollToBottom(); | ||
$(this).closest(".window").find(".chat").scrollToBottom(); | ||
}); | ||
chat.on("submit", "form", function() { | ||
chat.on("submit", "form", function(e) { | ||
e.preventDefault(); | ||
var form = $(this); | ||
@@ -200,2 +232,3 @@ var input = form.find(".input:not(.hint)"); | ||
input.val(""); | ||
input.prev(".hint").val(""); | ||
socket.emit("input", { | ||
@@ -207,3 +240,22 @@ id: form.data("target"), | ||
function escape(text) { | ||
var e = { | ||
"<": "<", | ||
">": ">" | ||
}; | ||
return text.replace(/[<>]/g, function (c) { | ||
return e[c]; | ||
}); | ||
} | ||
Handlebars.registerHelper( | ||
"uri", function(text) { | ||
text = escape(text); | ||
return URI.withinString(text, function(url) { | ||
return "<a href='" + url.replace(/^www/, "//www") + "' target='_blank'>" + url + "</a>"; | ||
}); | ||
} | ||
); | ||
Handlebars.registerHelper( | ||
"partial", function(id) { | ||
@@ -210,0 +262,0 @@ return new Handlebars.SafeString(render(id, this)); |
/*! | ||
* inputHistory | ||
* https://github.com/erming/inputHistory | ||
* stickyScroll | ||
* https://github.com/erming/stickyScroll | ||
* | ||
@@ -8,72 +8,6 @@ * Copyright (c) 2014 Mattias Erming <mattias@mattiaserming.com> | ||
* | ||
* Version 0.1.2 | ||
*/ | ||
(function($) { | ||
$.fn.inputHistory = function(options) { | ||
var settings = $.extend({ | ||
history: [], | ||
submit: false, | ||
}, options); | ||
var self = this; | ||
if (self.size() > 1) { | ||
return self.each(function() { | ||
$(this).inputHistory(options); | ||
}); | ||
} | ||
self.data('history', settings.history.concat([''])); | ||
var i = 0; | ||
self.on('keydown', function(e) { | ||
var history = self.data('history'); | ||
var key = e.which; | ||
switch (key) { | ||
case 13: // Enter | ||
if (self.val() != '') { | ||
i = history.length; | ||
history[i - 1] = self.val(); | ||
history.push(''); | ||
} | ||
if (settings.submit) { | ||
self.parents('form').eq(0).submit(); | ||
} | ||
self.val(''); | ||
break; | ||
case 38: // Up | ||
case 40: // Down | ||
history[i] = self.val(); | ||
if (key == 38 && i != 0) { | ||
i--; | ||
} else if (key == 40 && i < history.length - 1) { | ||
i++; | ||
} | ||
self.val(history[i]); | ||
break; | ||
default: | ||
return; | ||
} | ||
return false; | ||
}); | ||
return this; | ||
} | ||
})(jQuery); | ||
/*! | ||
* scrollGlue | ||
* https://github.com/erming/scrollGlue | ||
* | ||
* Copyright (c) 2014 Mattias Erming <mattias@mattiaserming.com> | ||
* Licensed under the MIT License. | ||
* | ||
* Version 1.2.1 | ||
*/ | ||
(function($) { | ||
$.fn.scrollGlue = function(options) { | ||
$.fn.sticky = function(options) { | ||
var settings = $.extend({ | ||
@@ -89,3 +23,3 @@ disableManualScroll: false, | ||
return self.each(function() { | ||
$(this).scrollGlue(options); | ||
$(this).sticky(options); | ||
}); | ||
@@ -161,2 +95,5 @@ } | ||
* tabComplete | ||
* Lightweight tab completion for <input> and <textarea> | ||
* | ||
* Source: | ||
* https://github.com/erming/tabComplete | ||
@@ -167,18 +104,12 @@ * | ||
* | ||
* Version 1.0.0-alpha2 | ||
* Version 1.1.1 | ||
*/ | ||
(function($) { | ||
var defaults = { | ||
after: "", | ||
caseSensitive: false, | ||
hint: true, | ||
minLength: 1, | ||
var keys = { | ||
tab: 9, | ||
up: 38, | ||
down: 40 | ||
}; | ||
$.fn.tabComplete = function(args, options) { | ||
var self = this; | ||
options = $.extend( | ||
{}, defaults, options | ||
); | ||
if (this.length > 1) { | ||
@@ -190,7 +121,18 @@ return this.each(function() { | ||
if (options.hint) { | ||
// Lets turn on hinting. | ||
hint.call(self, ""); | ||
// 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({ | ||
after: "", | ||
arrowKeys: tag == "INPUT" ? true : false, | ||
caseSensitive: false, | ||
hint: true, | ||
minLength: 1, | ||
onTabComplete: $.noop | ||
}, options); | ||
// Unbind namespace. | ||
@@ -200,3 +142,4 @@ // This allows us to override the plugin if necessary. | ||
var i = 0; | ||
var self = this; | ||
var i = -1; | ||
var words = []; | ||
@@ -210,3 +153,3 @@ var last = ""; | ||
if (!word) { | ||
i = 0; | ||
i = -1; | ||
words = []; | ||
@@ -223,2 +166,5 @@ last = ""; | ||
// Emit the number of matching words with the 'match' event. | ||
self.trigger("match", words.length); | ||
if (options.hint) { | ||
@@ -237,8 +183,22 @@ if (word.length >= options.minLength && words.length) { | ||
var key = e.which; | ||
if (key == 9) { | ||
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]; | ||
var word = words[i % words.length]; | ||
if (!word) { | ||
@@ -264,2 +224,8 @@ return; | ||
// Trigger callback. | ||
options.onTabComplete(last); | ||
// Trigger the 'tabComplete' event on a successful complete. | ||
self.trigger("tabComplete", last); | ||
if (options.hint) { | ||
@@ -272,2 +238,7 @@ // Turn off any additional hinting. | ||
if (options.hint) { | ||
// If enabled, turn on hinting. | ||
hint.call(this, ""); | ||
} | ||
return this; | ||
@@ -291,3 +262,3 @@ } | ||
// Add input hinting. | ||
// Input hinting. | ||
// This works by creating a copy of the input and placing it behind | ||
@@ -312,3 +283,3 @@ // the real input. | ||
.clone() | ||
.prop("disabled", true) | ||
.attr("tabindex", -1) | ||
.removeAttr("id name placeholder") | ||
@@ -315,0 +286,0 @@ .addClass("hint") |
@@ -9,3 +9,3 @@ var _ = require("lodash"); | ||
name: "", | ||
type: "", | ||
type: "channel", | ||
messages: [], | ||
@@ -12,0 +12,0 @@ users: [], |
@@ -167,2 +167,4 @@ var _ = require("lodash"); | ||
case "slap": | ||
var slap = "slaps " + args[1] + " around a bit with a large trout"; | ||
case "me": | ||
@@ -173,3 +175,3 @@ if (!args[1]) { | ||
var user; | ||
var text = args.slice(1).join(" "); | ||
var text = slap || args.slice(1).join(" "); | ||
if (client) { | ||
@@ -191,2 +193,29 @@ user = client.me; | ||
case "ame": | ||
var type = "action"; | ||
case "amsg": | ||
var user = client.me; | ||
var text = args.slice(1).join(" "); | ||
var channels = []; | ||
network.channels.forEach(function(chan) { | ||
if (chan.type == "channel") { | ||
channels.push(chan.name); | ||
var msg = new Msg({ | ||
type: type || "normal", | ||
from: user, | ||
text: text, | ||
}); | ||
chan.messages.push(msg) | ||
sockets.emit("msg", { | ||
id: chan.id, | ||
msg: msg, | ||
}); | ||
} | ||
}); | ||
client[type || "send"]( | ||
channels, | ||
text | ||
); | ||
break; | ||
case "server": | ||
@@ -200,11 +229,22 @@ case "connect": | ||
case "join": | ||
if (client && args[1]) { | ||
client.join(args.slice(1)); | ||
} | ||
break; | ||
case "nick": | ||
if (client && args[1]) { | ||
client[cmd].apply(client, args.slice(1)); | ||
client.nick(args[1]); | ||
} | ||
break; | ||
case "part": | ||
if (chan.type != "channel") { | ||
return; | ||
} | ||
case "close": | ||
case "leave": | ||
case "part": | ||
if (chan.type == "lobby") { | ||
return; | ||
} | ||
var id = chan.id; | ||
@@ -221,2 +261,16 @@ if (chan.type == "query" || !chan.users.length) { | ||
case "partall": | ||
var part = []; | ||
network.channels.forEach(function(c) { | ||
if (c.type == "channel") part.push(c.name); | ||
}); | ||
client.part(part); | ||
break; | ||
case "invite": | ||
if (client && args[2]) { | ||
client.invite(args[1], args[2]); | ||
} | ||
break; | ||
case "topic": | ||
@@ -288,2 +342,3 @@ if (client) { | ||
if (client) { | ||
console.log(args.slice(1).join(" ")); | ||
client.write(args.slice(1).join(" ")); | ||
@@ -333,3 +388,2 @@ } | ||
if (typeof chan === "undefined") { | ||
// TODO: Throw error | ||
break; | ||
@@ -361,6 +415,13 @@ } | ||
if (typeof chan !== "undefined") { | ||
this.client.write("NAMES " + data.target); | ||
clearTimeout(this.timer); | ||
this.timer = setTimeout((function() { | ||
this.client.write("NAMES " + data.target); | ||
}).bind(this), 200); | ||
var nick = data.nick; | ||
if (nick.indexOf(".") !== -1) { | ||
nick = data.target; | ||
} | ||
var msg = new Msg({ | ||
type: "mode", | ||
from: data.nick, | ||
from: nick, | ||
text: data.mode + " " + data.client, | ||
@@ -431,3 +492,2 @@ }); | ||
if (typeof chan === "undefined") { | ||
// TODO: Throw error | ||
break; | ||
@@ -488,5 +548,9 @@ } | ||
var chan = channels[0]; | ||
var from = data.from || "-!-"; | ||
if (data.to == "*" || data.from.indexOf(".") !== -1) { | ||
from = "-!-"; | ||
} | ||
var msg = new Msg({ | ||
type: "notice", | ||
from: (data.to == "*" ? "-!-" : data.from) || "-!-", | ||
from: from, | ||
text: data.message, | ||
@@ -504,3 +568,2 @@ }); | ||
if (typeof chan === "undefined") { | ||
// TODO: Throw error | ||
break; | ||
@@ -557,3 +620,2 @@ } | ||
if (typeof chan === "undefined") { | ||
// TODO: Throw error | ||
break; | ||
@@ -560,0 +622,0 @@ } |
{ | ||
"name": "shout", | ||
"description": "The modern IRC client", | ||
"version": "1.0.0-alpha2", | ||
"version": "1.0.0-alpha3", | ||
"homepage": "http://github.com/erming/shout", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -6,4 +6,4 @@ ## shout | ||
These are the commands currently implemented: | ||
- [ ] /ame | ||
- [ ] /amsg | ||
- [x] /ame | ||
- [x] /amsg | ||
- [x] /close | ||
@@ -15,3 +15,3 @@ - [x] /connect | ||
- [ ] /help | ||
- [ ] /invite | ||
- [x] /invite | ||
- [x] /join | ||
@@ -27,3 +27,3 @@ - [x] /kick | ||
- [x] /part | ||
- [ ] /partall | ||
- [x] /partall | ||
- [x] /query | ||
@@ -35,2 +35,3 @@ - [x] /quit | ||
- [x] /server | ||
- [x] /slap | ||
- [ ] /time | ||
@@ -37,0 +38,0 @@ - [x] /topic |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
228796
4098
119
18