Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f9b2a37
Merge pull request #21 from Cardshifter/master
sirpython Aug 6, 2015
afd60bf
now implements new API feature: onReady, switches to lobby screen.
acostarelli Aug 6, 2015
8bf54ae
wrote a todo on the init function for onError
acostarelli Aug 6, 2015
f26a750
initial css and html for lobby
acostarelli Aug 6, 2015
13707bf
sends query message and attempts to update player list
acostarelli Aug 6, 2015
b2d273d
added lobby to the routeProvider, and added a script ref for it's con…
acostarelli Aug 6, 2015
1b958f0
implemented onError, login_controller now uses it
acostarelli Aug 6, 2015
024b896
fixed double click bug, disables button after click
acostarelli Aug 6, 2015
bfe1749
removed console.logs.. excuse the content, horrible typing mistakes w…
acostarelli Aug 6, 2015
d9b4204
Added comments
acostarelli Aug 6, 2015
209e176
Removed ng-controller from the top because the controller was being c…
acostarelli Aug 6, 2015
e612258
will now display users and chat messages in very basic lists
acostarelli Aug 6, 2015
b235ff5
now uses $interval to update chat and users
acostarelli Aug 6, 2015
09e29c6
removed ng-controller so it is not created twice
acostarelli Aug 6, 2015
6b885c8
MAJOR FIX now, the API correctly sends messages
acostarelli Aug 6, 2015
c034334
correctly parses messages from server, new onReceive argument on send…
acostarelli Aug 7, 2015
fc39e56
cleaned up console.logs and comments
acostarelli Aug 7, 2015
24a057e
successfully keeps a list of users and chat messages (very, very basic)
acostarelli Aug 7, 2015
02594d4
stores current user information globally
acostarelli Aug 7, 2015
a5f6187
added form for sending a message
acostarelli Aug 7, 2015
53169cb
added a function sendMessage
acostarelli Aug 7, 2015
c811d1e
chatId is always 1 and from is always "unused", removed global user i…
acostarelli Aug 7, 2015
2b7c38a
all css will be in one file
acostarelli Aug 7, 2015
14ce163
no longer neeeded
sirpython Aug 7, 2015
defa4c1
will remove a user if an OFFLINE message is received
acostarelli Aug 7, 2015
8980974
added chat feed limit where oldest message recycle, eliminated magic …
acostarelli Aug 7, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
9 changes: 9 additions & 0 deletions cardshifter.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@
<head>
<title>Cardshifter</title>

<!-- Boostrap -->
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet"/>

<!-- The main CSS file -->
<link href="cardshifter.css" rel="stylesheet"/>

<!-- AngularJS libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.js"></script>

<!-- The API for communicating with the server -->
<script src="server_interface/server_interface.js"></script>

<!-- Controllers -->
<script src="cardshifter.js"></script>
<script src="login/login_controller.js"></script>
<script src="lobby/lobby_controller.js"></script>
</head>
<body>
<!-- Application pages will be injected here -->
<div ng-view></div>
</body>
</html>
7 changes: 4 additions & 3 deletions cardshifter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ CardshifterApp.config(function($routeProvider) {
$routeProvider
.when("/", { // default page is Login
controller: "LoginController",
// file name might change
templateUrl: "login/login.html",
css: "login/login.css"
})

.when("/lobby", {
controller: "LobbyController",
templateUrl: "lobby/lobby.html",
})
});
20 changes: 20 additions & 0 deletions lobby/lobby.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div>
<div>
<h2>Online users:</h2>
<ul>
<li ng-repeat="user in users">
{{user.name}}
</li>
</ul>
<h2>Chat:</h2>
<ul>
<li ng-repeat="message in chatMessages">
{{message.from}}: {{message.message}}
</li>
</ul>
<form>
<input ng-model="user_chat_message" type="text"/>
<input ng-click="sendMessage()" ng-disabled="sending" type="button" value="Send Message"/>
</form>
</div>
</div>
50 changes: 50 additions & 0 deletions lobby/lobby_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
CardshifterApp.controller("LobbyController", function($scope, $interval, $timeout) {
var CHAT_FEED_LIMIT = 10;
var POLL_FREQ = 2000;
var MESSAGE_DELAY = 3000;

$scope.users = [];
$scope.chatMessages = [];

var getUsersMessage = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", "");
CardshifterServerAPI.sendMessage(getUsersMessage);

$interval(function() { // update chat and users
while(message = CardshifterServerAPI.getMessage()) {
switch(message.command) {
case "userstatus":
// do conditional checking if user is offline
if(message.status === "OFFLINE") {
for(var i = 0, length = $scope.users.length; i < length; i++) {
// if the user described in the message is the user in this iteration
if($scope.users[i].name === message.name) {
$scope.users.splice(i, 1); // remove that user from the array
}
}
} else {
$scope.users.push(message);
}

break;
case "chat":
if($scope.chatMessages.length === CHAT_FEED_LIMIT) {
// remove the latest (opposite of earliest) chat message
$scope.chatMessages.shift();
}
$scope.chatMessages.push(message);
break;
}
}
}, POLL_FREQ);

$scope.sendMessage = function() {
$scope.sending = true;
var chatMessage = new CardshifterServerAPI.messageTypes.ChatMessage($scope.user_chat_message);
CardshifterServerAPI.sendMessage(chatMessage);

$scope.user_chat_message = ""; // clear the input box
$timeout(function() { // allow another message to be sent in 3 seconds
$scope.sending = false;
}, MESSAGE_DELAY);
}
});
4 changes: 2 additions & 2 deletions login/login.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div ng-controller="LoginController" class="col-sm-9 col-md-10 main csh-body">
<div class="col-sm-9 col-md-10 main csh-body">
<h1>Cardshifter login</h1>
<form name="login_information" id="login_information" class="login-form">
<div class="form-group">
Expand Down Expand Up @@ -30,7 +30,7 @@ <h1>Cardshifter login</h1>
<input name="test_message" id="test_message" type="text" size="100" class="form-control" placeholder="Optional... Leave blank unless using for testing." />
</div>
<div class="form-group">
<input ng-click="login()" name="submit" id="submit" type="button" value="Log in" class="btn btn-success" />
<input ng-click="login()" ng-disabled="loggedIn" name="submit" id="submit" type="button" value="Log in" class="btn btn-success" />
<input name="test_websocket" id="test_websocket" type="button" value="Test WebSocket" class="btn btn-primary" />
<input name="disconnect_websocket" id="disconnect_websocket" type="button" value="Disconnect WebSocket" class="btn btn-danger" />
</div>
Expand Down
41 changes: 31 additions & 10 deletions login/login_controller.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
CardshifterApp.controller("LoginController", function($scope) {
CardshifterApp.controller("LoginController", function($scope, $location, $rootScope) {
var SUCCESS = 200;

$scope.login = function() {
$scope.loggedIn = true;
var finalServer = ($scope.server === "other" ? $scope.other_server : $scope.server);

CardshifterServerAPI.init(finalServer, $scope.is_secure);
var login = new CardshifterServerAPI.messageTypes.LoginMessage($scope.username);
CardshifterServerAPI.init(finalServer, $scope.is_secure, function() {
var login = new CardshifterServerAPI.messageTypes.LoginMessage($scope.username);

try {
CardshifterServerAPI.sendMessage(login, function(serverResponse) {
if(serverResponse.status === SUCCESS && serverResponse.message === "OK") {
$rootScope.$apply(function() {
$location.path("/lobby");
});
} else {
// I don't actually know what the server will respond with
// notify the user that there was an issue logging in (custom server issue ???)

console.log("server message: " + serverResponse.message);
$scope.loggedIn = false;
}
});

// TODO: Need to find a way to make this work;
// As written it tries to sendMessage the instant that the socket is created, in which case the socket is not ready
/* try {
CardshifterServerAPI.sendMessage(login);
} catch (e) {
console.log(e);
}*/
} catch(e) {
// notify the user that there was an issue logging in (loginmessage issue)
console.log("LoginMessage error(error 2): " + e);
$scope.loggedIn = false;
}
}, function() {
// notify the user that there was an issue logging in (websocket issue)
console.log("Websocket error(error 1)");
$scope.loggedIn = false;
});
}
});
48 changes: 39 additions & 9 deletions server_interface/server_interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@
this.readyState = readyState;
}

/**
Returns all the keys of obj and it's inherited keys

@param obj:Object -- The object
@return Object -- a new Object, containing obj's keys and inherited keys
@source http://stackoverflow.com/questions/8779249/how-to-stringify-inherited-objects-to-json

This is used so JSON.stringify can get the .command of a message.
*/
function flatten(obj) {
var result = Object.create(obj);
for(var key in result) {
result[key] = result[key];
}
return result;
}

window.CardshifterServerAPI = {
socket: null,
incomingMessages: [],
Expand Down Expand Up @@ -128,13 +145,11 @@
* <p>
* These are messages printed to the game lobby which are visible to all users present at the time the message is posted.
* @constructor
* @param chatId The Id of this chat message
* @param from The Id of the sender of this message
* @param message The content of this chat message
*/
ChatMessage: function(chatId, from, message) {
this.chatId = chatId;
this.from = from;
ChatMessage: function(message) {
this.chatId = 1;
this.from = "unused";
this.message = message;

this.toString = function() {
Expand Down Expand Up @@ -196,8 +211,9 @@
* This sets up all the message types to inherit the main `Message` class, and sets
* up the websocket that will be used to communicate to the server, and to recieve
* information from the server.
*
*/
init: function(server, isSecure, onReady) {
init: function(server, isSecure, onReady, onError) {
var types = this.messageTypes;
var self = this; // for the events

Expand All @@ -221,12 +237,13 @@
var socket = new WebSocket(protocolAddon + server);

socket.onmessage = function(message) {
self.incomingMessages.push(message);
self.incomingMessages.push(JSON.parse(message.data));
}

socket.onopen = onReady;

socket.onerror = function() {
onError();
this.socket = null;
}

Expand All @@ -237,15 +254,28 @@
* Sends a message to the server.
*
* @param message:Message -- The message to send.
* @param onReceive:Function (OPTIONAL) -- A function to run when a message has returned
* @error NotInitializedException -- If the API has not been initialized yet.
*
* This will use websocket setup by `this.init` to send a message to the server.
*
* NOTE: The onReceive function will NOT NECESSARILY be run when the desired request
* is received. However, it is likely.
*/
sendMessage: function(message) {
sendMessage: function(message, onReceive) {
var socket = this.socket;
var self = this;
if(socket) {
if(socket.readyState === SOCKET_OPEN) {
this.socket.send(JSON.stringify(message));
this.socket.send(JSON.stringify(flatten(message)));
if(onReceive) {
this.socket.onmessage = function(msg) {
onReceive(JSON.parse(msg.data));
this.onmessage = function(msg2) {
self.incomingMessages.push(JSON.parse(msg2.data));
}
}
}
} else {
throw new SocketNotReadyException("The Websocket is not yet ready to be used", socket.readyState);
}
Expand Down