|
// import libWrapperShared from "./libWrapperShared.js";
|
|
|
|
export default class ChatMerge {
|
|
static get _enabled() {
|
|
return true;
|
|
}
|
|
static get _epoch() {
|
|
return 10;
|
|
}
|
|
static get _allowRolls() {
|
|
return "rolls";
|
|
}
|
|
static get _separateWithBorder() {
|
|
return false;
|
|
}
|
|
static get _showHover() {
|
|
return false;
|
|
}
|
|
static get _showHeader() {
|
|
return false;
|
|
}
|
|
|
|
static init() {
|
|
// libWrapperShared.register("ChatLog.prototype.deleteMessage", this._deleteMessage.bind(this));
|
|
Hooks.on("renderChatMessage", this._renderChatMessage);
|
|
Hooks.on("deleteChatMessage", this.deleteMessage);
|
|
}
|
|
|
|
static ready() {
|
|
const style = document.querySelector(":root").style;
|
|
// style.setProperty("--dfce-cm-separation", this._separateWithBorder ? "" : "0");
|
|
// this._showHover
|
|
// ? style.removeProperty("--dfce-cm-hover-shadow")
|
|
// : style.setProperty("--dfce-cm-hover-shadow", "0px");
|
|
// style.setProperty("--dfce-cm-header", this._showHeader ? "" : "none");
|
|
// if (game.user.isGM) {
|
|
// style.setProperty("--dfce-cm-header-delete", this._showHeader ? "" : "0");
|
|
// style.setProperty("--dfce-cm-header-delete-pad", this._showHeader ? "" : "16px");
|
|
// }
|
|
this._processAllMessage(ui.chat.element);
|
|
Hooks.on("renderChatLog", (_, html) => this._processAllMessage(html));
|
|
}
|
|
|
|
static deleteMessage(message, flags) {
|
|
if (flags.deleteAll === true) return;
|
|
const messageId = message._id;
|
|
const element = document.querySelector(`li[data-message-id="${messageId}"`);
|
|
// If we were a TOP
|
|
if (element?.classList?.contains("dfce-cm-top")) {
|
|
element.classList.remove("dfce-cm-top");
|
|
// If the next element was a middle, make it a top
|
|
if (element.nextElementSibling.classList.contains("dfce-cm-middle")) {
|
|
element.nextElementSibling.classList.remove("dfce-cm-middle");
|
|
element.nextElementSibling.classList.add("dfce-cm-top");
|
|
}
|
|
// Otherwise, it was a bottom and should now become a normal message again
|
|
else element.nextElementSibling.classList.remove("dfce-cm-bottom");
|
|
}
|
|
// If we were a BOTTOM
|
|
else if (element?.classList?.contains("dfce-cm-bottom")) {
|
|
element.classList.remove("dfce-cm-bottom");
|
|
// If the previous element was a middle, make it a bottom
|
|
if (element.previousElementSibling.classList.contains("dfce-cm-middle")) {
|
|
element.previousElementSibling.classList.remove("dfce-cm-middle");
|
|
element.previousElementSibling.classList.add("dfce-cm-bottom");
|
|
}
|
|
// Otherwise, it was a top and should now become a normal message again
|
|
else element.previousElementSibling.classList.remove("dfce-cm-top");
|
|
}
|
|
// If we were a MIDDLE, let the above and below snug and they'll be fine
|
|
else if (element?.classList?.contains("dfce-cm-middle")) element.classList.remove("dfce-cm-middle");
|
|
}
|
|
|
|
// static _deleteMessage(wrapper, messageId, { deleteAll = false } = {}) {
|
|
// // Ignore the Delete All process. Everything is being obliterated, who cares about the styling
|
|
// if (!deleteAll && this._enabled) {
|
|
// const element = document.querySelector(`li[data-message-id="${messageId}"`);
|
|
// // If we were a TOP
|
|
// if (element?.classList?.contains("dfce-cm-top")) {
|
|
// element.classList.remove("dfce-cm-top");
|
|
// // If the next element was a middle, make it a top
|
|
// if (element.nextElementSibling.classList.contains("dfce-cm-middle")) {
|
|
// element.nextElementSibling.classList.remove("dfce-cm-middle");
|
|
// element.nextElementSibling.classList.add("dfce-cm-top");
|
|
// }
|
|
// // Otherwise, it was a bottom and should now become a normal message again
|
|
// else element.nextElementSibling.classList.remove("dfce-cm-bottom");
|
|
// }
|
|
// // If we were a BOTTOM
|
|
// else if (element?.classList?.contains("dfce-cm-bottom")) {
|
|
// element.classList.remove("dfce-cm-bottom");
|
|
// // If the previous element was a middle, make it a bottom
|
|
// if (element.previousElementSibling.classList.contains("dfce-cm-middle")) {
|
|
// element.previousElementSibling.classList.remove("dfce-cm-middle");
|
|
// element.previousElementSibling.classList.add("dfce-cm-bottom");
|
|
// }
|
|
// // Otherwise, it was a top and should now become a normal message again
|
|
// else element.previousElementSibling.classList.remove("dfce-cm-top");
|
|
// }
|
|
// // If we were a MIDDLE, let the above and below snug and they'll be fine
|
|
// else if (element?.classList?.contains("dfce-cm-middle")) element.classList.remove("dfce-cm-middle");
|
|
// }
|
|
// return wrapper(messageId, { deleteAll });
|
|
// }
|
|
|
|
static _processAllMessage(element) {
|
|
element = element ?? $(document.body);
|
|
// Remove the old CSS class designations
|
|
element.find(".dfce-cm-top").removeClass("dfce-cm-top");
|
|
element.find(".dfce-cm-middle").removeClass("dfce-cm-middle");
|
|
element.find(".dfce-cm-bottom").removeClass("dfce-cm-bottom");
|
|
// If we are disabled, return
|
|
if (!ChatMerge._enabled) return;
|
|
// Collect all rendered chat messages
|
|
const messages = element.find("li.chat-message");
|
|
// Return if there are no messages rendered
|
|
if (messages.length === 0) return;
|
|
|
|
// Process each message after the first
|
|
for (let c = 1; c < messages.length; c++) {
|
|
// Update styling of the chat messages
|
|
this._styleChatMessages(
|
|
game.messages.get(messages[c].getAttribute("data-message-id")),
|
|
messages[c],
|
|
game.messages.get(messages[c - 1].getAttribute("data-message-id")),
|
|
messages[c - 1]
|
|
);
|
|
}
|
|
}
|
|
|
|
static _renderChatMessage(message, html, _cmd) {
|
|
if (!ChatMerge._enabled) return;
|
|
// Find the most recent message in the chat log
|
|
const partnerElem = $(`li.chat-message`).last()[0];
|
|
// If there is no message, return
|
|
if (partnerElem === null || partnerElem === undefined) return;
|
|
// get the ChatMessage document associated with the html
|
|
const partner = game.messages.get(partnerElem.getAttribute("data-message-id"));
|
|
if (!message || !partner) return;
|
|
// Update styling of the chat messages
|
|
ChatMerge._styleChatMessages(message, html[0], partner, partnerElem);
|
|
}
|
|
|
|
static _inTimeFrame(current, previous) {
|
|
return current > previous && current - previous < this._epoch * 1000;
|
|
}
|
|
|
|
static _isValidMessage(current, previous) {
|
|
const rolls = this._allowRolls;
|
|
// const splitSpeaker = SETTINGS.get < boolean > this.PREF_SPLIT_SPEAKER;
|
|
const splitSpeaker = true;
|
|
let userCompare = false;
|
|
const currData = current ?? current;
|
|
const prevData = previous ?? previous;
|
|
if (splitSpeaker) {
|
|
// this is a bit complex, basically we want to group by actors, but if you're not using an actor, group by user instead
|
|
userCompare =
|
|
// If actors are equal and NOT null
|
|
(currData.speaker.actor === prevData.speaker.actor && !!currData.speaker.actor) || // If BOTH actors are null and users are equal
|
|
(!currData.speaker.actor && !prevData.speaker.actor && currData.user === prevData.user);
|
|
} else {
|
|
// If we are not splitting by speaker, just do the simple option of comparing the users
|
|
userCompare = currData.user === prevData.user;
|
|
}
|
|
return (
|
|
userCompare &&
|
|
this._inTimeFrame(currData.timestamp, prevData.timestamp) &&
|
|
// Check for merging with roll types
|
|
(rolls === "all" ||
|
|
(rolls === "rolls" && current.isRoll === previous.isRoll) ||
|
|
(rolls === "none" && !current.isRoll && !previous.isRoll))
|
|
);
|
|
}
|
|
|
|
static _styleChatMessages(curr, currElem, prev, prevElem) {
|
|
if (!ChatMerge._isValidMessage(curr, prev)) return;
|
|
if (prevElem.classList.contains("dfce-cm-bottom")) {
|
|
prevElem.classList.remove("dfce-cm-bottom");
|
|
prevElem.classList.add("dfce-cm-middle");
|
|
} else prevElem.classList.add("dfce-cm-top");
|
|
currElem.classList.add("dfce-cm-bottom");
|
|
}
|
|
}
|