Merge pull request #1452 from thelounge/xpaw/refactor-dates
Completely refactor how date markers are inserted
This commit is contained in:
commit
d8f2d7fc10
@ -15,57 +15,85 @@ const sidebar = $("#sidebar");
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
appendMessage,
|
appendMessage,
|
||||||
buildChannelMessages,
|
buildChannelMessages,
|
||||||
buildChatMessage,
|
|
||||||
renderChannel,
|
renderChannel,
|
||||||
renderChannelMessages,
|
|
||||||
renderChannelUsers,
|
renderChannelUsers,
|
||||||
renderNetworks,
|
renderNetworks,
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildChannelMessages(data) {
|
function buildChannelMessages(chanId, chanType, messages) {
|
||||||
return data.messages.reduce(function(docFragment, message) {
|
return messages.reduce((docFragment, message) => {
|
||||||
appendMessage(docFragment, data.id, data.type, message.type, buildChatMessage({
|
appendMessage(docFragment, chanId, chanType, message);
|
||||||
chan: data.id,
|
|
||||||
msg: message
|
|
||||||
}));
|
|
||||||
return docFragment;
|
return docFragment;
|
||||||
}, $(document.createDocumentFragment()));
|
}, $(document.createDocumentFragment()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendMessage(container, chan, chanType, messageType, msg) {
|
function appendMessage(container, chanId, chanType, msg) {
|
||||||
// TODO: To fix #1432, statusMessage option should entirely be implemented in CSS
|
const renderedMessage = buildChatMessage(chanId, msg);
|
||||||
if (constants.condensedTypes.indexOf(messageType) === -1 || chanType !== "channel" || options.statusMessages !== "condensed") {
|
|
||||||
container.append(msg);
|
// Check if date changed
|
||||||
|
let lastChild = container.find(".msg").last();
|
||||||
|
const msgTime = new Date(msg.time);
|
||||||
|
|
||||||
|
// It's the first message in a window,
|
||||||
|
// then just append the message and do nothing else
|
||||||
|
if (lastChild.length === 0) {
|
||||||
|
container
|
||||||
|
.append(templates.date_marker({msgDate: msgTime}))
|
||||||
|
.append(renderedMessage);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastChild = container.children("div.msg").last();
|
const prevMsgTime = new Date(lastChild.attr("data-time"));
|
||||||
|
const parent = lastChild.parent();
|
||||||
|
|
||||||
if (lastChild && $(lastChild).hasClass("condensed")) {
|
// If this message is condensed, we have to work on the wrapper
|
||||||
lastChild.append(msg);
|
if (parent.hasClass("condensed")) {
|
||||||
condensed.updateText(lastChild, [messageType]);
|
lastChild = parent;
|
||||||
} else if (lastChild && $(lastChild).is(constants.condensedTypesQuery)) {
|
}
|
||||||
const newCondensed = buildChatMessage({
|
|
||||||
chan: chan,
|
// Insert date marker if date changed compared to previous message
|
||||||
msg: {
|
if (prevMsgTime.toDateString() !== msgTime.toDateString()) {
|
||||||
type: "condensed",
|
lastChild.after(templates.date_marker({msgDate: msgTime}));
|
||||||
time: msg.attr("data-time"),
|
|
||||||
previews: []
|
// If date changed, we don't need to do condensed logic
|
||||||
}
|
container.append(renderedMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: To fix #1432, statusMessage option should entirely be implemented in CSS
|
||||||
|
// 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 (constants.condensedTypes.indexOf(msg.type) === -1 || chanType !== "channel" || options.statusMessages !== "condensed") {
|
||||||
|
container.append(renderedMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, [msg.type]);
|
||||||
|
// If the previous message can be condensed, we create a new condensed wrapper
|
||||||
|
} else if (lastChild.is(constants.condensedTypesQuery)) {
|
||||||
|
const newCondensed = buildChatMessage(chanId, {
|
||||||
|
type: "condensed",
|
||||||
|
time: msg.time,
|
||||||
|
previews: []
|
||||||
});
|
});
|
||||||
|
|
||||||
condensed.updateText(newCondensed, [messageType, lastChild.attr("data-type")]);
|
condensed.updateText(newCondensed, [msg.type, lastChild.attr("data-type")]);
|
||||||
container.append(newCondensed);
|
container.append(newCondensed);
|
||||||
newCondensed.append(lastChild);
|
newCondensed.append(lastChild);
|
||||||
newCondensed.append(msg);
|
newCondensed.append(renderedMessage);
|
||||||
} else {
|
} else {
|
||||||
container.append(msg);
|
container.append(renderedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildChatMessage(data) {
|
function buildChatMessage(chanId, msg) {
|
||||||
const type = data.msg.type;
|
const type = msg.type;
|
||||||
let target = "#chan-" + data.chan;
|
let target = "#chan-" + chanId;
|
||||||
if (type === "error") {
|
if (type === "error") {
|
||||||
target = "#chan-" + chat.find(".active").data("id");
|
target = "#chan-" + chat.find(".active").data("id");
|
||||||
}
|
}
|
||||||
@ -74,15 +102,15 @@ function buildChatMessage(data) {
|
|||||||
let template = "msg";
|
let template = "msg";
|
||||||
|
|
||||||
// See if any of the custom highlight regexes match
|
// See if any of the custom highlight regexes match
|
||||||
if (!data.msg.highlight && !data.msg.self
|
if (!msg.highlight && !msg.self
|
||||||
&& options.highlightsRE
|
&& options.highlightsRE
|
||||||
&& (type === "message" || type === "notice")
|
&& (type === "message" || type === "notice")
|
||||||
&& options.highlightsRE.exec(data.msg.text)) {
|
&& options.highlightsRE.exec(msg.text)) {
|
||||||
data.msg.highlight = true;
|
msg.highlight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constants.actionTypes.indexOf(type) !== -1) {
|
if (constants.actionTypes.indexOf(type) !== -1) {
|
||||||
data.msg.template = "actions/" + type;
|
msg.template = "actions/" + type;
|
||||||
template = "msg_action";
|
template = "msg_action";
|
||||||
} else if (type === "unhandled") {
|
} else if (type === "unhandled") {
|
||||||
template = "msg_unhandled";
|
template = "msg_unhandled";
|
||||||
@ -90,29 +118,29 @@ function buildChatMessage(data) {
|
|||||||
template = "msg_condensed";
|
template = "msg_condensed";
|
||||||
}
|
}
|
||||||
|
|
||||||
const msg = $(templates[template](data.msg));
|
const renderedMessage = $(templates[template](msg));
|
||||||
const content = msg.find(".content");
|
const content = renderedMessage.find(".content");
|
||||||
|
|
||||||
if (template === "msg_action") {
|
if (template === "msg_action") {
|
||||||
content.html(templates.actions[type](data.msg));
|
content.html(templates.actions[type](msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
data.msg.previews.forEach((preview) => {
|
msg.previews.forEach((preview) => {
|
||||||
renderPreview(preview, msg);
|
renderPreview(preview, renderedMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((type === "message" || type === "action" || type === "notice") && chan.hasClass("channel")) {
|
if ((type === "message" || type === "action" || type === "notice") && chan.hasClass("channel")) {
|
||||||
const nicks = chan.find(".users").data("nicks");
|
const nicks = chan.find(".users").data("nicks");
|
||||||
if (nicks) {
|
if (nicks) {
|
||||||
const find = nicks.indexOf(data.msg.from);
|
const find = nicks.indexOf(msg.from);
|
||||||
if (find !== -1) {
|
if (find !== -1) {
|
||||||
nicks.splice(find, 1);
|
nicks.splice(find, 1);
|
||||||
nicks.unshift(data.msg.from);
|
nicks.unshift(msg.from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg;
|
return renderedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderChannel(data) {
|
function renderChannel(data) {
|
||||||
@ -124,7 +152,7 @@ function renderChannel(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderChannelMessages(data) {
|
function renderChannelMessages(data) {
|
||||||
const documentFragment = buildChannelMessages(data);
|
const documentFragment = buildChannelMessages(data.id, data.type, data.messages);
|
||||||
const channel = chat.find("#chan-" + data.id + " .messages").append(documentFragment);
|
const channel = chat.find("#chan-" + data.id + " .messages").append(documentFragment);
|
||||||
|
|
||||||
if (data.firstUnread > 0) {
|
if (data.firstUnread > 0) {
|
||||||
@ -141,30 +169,6 @@ function renderChannelMessages(data) {
|
|||||||
} else {
|
} else {
|
||||||
channel.append(templates.unread_marker());
|
channel.append(templates.unread_marker());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type !== "lobby") {
|
|
||||||
let lastDate;
|
|
||||||
$(chat.find("#chan-" + data.id + " .messages .msg[data-time]")).each(function() {
|
|
||||||
const msg = $(this);
|
|
||||||
const msgDate = new Date(msg.attr("data-time"));
|
|
||||||
|
|
||||||
// Top-most message in a channel
|
|
||||||
if (!lastDate) {
|
|
||||||
lastDate = msgDate;
|
|
||||||
msg.before(templates.date_marker({msgDate: msgDate}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastDate.toDateString() !== msgDate.toDateString()) {
|
|
||||||
var parent = msg.parent();
|
|
||||||
if (parent.hasClass("condensed")) {
|
|
||||||
msg.insertAfter(parent);
|
|
||||||
}
|
|
||||||
msg.before(templates.date_marker({msgDate: msgDate}));
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDate = msgDate;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderChannelUsers(data) {
|
function renderChannelUsers(data) {
|
||||||
|
@ -4,12 +4,11 @@ const $ = require("jquery");
|
|||||||
const socket = require("../socket");
|
const socket = require("../socket");
|
||||||
const render = require("../render");
|
const render = require("../render");
|
||||||
const chat = $("#chat");
|
const chat = $("#chat");
|
||||||
const templates = require("../../views");
|
|
||||||
|
|
||||||
socket.on("more", function(data) {
|
socket.on("more", function(data) {
|
||||||
const chan = chat
|
let chan = chat.find("#chan-" + data.chan);
|
||||||
.find("#chan-" + data.chan)
|
const type = chan.data("type");
|
||||||
.find(".messages");
|
chan = chan.find(".messages");
|
||||||
|
|
||||||
// get the scrollable wrapper around messages
|
// get the scrollable wrapper around messages
|
||||||
const scrollable = chan.closest(".chat");
|
const scrollable = chan.closest(".chat");
|
||||||
@ -34,7 +33,7 @@ socket.on("more", function(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the older messages
|
// Add the older messages
|
||||||
const documentFragment = render.buildChannelMessages(data);
|
const documentFragment = render.buildChannelMessages(data.chan, type, data.messages);
|
||||||
chan.prepend(documentFragment).end();
|
chan.prepend(documentFragment).end();
|
||||||
|
|
||||||
// restore scroll position
|
// restore scroll position
|
||||||
@ -45,31 +44,6 @@ socket.on("more", function(data) {
|
|||||||
scrollable.find(".show-more").removeClass("show");
|
scrollable.find(".show-more").removeClass("show");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date change detect
|
|
||||||
// Have to use data instead of the documentFragment because it's being weird
|
|
||||||
let lastDate;
|
|
||||||
$(data.messages).each(function() {
|
|
||||||
const msgData = this;
|
|
||||||
const msgDate = new Date(msgData.time);
|
|
||||||
const msg = $(chat.find("#chan-" + data.chan + " .messages #msg-" + msgData.id));
|
|
||||||
|
|
||||||
// Top-most message in a channel
|
|
||||||
if (!lastDate) {
|
|
||||||
lastDate = msgDate;
|
|
||||||
msg.before(templates.date_marker({msgDate: msgDate}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastDate.toDateString() !== msgDate.toDateString()) {
|
|
||||||
var parent = msg.parent();
|
|
||||||
if (parent.hasClass("condensed")) {
|
|
||||||
msg.insertAfter(parent);
|
|
||||||
}
|
|
||||||
msg.before(templates.date_marker({msgDate: msgDate}));
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDate = msgDate;
|
|
||||||
});
|
|
||||||
|
|
||||||
scrollable.find(".show-more-button")
|
scrollable.find(".show-more-button")
|
||||||
.text("Show older messages")
|
.text("Show older messages")
|
||||||
.prop("disabled", false);
|
.prop("disabled", false);
|
||||||
|
@ -4,7 +4,6 @@ const $ = require("jquery");
|
|||||||
const socket = require("../socket");
|
const socket = require("../socket");
|
||||||
const render = require("../render");
|
const render = require("../render");
|
||||||
const chat = $("#chat");
|
const chat = $("#chat");
|
||||||
const templates = require("../../views");
|
|
||||||
|
|
||||||
socket.on("msg", function(data) {
|
socket.on("msg", function(data) {
|
||||||
if (window.requestIdleCallback) {
|
if (window.requestIdleCallback) {
|
||||||
@ -18,7 +17,6 @@ socket.on("msg", function(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function processReceivedMessage(data) {
|
function processReceivedMessage(data) {
|
||||||
const msg = render.buildChatMessage(data);
|
|
||||||
const targetId = data.chan;
|
const targetId = data.chan;
|
||||||
const target = "#chan-" + targetId;
|
const target = "#chan-" + targetId;
|
||||||
const channel = chat.find(target);
|
const channel = chat.find(target);
|
||||||
@ -30,31 +28,12 @@ function processReceivedMessage(data) {
|
|||||||
$(container).empty();
|
$(container).empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if date changed
|
|
||||||
let prevMsg = $(container.find(".msg")).last();
|
|
||||||
const prevMsgTime = new Date(prevMsg.attr("data-time"));
|
|
||||||
const msgTime = new Date(msg.attr("data-time"));
|
|
||||||
|
|
||||||
// It's the first message in a channel/query
|
|
||||||
if (prevMsg.length === 0) {
|
|
||||||
container.append(templates.date_marker({msgDate: msgTime}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevMsgTime.toDateString() !== msgTime.toDateString()) {
|
|
||||||
var parent = prevMsg.parent();
|
|
||||||
if (parent.hasClass("condensed")) {
|
|
||||||
prevMsg = parent;
|
|
||||||
}
|
|
||||||
prevMsg.after(templates.date_marker({msgDate: msgTime}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add message to the container
|
// Add message to the container
|
||||||
render.appendMessage(
|
render.appendMessage(
|
||||||
container,
|
container,
|
||||||
data.chan,
|
targetId,
|
||||||
$(target).attr("data-type"),
|
$(target).attr("data-type"),
|
||||||
data.msg.type,
|
data.msg
|
||||||
msg
|
|
||||||
);
|
);
|
||||||
|
|
||||||
container.trigger("msg", [
|
container.trigger("msg", [
|
||||||
|
Loading…
Reference in New Issue
Block a user