thelounge/client/js/render.js

189 lines
4.8 KiB
JavaScript
Raw Normal View History

2017-05-18 20:08:54 +00:00
"use strict";
const $ = require("jquery");
const templates = require("../views");
const options = require("./options");
const renderPreview = require("./renderPreview");
2017-05-18 20:08:54 +00:00
const utils = require("./utils");
2017-06-22 20:08:36 +00:00
const constants = require("./constants");
2017-08-19 18:47:23 +00:00
const condensed = require("./condensed");
const JoinChannel = require("./join-channel");
const {vueApp} = require("./vue");
2017-05-18 20:08:54 +00:00
module.exports = {
renderNetworks,
trimMessageInChannel,
2017-05-18 20:08:54 +00:00
};
function appendMessage(container, chanId, chanType, msg) {
2017-08-28 15:03:27 +00:00
if (utils.lastMessageId < msg.id) {
utils.lastMessageId = msg.id;
}
return;
2017-09-01 11:43:24 +00:00
let lastChild = container.children(".msg, .date-marker-container").last();
const renderedMessage = buildChatMessage(msg);
// Check if date changed
const msgTime = new Date(msg.time);
2017-09-01 11:43:24 +00:00
const prevMsgTime = new Date(lastChild.data("time"));
// Insert date marker if date changed compared to previous message
if (prevMsgTime.toDateString() !== msgTime.toDateString()) {
lastChild = $(templates.date_marker({time: msg.time}));
2017-09-01 11:43:24 +00:00
container.append(lastChild);
}
// If current window is not a channel or this message is not condensable,
// then just append the message to container and be done with it
if (msg.self || msg.highlight || constants.condensedTypes.indexOf(msg.type) === -1 || chanType !== "channel") {
container.append(renderedMessage);
2017-08-19 18:47:23 +00:00
return;
}
const obj = {};
obj[msg.type] = 1;
// If the previous message is already condensed,
// we just append to it and update text
if (lastChild.hasClass("condensed")) {
lastChild.append(renderedMessage);
condensed.updateText(lastChild, obj);
return;
2017-06-22 20:08:36 +00:00
}
2017-09-01 11:43:24 +00:00
// Always create a condensed container
const newCondensed = $(templates.msg_condensed({time: msg.time}));
condensed.updateText(newCondensed, obj);
newCondensed.append(renderedMessage);
container.append(newCondensed);
2017-06-22 20:08:36 +00:00
}
function buildChatMessage(msg) {
const type = msg.type;
2017-05-18 20:08:54 +00:00
let template = "msg";
// See if any of the custom highlight regexes match
if (!msg.highlight && !msg.self
&& options.highlightsRE
&& (type === "message" || type === "notice")
&& options.highlightsRE.exec(msg.text)) {
msg.highlight = true;
2017-05-18 20:08:54 +00:00
}
if (typeof templates.actions[type] !== "undefined") {
2017-05-18 20:08:54 +00:00
template = "msg_action";
} else if (type === "unhandled") {
template = "msg_unhandled";
}
// Make the MOTDs a little nicer if possible
if (msg.type === "motd") {
let lines = msg.text.split("\n");
// If all non-empty lines of the MOTD start with a hyphen (which is common
// across MOTDs), remove all the leading hyphens.
if (lines.every((line) => line === "" || line[0] === "-")) {
lines = lines.map((line) => line.substr(2));
}
// Remove empty lines around the MOTD (but not within it)
msg.text = lines
.map((line) => line.replace(/\s*$/, ""))
.join("\n")
.replace(/^[\r\n]+|[\r\n]+$/g, "");
}
const renderedMessage = $(templates[template](msg));
const content = renderedMessage.find(".content");
2017-05-18 20:08:54 +00:00
if (template === "msg_action") {
content.html(templates.actions[type](msg));
2017-05-18 20:08:54 +00:00
}
msg.previews.forEach((preview) => {
renderPreview(preview, renderedMessage);
});
return renderedMessage;
2017-05-18 20:08:54 +00:00
}
2017-08-28 20:06:28 +00:00
function renderNetworks(data, singleNetwork) {
// Add keyboard handlers to the "Join a channel…" form inputs/button
JoinChannel.handleKeybinds(data.networks);
2017-08-28 20:06:28 +00:00
let newChannels;
2017-05-18 20:08:54 +00:00
const channels = $.map(data.networks, function(n) {
return n.channels;
});
2017-08-28 20:06:28 +00:00
if (!singleNetwork && utils.lastMessageId > -1) {
newChannels = [];
channels.forEach((channel) => {
const chan = $("#chan-" + channel.id);
if (chan.length > 0) {
if (channel.type === "channel") {
channel.usersOutdated = true;
2017-08-28 20:06:28 +00:00
}
if (channel.messages.length > 0) {
const container = chan.find(".messages");
2017-08-28 20:06:28 +00:00
if (container.find(".msg").length >= 100) {
container.find(".show-more").addClass("show");
}
container.parent().trigger("keepToBottom");
2017-08-28 20:06:28 +00:00
}
} else {
newChannels.push(channel);
}
});
} else {
newChannels = channels;
}
if (newChannels.length > 0) {
newChannels.forEach((channel) => {
if (channel.type === "channel") {
channel.usersOutdated = true;
}
});
}
2017-05-18 20:08:54 +00:00
utils.confirmExit();
for (const network of vueApp.networks) {
for (const channel of network.channels) {
if (channel.highlight > 0) {
utils.updateTitle();
utils.toggleNotificationMarkers(true);
return;
}
}
2017-05-18 20:08:54 +00:00
}
}
function trimMessageInChannel(channel, messageLimit) {
const messages = channel.find(".messages .msg").slice(0, -messageLimit);
if (messages.length === 0) {
return;
}
messages.remove();
channel.find(".show-more").addClass("show");
// Remove date-separators that would otherwise be "stuck" at the top of the channel
channel.find(".date-marker-container").each(function() {
if ($(this).next().hasClass("date-marker-container")) {
$(this).remove();
}
});
}