glowing-bear/js/handlers.js

537 lines
20 KiB
JavaScript

(function() {
'use strict';
var weechat = angular.module('weechat');
weechat.factory('handlers', ['$rootScope', '$log', 'models', 'plugins', 'notifications', 'bufferResume', function($rootScope, $log, models, plugins, notifications, bufferResume) {
var handleVersionInfo = function(message) {
var content = message.objects[0].content;
var version = content.value;
// Store the WeeChat version in models
// this eats things like 1.3-dev -> [1,3]
models.version = version.split(".").map(function(c) { return parseInt(c); });
};
var handleConfValue = function(message) {
var infolist = message.objects[0].content;
for (var i = 0; i < infolist.length ; i++) {
var key, val;
var item = infolist[i];
for (var j = 0; j < item.length ; j++) {
var confitem = item[j];
if (confitem.full_name) {
key = confitem.full_name;
}
if (confitem.value) {
val = confitem.value;
}
}
if (key && val) {
$log.debug('Setting wconfig "' + key + '" to value "' + val + '"');
models.wconfig[key] = val;
}
}
};
var handleBufferClosing = function(message) {
var bufferMessage = message.objects[0].content[0];
var bufferId = bufferMessage.pointers[0];
models.closeBuffer(bufferId);
};
// inject a fake buffer line for date change if needed
var injectDateChangeMessageIfNeeded = function(buffer, manually, old_date, new_date) {
if (buffer.bufferType === 1) {
// Don't add date change messages to free buffers
return;
}
old_date.setHours(0, 0, 0, 0);
new_date.setHours(0, 0, 0, 0);
// Check if the date changed
if (old_date.valueOf() !== new_date.valueOf()) {
if (manually) {
// if the message that caused this date change to be sent
// would increment buffer.lastSeen, we should increment as
// well.
++buffer.lastSeen;
}
var old_date_plus_one = old_date;
old_date_plus_one.setDate(old_date.getDate() + 1);
// it's not always true that a date with time 00:00:00
// plus one day will be time 00:00:00
old_date_plus_one.setHours(0, 0, 0, 0);
var content = "\u001943"; // this colour corresponds to chat_day_change
// Add day of the week
if ($rootScope.supports_formatting_date) {
content += new_date.toLocaleDateString(window.navigator.language,
{weekday: "long"});
} else {
// Gross code that only does English dates ew gross
var dow_to_word = [
"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"];
content += dow_to_word[new_date.getDay()];
}
// if you're testing different date formats,
// make sure to test different locales such as "en-US",
// "en-US-u-ca-persian" (which has different weekdays, year 0, and an ERA)
// "ja-JP-u-ca-persian-n-thai" (above, diff numbering, diff text)
var extra_date_format = {
day: "numeric",
month: "long"
};
if (new_date.getYear() !== old_date.getYear()) {
extra_date_format.year = "numeric";
}
content += " (";
if ($rootScope.supports_formatting_date) {
content += new_date.toLocaleDateString(window.navigator.language,
extra_date_format);
} else {
// ew ew not more gross code
var month_to_word = [
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"];
content += month_to_word[new_date.getMonth()] + " " + new_date.getDate().toString();
if (extra_date_format.year === "numeric") {
content += ", " + new_date.getFullYear().toString();
}
}
// Result should be something like
// Friday (November 27)
// or if the year is different,
// Friday (November 27, 2015)
// Comparing dates in javascript is beyond tedious
if (old_date_plus_one.valueOf() !== new_date.valueOf()) {
var date_diff = Math.round((new_date - old_date)/(24*60*60*1000)) + 1;
if (date_diff < 0) {
date_diff = -1*(date_diff);
if (date_diff === 1) {
content += ", 1 day before";
} else {
content += ", " + date_diff + " days before";
}
} else {
content += ", " + date_diff + " days later";
}
// Result: Friday (November 27, 5 days later)
}
content += ")";
var line = {
buffer: buffer.id,
date: new_date,
prefix: '\u001943\u2500',
tags_array: [],
displayed: true,
highlight: 0,
message: content
};
var new_message = new models.BufferLine(line);
buffer.addLine(new_message);
}
};
var handleLine = function(line, manually) {
var message = new models.BufferLine(line);
var buffer = models.getBuffer(message.buffer);
buffer.requestedLines++;
// Only react to line if its displayed
if (message.displayed) {
// Check for date change
if (buffer.lines.length > 0) {
var old_date = new Date(buffer.lines[buffer.lines.length - 1].date),
new_date = new Date(message.date);
injectDateChangeMessageIfNeeded(buffer, manually, old_date, new_date);
}
message = plugins.PluginManager.contentForMessage(message);
buffer.addLine(message);
if (manually) {
buffer.lastSeen++;
}
if (buffer.active && !manually) {
$rootScope.scrollWithBuffer();
}
if (!manually && (!buffer.active || !$rootScope.isWindowFocused())) {
var server = models.getServerForBuffer(buffer);
if (buffer.notify > 1 && _.contains(message.tags, 'notify_message') && !_.contains(message.tags, 'notify_none')) {
buffer.unread++;
server.unread++;
$rootScope.$emit('notificationChanged');
}
if ((buffer.notify !== 0) && (message.highlight || _.contains(message.tags, 'notify_private'))) {
buffer.notification++;
server.unread++;
notifications.createHighlight(buffer, message);
$rootScope.$emit('notificationChanged');
}
}
}
};
var handleBufferInfo = function(message) {
var bufferInfos = message.objects[0].content;
// buffers objects
for (var i = 0; i < bufferInfos.length ; i++) {
var bufferId = bufferInfos[i].pointers[0];
var buffer = models.getBuffer(bufferId);
if (buffer !== undefined) {
// We already know this buffer
handleBufferUpdate(buffer, bufferInfos[i]);
} else {
buffer = new models.Buffer(bufferInfos[i]);
if (buffer.type === 'server') {
models.registerServer(buffer);
} else {
var server = models.getServerForBuffer(buffer);
server.unread += buffer.unread + buffer.notification;
}
models.addBuffer(buffer);
// Switch to first buffer on startup
var shouldResume = bufferResume.shouldResume(buffer);
if(shouldResume){
models.setActiveBuffer(buffer.id);
}
}
}
// If there was no buffer to autmatically load, go to the first one.
if (!bufferResume.wasAbleToResume()) {
var first = bufferInfos[0].pointers[0];
models.setActiveBuffer(first);
}
};
var handleBufferUpdate = function(buffer, message) {
if (message.pointers[0] !== buffer.id) {
// this is information about some other buffer!
return;
}
// weechat properties -- short name can be changed
buffer.shortName = message.short_name;
buffer.trimmedName = buffer.shortName.replace(/^[#&+]/, '');
buffer.title = message.title;
buffer.number = message.number;
buffer.hidden = message.hidden;
// reset unread counts, hotlist info will arrive shortly
var server = models.getServerForBuffer(buffer);
server.unread -= (buffer.unread + buffer.notification);
buffer.notification = 0;
buffer.unread = 0;
buffer.lastSeen = -1;
if (message.local_variables.type !== undefined) {
buffer.type = message.local_variables.type;
buffer.indent = (['channel', 'private'].indexOf(buffer.type) >= 0);
}
if (message.notify !== undefined) {
buffer.notify = message.notify;
}
};
var handleBufferLineAdded = function(message) {
message.objects[0].content.forEach(function(l) {
handleLine(l, false);
});
};
var handleBufferOpened = function(message) {
var bufferMessage = message.objects[0].content[0];
var buffer = new models.Buffer(bufferMessage);
if (buffer.type === 'server') {
models.registerServer(buffer);
} else {
var server = models.getServerForBuffer(buffer);
server.unread += buffer.unread + buffer.notification;
}
models.addBuffer(buffer);
};
var handleBufferTitleChanged = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
old.fullName = obj.full_name;
old.title = models.parseRichText(obj.title);
old.number = obj.number;
old.rtitle = "";
for (var i = 0; i < old.title.length; ++i) {
old.rtitle += old.title[i].text;
}
};
var handleBufferRenamed = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
old.fullName = obj.full_name;
old.shortName = obj.short_name;
// If it's a channel, trim away the prefix (#, &, or +). If that is empty and the buffer
// has a short name, use a space (because the prefix will be displayed separately, and we don't want
// prefix + fullname, which would happen otherwise). Else, use null so that full_name is used
old.trimmedName = obj.short_name.replace(/^[#&+]/, '') || (obj.short_name ? ' ' : null);
old.prefix = ['#', '&', '+'].indexOf(obj.short_name.charAt(0)) >= 0 ? obj.short_name.charAt(0) : '';
// After a buffer openes we get the name change event from relay protocol
// Here we check our outgoing commands that openes a buffer and switch
// to it if we find the buffer name it the list
var position = models.outgoingQueries.indexOf(old.shortName);
if (position >= 0) {
models.outgoingQueries.splice(position, 1);
models.setActiveBuffer(old.id);
}
};
var handleBufferMoved = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
var old_number = old.number;
var new_number = obj.number;
_.each(models.getBuffers(), function(buffer) {
if (buffer.number > old_number && buffer.number <= new_number) {
buffer.number -= 1;
}
if (buffer.number < old_number && buffer.number >= new_number) {
buffer.number += 1;
}
});
old.number = new_number;
};
var handleBufferHidden = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
old.hidden = true;
};
var handleBufferUnhidden = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
old.hidden = false;
};
var handleBufferLocalvarChanged = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
var old = models.getBuffer(buffer);
var localvars = obj.local_variables;
if (old !== undefined && localvars !== undefined) {
// Update indentation status
old.type = localvars.type;
old.indent = (['channel', 'private'].indexOf(localvars.type) >= 0);
// Update serverSortKey and related variables
old.plugin = localvars.plugin;
old.server = localvars.server;
old.serverSortKey = old.plugin + "." + old.server +
(old.type === "server" ? "" : ("." + old.shortName));
old.pinned = localvars.pinned === "true";
}
};
var handleBufferTypeChanged = function(message) {
var obj = message.objects[0].content[0];
var buffer = obj.pointers[0];
//var old = models.getBuffer(buffer);
// 0 = formatted (normal); 1 = free
buffer.bufferType = obj.type;
};
/*
* Handle answers to (lineinfo) messages
*
* (lineinfo) messages are specified by this client. It is request after bufinfo completes
*/
var handleLineInfo = function(message, manually) {
var lines = message.objects[0].content.reverse();
if (manually === undefined) {
manually = true;
}
lines.forEach(function(l) {
handleLine(l, manually);
});
if (message.objects[0].content.length > 0) {
// fiddle out the buffer ID and take the last line's date
var last_line =
message.objects[0].content[message.objects[0].content.length-1];
var buffer = models.getBuffer(last_line.buffer);
if (buffer.lines.length > 0) {
var last_date = new Date(buffer.lines[buffer.lines.length - 1].date);
injectDateChangeMessageIfNeeded(buffer, true, last_date, new Date());
}
}
};
/*
* Handle answers to hotlist request
*/
var handleHotlistInfo = function(message) {
// Hotlist includes only buffers with unread counts so first we
// iterate all our buffers and resets the counts.
_.each(models.getBuffers(), function(buffer) {
buffer.unread = 0;
buffer.notification = 0;
});
_.each(models.getServers(), function(server) {
server.unread = 0;
});
if (message.objects.length > 0) {
var hotlist = message.objects[0].content;
hotlist.forEach(function(l) {
var buffer = models.getBuffer(l.buffer);
// If buffer is active in gb, but not active in WeeChat the
// hotlist in WeeChat will increase but we should ignore that
// in gb.
if (buffer.active) {
return;
}
// 1 is message
buffer.unread = l.count[1];
// 2 is private
// Use += so count[2] or count[3] doesn't overwrite each other
buffer.notification += l.count[2];
// 3 is highlight
// Use += so count[2] or count[3] doesn't overwrite each other
buffer.notification += l.count[3];
/* Since there is unread messages, we can guess
* what the last read line is and update it accordingly
*/
var unreadSum = _.reduce(l.count, function(memo, num) { return memo + num; }, 0);
buffer.lastSeen = buffer.lines.length - 1 - unreadSum;
// update server buffer. Don't incude index 0 -> not unreadSum
models.getServerForBuffer(buffer).unread += l.count[1] + l.count[2] + l.count[3];
});
}
// the unread badges in the bufferlist doesn't update if we don't do this
setTimeout(function() {
$rootScope.$apply();
$rootScope.$emit('notificationChanged');
});
};
/*
* Handle nicklist event
*
* This event can either fill or clear a nicklist. It is always a complete nicklist.
*/
var handleNicklist = function(message) {
var nicklist = message.objects[0].content;
var group = 'root';
//clear the nicklists in case we are clearing
if (nicklist.length==1)
{
models.getBuffer(nicklist[0].pointers[0]).clearNicklist();
}
//fill the nicklist
nicklist.forEach(function(n) {
var buffer = models.getBuffer(n.pointers[0]);
//buffer nicklist
if (n.group === 1) {
var g = new models.NickGroup(n);
group = g.name;
buffer.nicklist[group] = g;
} else {
var nick = new models.Nick(n);
buffer.addNick(group, nick);
}
});
//check if nicklist should be hidden or not
$rootScope.$emit('nickListChanged');
};
/*
* Handle nicklist diff event
*/
var handleNicklistDiff = function(message) {
var nicklist = message.objects[0].content;
var group;
nicklist.forEach(function(n) {
var buffer = models.getBuffer(n.pointers[0]);
var d = n._diff;
if (n.group === 1) {
group = n.name;
if (group === undefined) {
var g = new models.NickGroup(n);
buffer.nicklist[group] = g;
group = g.name;
}
} else {
var nick = new models.Nick(n);
if (d === 43) { // +
buffer.addNick(group, nick);
} else if (d === 45) { // -
buffer.delNick(group, nick);
} else if (d === 42) { // *
buffer.updateNick(group, nick);
}
}
});
};
var eventHandlers = {
_buffer_closing: handleBufferClosing,
_buffer_line_added: handleBufferLineAdded,
_buffer_localvar_added: handleBufferLocalvarChanged,
_buffer_localvar_removed: handleBufferLocalvarChanged,
_buffer_localvar_changed: handleBufferLocalvarChanged,
_buffer_moved: handleBufferMoved,
_buffer_opened: handleBufferOpened,
_buffer_title_changed: handleBufferTitleChanged,
_buffer_type_changed: handleBufferTypeChanged,
_buffer_renamed: handleBufferRenamed,
_buffer_hidden: handleBufferHidden,
_buffer_unhidden: handleBufferUnhidden,
_nicklist: handleNicklist,
_nicklist_diff: handleNicklistDiff
};
$rootScope.$on('onMessage', function(event, message) {
if (_.has(eventHandlers, message.id)) {
eventHandlers[message.id](message);
} else {
$log.debug('Unhandled event received: ' + message.id);
}
});
var handleEvent = function(event) {
if (_.has(eventHandlers, event.id)) {
eventHandlers[event.id](event);
}
};
return {
handleVersionInfo: handleVersionInfo,
handleConfValue: handleConfValue,
handleEvent: handleEvent,
handleLineInfo: handleLineInfo,
handleHotlistInfo: handleHotlistInfo,
handleNicklist: handleNicklist,
handleBufferInfo: handleBufferInfo
};
}]);
})();