element.classList.add("blink");
}
- function chatMessage(sender, content) {
+ function chatMessage(sender, content, date) {
+ const msgId = "";
+ if (sender && date) {
+ msgId = "chatmsg-" + date + "--" + sender;
+ if (document.getElementById(msgId)) {
+ // we already have that message
+ return;
+ }
+ }
+
chatMessages.style.width = chatTextarea.offsetWidth + "px"; // HACK to prevent the chat box from getting too big
const msgDom = document.createElement("div");
+ if (msgId) {
+ msgDom.id = msgId;
+ }
msgDom.className = "msg";
return content;
}
- function handleChatMessage(msg) {
+ function handleHistoricalChatMessage(msg) {
+ handleChatMessage(true, msg);
+ }
+
+ function handleChatMessage(fromHistory, msg) {
if (msg.specialMsg) {
switch (msg.specialMsg.type) {
case "rack": {
}
case "highlightCell": {
- localHighlightCell(msg.specialMsg.cell);
- infoMessage(msg.msg);
+ if (!fromHistory) {
+ localHighlightCell(msg.specialMsg.cell);
+ infoMessage(msg.msg);
+ }
break;
}
}
}
if (msg.content) {
- chatMessage(msg.sender, msg.content);
+ chatMessage(msg.sender, msg.content, msg.date);
}
}
}
if (data.msg) {
- handleChatMessage(data.msg);
+ handleChatMessage(false, data.msg);
}
if (typeof data.currentPlayer === "string") {
tileCount.textContent = data.remainingLetters;
}
+ if (data.chatHistory) {
+ data.chatHistory.forEach(handleHistoricalChatMessage);
+ }
+
+ if (data.chatMessageMaxSize && data.chatMessageMaxSize > 0) {
+ chatTextarea.maxLength = data.chatMessageMaxSize;
+ }
+
if (data.rack) {
setRack(data.rack);
}
const DEFAULT_BAG_FACTOR = 1;
const CHECK_FIRST_WORD = 1; // 1: check, 0: not set, -1: no check
const FREEZE_PLAYED_TILES = -1; // 1: freeze, 0: not set, -1: no freeze
+const CHAT_HISTORY_SIZE_LIMIT = parseInt(process.env.TRIVABBLE_CHAT_HISTORY_SIZE_LIMIT || "50");
+const CHAT_MESSAGE_MAX_SIZE = parseInt(process.env.TRIVABBLE_CHAT_MESSAGE_MAX_SIZE || "1000");
const VERSION = 202508050000;
// if you add something there that stores the player name, please make sure to
// update changePlayerName
// eslint-disable-next-line max-params
-Game.prototype.init = function (lang, label, factor, checkFirstWord, freezePlayedTiles) {
+Game.prototype.init = function (lang, label, factor, checkFirstWord, freezePlayedTiles, chatHistory) {
this.label = label || DEFAULT_BOARD_LABEL;
this.factor = factor || DEFAULT_BAG_FACTOR;
this.board = newBoard(this.label);
this.freezePlayedTiles = freezePlayedTiles || FREEZE_PLAYED_TILES;
this.lastUpdated = new Date();
this.currentPlayer = "";
+ this.chatHistory = chatHistory || [];
this.bag = expandAndShuffleBag(bag, this.factor);
};
checkFirstWord: this.checkFirstWord,
freezePlayedTiles: this.freezePlayedTiles,
lastUpdated: this.lastUpdated.toISOString(),
+ chatHistory: this.chatHistory,
currentPlayer: this.currentPlayer
};
};
game.freezePlayedTiles = obj.freezePlayedTiles || FREEZE_PLAYED_TILES;
game.lastUpdated = obj.lastUpdated ? new Date(obj.lastUpdated) : new Date();
game.currentPlayer = obj.currentPlayer || "";
+ game.chatHistory = obj.chatHistory || [];
return game;
};
};
Game.prototype.reset = function (player) {
- this.init(this.lang, this.label, this.factor, this.checkFirstWord, this.freezePlayedTiles);
+ this.init(this.lang, this.label, this.factor, this.checkFirstWord, this.freezePlayedTiles, this.chatHistory);
this.pendingEvents.push({
player: player,
action: "reset",
newName: n
}]
});
+
+ // We don't currently update the chat history with the new name.
+ // This is on purpose, but maybe we should update the name there too?
+
this.commit();
return n;
};
+Game.prototype.storeAndDispatchChatMessage = function (msg) {
+ if (CHAT_HISTORY_SIZE_LIMIT !== -1) {
+ this.chatHistory.push(msg);
+ }
+
+ while (this.chatHistory.length > CHAT_HISTORY_SIZE_LIMIT) {
+ this.chatHistory.shift();
+ }
+
+ this.pendingEvents.push({msg});
+};
+
function newGameId() {
let number;
tileOwner: game.tileOwner,
remainingLetters: game.bag.length,
letterValues: game.letterValues,
+ chatHistory: game.chatHistory,
+ chatHistoryLimit: CHAT_HISTORY_SIZE_LIMIT,
+ chatMessageMaxSize: CHAT_MESSAGE_MAX_SIZE,
version: VERSION
});
break;
case "msg": {
- game.pendingEvents.push({
- msg: {
- sender: playerName,
- content: cmd.msg,
- specialMsg: cmd.specialMsg
- }
- });
+ const msg = {
+ date: new Date(),
+ sender: playerName,
+ content: cmd.msg,
+ specialMsg: cmd.specialMsg
+ };
+
+ if (CHAT_MESSAGE_MAX_SIZE !== -1 && msg.content.length > CHAT_MESSAGE_MAX_SIZE) {
+ msg.content = msg.content.substr(0, CHAT_MESSAGE_MAX_SIZE);
+ }
+
+ game.storeAndDispatchChatMessage(msg);
reply(message, response, cmdNumber, {error: 0});
break;
if (!message.cmds || !message.cmds.length) {
const {gameNumber, game} = joinGame(message.gameNumber, message);
+ // FIXME: deduplicate with joinGame?
writeMessage(responseAndType,
JSON.stringify({
playerName: message.playerName,
remainingLetters: game.bag.length,
checkFirstWord: game.checkFirstWord,
freezePlayedTiles: game.freezePlayedTiles,
+ chatHistory: game.chatHistory,
+ chatHistoryLimit: CHAT_HISTORY_SIZE_LIMIT,
+ chatMessageMaxSize: CHAT_MESSAGE_MAX_SIZE,
version: VERSION
})
);