Added link plugin

This commit is contained in:
Mattias Erming 2014-09-27 12:17:05 -07:00
parent ea5f7b2517
commit 2a00fb1bb6
12 changed files with 178 additions and 97 deletions

View File

@ -573,9 +573,31 @@ button {
#chat .action .user:before { #chat .action .user:before {
content: '* '; content: '* ';
} }
#chat .image { #chat .toggle-button {
max-height: 120px; background: #eee;
max-width: 240px; border-radius: 2px;
display: inline-block;
color: #666;
height: 1em;
line-height: 0px;
padding: 0px 6px;
}
#chat .toggle-content {
background: #f5f5f5;
border-radius: 2px;
display: none;
color: #222;
font: 12px Lato;
max-width: 220px;
padding: 6px 8px;
margin-top: 2px;
}
#chat .toggle-content.show {
display: inline-block !important;
}
#chat .toggle-content img {
max-width: 100%;
max-height: 100%;
} }
#chat .count { #chat .count {
background: #fafafa; background: #fafafa;

22
client/js/libs.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,10 @@
Handlebars.registerHelper( Handlebars.registerHelper(
"tz", function(time) { "tz", function(time) {
if (time) {
var utc = moment.utc(time, "HH:mm:ss").toDate(); var utc = moment.utc(time, "HH:mm:ss").toDate();
return moment(utc).format("HH:mm"); return moment(utc).format("HH:mm");
} else {
return "";
}
} }
); );

View File

@ -276,6 +276,10 @@ $(function() {
} }
}); });
socket.on("toggle", function(data) {
$("#toggle-" + data.id).parent().after(render("toggle", data));
});
socket.on("users", function(data) { socket.on("users", function(data) {
var users = chat.find("#chan-" + data.chan) var users = chat.find("#chan-" + data.chan)
.find(".users") .find(".users")
@ -559,6 +563,11 @@ $(function() {
}); });
}); });
chat.on("click", ".toggle-button", function() {
var self = $(this);
self.parent().next(".toggle-content").toggleClass("show");
});
var windows = $("#windows"); var windows = $("#windows");
var forms = $("#sign-in, #connect"); var forms = $("#sign-in, #connect");

View File

@ -84,7 +84,7 @@ templates['msg'] = template({"1":function(depth0,helpers,partials,data) {
buffer += " </span>\n <span class=\"text\">\n <em class=\"type\">" buffer += " </span>\n <span class=\"text\">\n <em class=\"type\">"
+ escapeExpression(((helper = (helper = helpers.type || (depth0 != null ? depth0.type : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"type","hash":{},"data":data}) : helper))) + escapeExpression(((helper = (helper = helpers.type || (depth0 != null ? depth0.type : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"type","hash":{},"data":data}) : helper)))
+ "</em>\n"; + "</em>\n";
stack1 = ((helpers.equal || (depth0 && depth0.equal) || helperMissing).call(depth0, (depth0 != null ? depth0.type : depth0), "image", {"name":"equal","hash":{},"fn":this.program(6, data),"inverse":this.program(8, data),"data":data})); stack1 = ((helpers.equal || (depth0 && depth0.equal) || helperMissing).call(depth0, (depth0 != null ? depth0.type : depth0), "toggle", {"name":"equal","hash":{},"fn":this.program(6, data),"inverse":this.program(8, data),"data":data}));
if (stack1 != null) { buffer += stack1; } if (stack1 != null) { buffer += stack1; }
return buffer + " </span>\n</div>\n"; return buffer + " </span>\n</div>\n";
},"2":function(depth0,helpers,partials,data) { },"2":function(depth0,helpers,partials,data) {
@ -96,9 +96,9 @@ templates['msg'] = template({"1":function(depth0,helpers,partials,data) {
+ "</button>\n"; + "</button>\n";
},"6":function(depth0,helpers,partials,data) { },"6":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return " <img src=\"" return " <div class=\"force-newline\">\n <button id=\"toggle-"
+ escapeExpression(((helper = (helper = helpers.text || (depth0 != null ? depth0.text : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"text","hash":{},"data":data}) : helper))) + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper)))
+ "\" class=\"image\">\n"; + "\" class=\"toggle-button\">···</button>\n </div>\n";
},"8":function(depth0,helpers,partials,data) { },"8":function(depth0,helpers,partials,data) {
var stack1, helperMissing=helpers.helperMissing, buffer = " "; var stack1, helperMissing=helpers.helperMissing, buffer = " ";
stack1 = ((helpers.uri || (depth0 && depth0.uri) || helperMissing).call(depth0, (depth0 != null ? depth0.text : depth0), {"name":"uri","hash":{},"data":data})); stack1 = ((helpers.uri || (depth0 && depth0.uri) || helperMissing).call(depth0, (depth0 != null ? depth0.text : depth0), {"name":"uri","hash":{},"data":data}));
@ -127,6 +127,26 @@ templates['network'] = template({"1":function(depth0,helpers,partials,data) {
if (stack1 != null) { buffer += stack1; } if (stack1 != null) { buffer += stack1; }
return buffer; return buffer;
},"useData":true}); },"useData":true});
templates['toggle'] = template({"1":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return " <a href=\""
+ escapeExpression(((helper = (helper = helpers.body || (depth0 != null ? depth0.body : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"body","hash":{},"data":data}) : helper)))
+ "\" target=\"_blank\">\n <img src=\""
+ escapeExpression(((helper = (helper = helpers.body || (depth0 != null ? depth0.body : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"body","hash":{},"data":data}) : helper)))
+ "\">\n </a>\n";
},"3":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return " <div class=\"head\">"
+ escapeExpression(((helper = (helper = helpers.head || (depth0 != null ? depth0.head : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"head","hash":{},"data":data}) : helper)))
+ "</div>\n <div class=\"body\">\n "
+ escapeExpression(((helper = (helper = helpers.body || (depth0 != null ? depth0.body : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"body","hash":{},"data":data}) : helper)))
+ "\n </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var stack1, helperMissing=helpers.helperMissing, buffer = "<div class=\"toggle-content\">\n";
stack1 = ((helpers.equal || (depth0 && depth0.equal) || helperMissing).call(depth0, (depth0 != null ? depth0.type : depth0), "image", {"name":"equal","hash":{},"fn":this.program(1, data),"inverse":this.program(3, data),"data":data}));
if (stack1 != null) { buffer += stack1; }
return buffer + " </div>\n</div>\n";
},"useData":true});
templates['user'] = template({"1":function(depth0,helpers,partials,data) { templates['user'] = template({"1":function(depth0,helpers,partials,data) {
var stack1, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; var stack1, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return "<div class=\"count\">\n <input class=\"search\" placeholder=\"" return "<div class=\"count\">\n <input class=\"search\" placeholder=\""

View File

@ -10,8 +10,10 @@
</span> </span>
<span class="text"> <span class="text">
<em class="type">{{type}}</em> <em class="type">{{type}}</em>
{{#equal type "image"}} {{#equal type "toggle"}}
<img src="{{text}}" class="image"> <div class="force-newline">
<button id="toggle-{{id}}" class="toggle-button">···</button>
</div>
{{else}} {{else}}
{{{uri text}}} {{{uri text}}}
{{/equal}} {{/equal}}

View File

@ -0,0 +1,13 @@
<div class="toggle-content">
{{#equal type "image"}}
<a href="{{body}}" target="_blank">
<img src="{{body}}">
</a>
{{else}}
<div class="head">{{head}}</div>
<div class="body">
{{body}}
</div>
{{/equal}}
</div>
</div>

View File

@ -33,8 +33,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bcrypt": "^0.8.0", "bcrypt": "^0.8.0",
"cheerio": "^0.17.0",
"commander": "^2.3.0", "commander": "^2.3.0",
"connect": "~2.19.6",
"express": "^4.9.5", "express": "^4.9.5",
"lodash": "~2.4.1", "lodash": "~2.4.1",
"mkdirp": "^0.5.0", "mkdirp": "^0.5.0",

View File

@ -15,12 +15,12 @@ var id = 0;
var events = [ var events = [
"ctcp", "ctcp",
"error", "error",
"image",
"join", "join",
"kick", "kick",
"mode", "mode",
"motd", "motd",
"message", "message",
"link",
"names", "names",
"nick", "nick",
"notice", "notice",

View File

@ -4,7 +4,6 @@ var moment = require("moment");
Msg.Type = { Msg.Type = {
ACTION: "action", ACTION: "action",
ERROR: "error", ERROR: "error",
IMAGE: "image",
JOIN: "join", JOIN: "join",
KICK: "kick", KICK: "kick",
MESSAGE: "message", MESSAGE: "message",
@ -14,15 +13,19 @@ Msg.Type = {
NOTICE: "notice", NOTICE: "notice",
PART: "part", PART: "part",
QUIT: "quit", QUIT: "quit",
TOGGLE: "toggle",
TOPIC: "topic", TOPIC: "topic",
WHOIS: "whois" WHOIS: "whois"
}; };
module.exports = Msg; module.exports = Msg;
var id = 0;
function Msg(attr) { function Msg(attr) {
_.merge(this, _.extend({ _.merge(this, _.extend({
from: "", from: "",
id: id++,
text: "", text: "",
time: moment().utc().format("HH:mm:ss"), time: moment().utc().format("HH:mm:ss"),
type: Msg.Type.MESSAGE, type: Msg.Type.MESSAGE,

View File

@ -1,72 +0,0 @@
var _ = require("lodash");
var Msg = require("../../models/msg");
var config = require("../../../config");
var fs = require("fs");
var mkdirp = require("mkdirp");
var request = require("superagent");
var Helper = require("../../helper");
module.exports = function(irc, network) {
var client = this;
irc.on("message", function(data) {
var image = "";
var split = data.message.split(" ");
_.each(split, function(w) {
var match = w.match(/^(http|https).*\.(gif|png|jpg|jpeg)$/i);
if (match !== null) {
image = w;
}
});
if (image === "") {
return;
}
var target = data.to;
var chan = _.findWhere(network.channels, {name: target.charAt(0) == "#" ? target : data.from});
if (typeof chan === "undefined") {
return;
}
var self = false;
if (data.from.toLowerCase() == irc.me.toLowerCase()) {
self = true;
}
fetchImage(image, function(name) {
var msg = new Msg({
type: Msg.Type.IMAGE,
from: data.from,
text: "thumbs/" + name,
self: self
});
chan.messages.push(msg);
client.emit("msg", {
chan: chan.id,
msg: msg
});
});
});
};
function fetchImage(url, callback) {
var path = Helper.resolveHomePath("cache", "thumbs");
var name = new Date().getTime().toString();
mkdirp(path, function(e) {
if (e) {
console.log(e);
return;
}
var stream = fs.createWriteStream(
path + "/" + name,
{mode: "0777"}
);
var req = request.get(url);
req.pipe(stream);
req.on("error", function(e) {
console.log(e);
});
req.on("end", function() {
if (this.req.res.statusCode == 200) {
callback(name);
}
});
});
}

View File

@ -0,0 +1,80 @@
var _ = require("lodash");
var Msg = require("../../models/msg");
var request = require("superagent");
module.exports = function(irc, network) {
var client = this;
irc.on("message", function(data) {
var links = [];
var split = data.message.split(" ");
_.each(split, function(w) {
var match = w.indexOf("http://") === 0 || w.indexOf("https://") === 0;
if (match) {
links.push(w);
}
});
if (links.length === 0) {
return;
}
var self = data.to.toLowerCase() == irc.me.toLowerCase();
var chan = _.findWhere(network.channels, {name: self ? data.from : data.to});
if (typeof chan === "undefined") {
return;
}
var msg = new Msg({
type: Msg.Type.TOGGLE,
time: ""
});
chan.messages.push(msg);
client.emit("msg", {
chan: chan.id,
msg: msg
});
_.each(links, function(url) {
fetch(url, function(res) {
parse(msg.id, url, res, client);
});
});
});
};
function parse(id, url, res, client) {
var head = "";
var body = "";
var type = "";
switch (res.type) {
case "text/html":
type = "link";
break;
case "image/png":
case "image/gif":
case "image/jpg":
case "image/jpeg":
type = "image";
body = url;
break;
default:
return;
}
client.emit("toggle", {
id: id,
type: type,
head: type,
body: body
});
}
function fetch(url, cb) {
var req = request.get(url);
req.end(function(e, res) {
if (res) {
cb(res);
}
});
}