Fix up per-game chats so global chat still works. Fix graphical glitch with game chat tab. Make enter work in game chat box. Clear game chat log when joinging game.

This commit is contained in:
Andy Janata 2013-02-24 18:47:05 -08:00
parent b1c8e52dd4
commit 300e7e09b7
9 changed files with 142 additions and 27 deletions

View File

@ -90,6 +90,10 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.CHAT] = function(data) {
// pass
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.GAME_CHAT] = function(data) {
// pass
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.LOG_OUT] = function(data) {
window.location.reload();
};

View File

@ -43,7 +43,7 @@ $(document).ready(function() {
$("#nickbox").keyup(nickbox_keyup);
$("#nickbox").focus();
$(".chat", $("#tab-global")).keyup(chat_keyup);
$(".chat", $("#tab-global")).keyup(chat_keyup($(".chat_submit", $("#tab-global"))));
$(".chat_submit", $("#tab-global")).click(chatsubmit_click(null, $("#tab-global")));
// TODO: have some sort of mechanism to alert the server that we have unloaded the page, but
@ -92,14 +92,16 @@ function nicknameconfirm_click() {
/**
* Handle a key up event in the chat box. If the key was enter, send the message to the server.
*
* @param {jQuery.Event}
* e
* @param {jQuery.HTMLButtonElement}
* submitButton Submit button for the chat box.
*/
function chat_keyup(e) {
if (e.which == 13) {
$(".chat_submit", $('#tab-global')).click();
e.preventDefault();
}
function chat_keyup(submitButton) {
return function(e) {
if (e.which == 13) {
$(submitButton).click();
e.preventDefault();
}
};
}
/**
@ -132,8 +134,12 @@ function chatsubmit_click(game_id, parent_element) {
switch (cmd) {
// TODO support an /ignore command
case '':
// TODO when I get multiple channels working, this needs to know active and pass it
ajax = cah.Ajax.build(cah.$.AjaxOperation.CHAT).withMessage(text);
if (game_id != undefined) {
ajax = cah.Ajax.build(cah.$.AjaxOperation.GAME_CHAT).withGameId(game_id);
} else {
ajax = cah.Ajax.build(cah.$.AjaxOperation.CHAT);
}
ajax = ajax.withMessage(text);
cah.log.status_with_game(game_id, "<" + cah.nickname + "> " + text);
break;
case 'kick':

View File

@ -16,6 +16,7 @@ cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
cah.$.AjaxOperation.PLAY_CARD = "pc";
cah.$.AjaxOperation.CREATE_GAME = "cg";
cah.$.AjaxOperation.GAME_CHAT = "GC";
cah.$.AjaxOperation.KICK = "K";
cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl";
cah.$.AjaxOperation.GET_CARDS = "gc";

View File

@ -58,16 +58,18 @@ cah.Game = function(id) {
this.scoreboardElement_.id = "scoreboard_" + id;
$(this.scoreboardElement_).removeClass("hide");
var chatElement = $("#tab-global").clone()[0];
/**
* The element for the chat room for this game
*
*
* @type {HTMLDivElement}
* @private
*/
this.chatElement_ = chatElement;
chatElement.id = "tab-chat-game_" + this.id_;
$(".chat_submit", chatElement).click(chatsubmit_click(this.id_, chatElement));
this.chatElement_ = $("#tab-global").clone()[0];
this.chatElement_.id = "tab-chat-game_" + this.id_;
$(".chat_submit", this.chatElement_).click(chatsubmit_click(this.id_, this.chatElement_));
$(".chat", this.chatElement_).keyup(chat_keyup($(".chat_submit", this.chatElement_)));
// TODO make it not even copy this in the first place
$(".log", this.chatElement_).empty();
/**
* The element for the game options for this game.
@ -672,11 +674,13 @@ cah.Game.prototype.insertIntoDocument = function() {
this.gameChatTab_ = $("<li>");
linkToChatArea.attr("href", "#" + this.chatElement_.id);
linkToChatArea.text("Chat with game members");
linkToChatArea.addClass("tab-button");
this.gameChatTab_.append(linkToChatArea);
$("#tabs ul").append(this.gameChatTab_);
$("#tabs").append(this.chatElement_);
$("#tabs").tabs("refresh");
linkToChatArea.click();
this.windowResize_();
// TODO display a loading animation
};

View File

@ -103,7 +103,7 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.CHAT] = function(data) {
// don't display our own chat
if (from != cah.nickname && show) {
cah.log.status_with_game(game,"<" + data[cah.$.LongPollResponse.FROM] + "> "
cah.log.status_with_game(game, "<" + data[cah.$.LongPollResponse.FROM] + "> "
+ data[cah.$.LongPollResponse.MESSAGE], clazz);
}
};

View File

@ -164,6 +164,7 @@ public class Constants {
CHAT("c"),
CREATE_GAME("cg"),
FIRST_LOAD("fl"),
GAME_CHAT("GC"),
GAME_LIST("ggl"),
/**
* Get all cards for a particular game: black, hand, and round white cards.

View File

@ -35,10 +35,9 @@ import net.socialgamer.cah.Constants.ErrorCode;
import net.socialgamer.cah.Constants.LongPollEvent;
import net.socialgamer.cah.Constants.LongPollResponse;
import net.socialgamer.cah.Constants.ReturnableData;
import net.socialgamer.cah.Constants.SessionAttribute;
import net.socialgamer.cah.RequestWrapper;
import net.socialgamer.cah.data.ConnectedUsers;
import net.socialgamer.cah.data.Game;
import net.socialgamer.cah.data.GameManager;
import net.socialgamer.cah.data.QueuedMessage.MessageType;
import net.socialgamer.cah.data.User;
@ -50,23 +49,25 @@ import com.google.inject.Inject;
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
public class ChatHandler extends GameWithPlayerHandler {
public class ChatHandler extends Handler {
public static final String OP = AjaxOperation.CHAT.toString();
private final ConnectedUsers users;
@Inject
public ChatHandler(final GameManager gameManager, final ConnectedUsers users) {
super(gameManager);
public ChatHandler(final ConnectedUsers users) {
this.users = users;
}
@Override
public Map<ReturnableData, Object> handleWithUserInGame(final RequestWrapper request,
final HttpSession session, final User user, final Game game) {
public Map<ReturnableData, Object> handle(final RequestWrapper request,
final HttpSession session) {
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
final User user = (User) session.getAttribute(SessionAttribute.USER);
assert (user != null);
if (request.getParameter(AjaxRequest.MESSAGE) == null) {
return error(ErrorCode.NO_MSG_SPECIFIED);
} else {
@ -93,10 +94,8 @@ public class ChatHandler extends GameWithPlayerHandler {
broadcastData.put(LongPollResponse.FROM, user.getNickname());
broadcastData.put(LongPollResponse.MESSAGE, message);
broadcastData.put(LongPollResponse.FROM_ADMIN, user.isAdmin());
broadcastData.put(LongPollResponse.GAME_ID, game.getId());
// TODO once there are multiple chat channels, put the destination here
// TODO once there are games and they have their own chat, make it only send to participants
game.broadcastToPlayers(MessageType.CHAT, broadcastData);
// broadcastData.put(LongPollResponse.GAME_ID, -1);
users.broadcastToAll(MessageType.CHAT, broadcastData);
}
}

View File

@ -0,0 +1,99 @@
/**
* Copyright (c) 2012, Andy Janata
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.socialgamer.cah.handlers;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import net.socialgamer.cah.Constants;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest;
import net.socialgamer.cah.Constants.ErrorCode;
import net.socialgamer.cah.Constants.LongPollEvent;
import net.socialgamer.cah.Constants.LongPollResponse;
import net.socialgamer.cah.Constants.ReturnableData;
import net.socialgamer.cah.RequestWrapper;
import net.socialgamer.cah.data.Game;
import net.socialgamer.cah.data.GameManager;
import net.socialgamer.cah.data.QueuedMessage.MessageType;
import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/**
* Handler for chat messages.
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
public class GameChatHandler extends GameWithPlayerHandler {
public static final String OP = AjaxOperation.GAME_CHAT.toString();
@Inject
public GameChatHandler(final GameManager gameManager) {
super(gameManager);
}
@Override
public Map<ReturnableData, Object> handleWithUserInGame(final RequestWrapper request,
final HttpSession session, final User user, final Game game) {
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
if (request.getParameter(AjaxRequest.MESSAGE) == null) {
return error(ErrorCode.NO_MSG_SPECIFIED);
} else {
final String message = request.getParameter(AjaxRequest.MESSAGE).trim();
// Intentionally leaving flood protection as per-user, rather than
// changing it to per-user-per-game.
if (user.getLastMessageTimes().size() >= Constants.CHAT_FLOOD_MESSAGE_COUNT) {
final Long head = user.getLastMessageTimes().get(0);
if (System.currentTimeMillis() - head < Constants.CHAT_FLOOD_TIME) {
return error(ErrorCode.TOO_FAST);
}
user.getLastMessageTimes().remove(0);
}
if (message.length() > Constants.CHAT_MAX_LENGTH) {
return error(ErrorCode.MESSAGE_TOO_LONG);
} else if (message.length() == 0) {
return error(ErrorCode.NO_MSG_SPECIFIED);
} else {
user.getLastMessageTimes().add(System.currentTimeMillis());
final HashMap<ReturnableData, Object> broadcastData = new HashMap<ReturnableData, Object>();
broadcastData.put(LongPollResponse.EVENT, LongPollEvent.CHAT.toString());
broadcastData.put(LongPollResponse.FROM, user.getNickname());
broadcastData.put(LongPollResponse.MESSAGE, message);
broadcastData.put(LongPollResponse.FROM_ADMIN, user.isAdmin());
broadcastData.put(LongPollResponse.GAME_ID, game.getId());
game.broadcastToPlayers(MessageType.CHAT, broadcastData);
}
}
return data;
}
}

View File

@ -16,6 +16,7 @@ public class Handlers {
LIST.put(ChatHandler.OP, ChatHandler.class);
LIST.put(CreateGameHandler.OP, CreateGameHandler.class);
LIST.put(FirstLoadHandler.OP, FirstLoadHandler.class);
LIST.put(GameChatHandler.OP, GameChatHandler.class);
LIST.put(GameListHandler.OP, GameListHandler.class);
LIST.put(GetCardsHandler.OP, GetCardsHandler.class);
LIST.put(GetGameInfoHandler.OP, GetGameInfoHandler.class);