403 lines
13 KiB
HTML
Executable file
403 lines
13 KiB
HTML
Executable file
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>Cockatrice web client</title>
|
|
<link rel="shortcut icon" href="imgs/cockatrice.png" />
|
|
<link rel="stylesheet" href="js/jquery-ui-1.11.4.css">
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<h1><img src="imgs/cockatrice.png" align="absmiddle"/> Cockatrice web client</h1>
|
|
</header>
|
|
<div id="loading">
|
|
Loading cockatrice web client...
|
|
</div>
|
|
|
|
<div id="error-dialog" title="Error" style="display:none"></div>
|
|
<div id="info-dialog" title="Information" style="display:none"></div>
|
|
|
|
<div id="tabs" style="display:none">
|
|
<ul>
|
|
<li><a href="#tab-login">Login</a></li>
|
|
<li><a href="#tab-server">Server</a></li>
|
|
<li><a href="#tab-account">Account</a></li>
|
|
</ul>
|
|
|
|
<div id="tab-login">
|
|
<h3>Login to server</h3>
|
|
<label for="host">Host</label>
|
|
<input type="text" id="host" value="" />
|
|
<br/>
|
|
<label for="port">Port</label>
|
|
<input type="text" id="port" value ="4748" />
|
|
<br/>
|
|
<label for="user">Username</label>
|
|
<input type="text" id="user" />
|
|
<br/>
|
|
<label for="pass">Password</label>
|
|
<input type="password" id="pass" />
|
|
<br/>
|
|
<button id="loginnow">Connect</button>
|
|
<button id="quit" style="display:none">Disconnect</button>
|
|
<span id="status"></span>
|
|
</div>
|
|
|
|
<div id="tab-server">
|
|
<!--
|
|
<h3>Rooms</h3>
|
|
<span id="roomslist"></span>
|
|
-->
|
|
<h3>Server messages</h3>
|
|
<div id="servermessages"></div>
|
|
</div>
|
|
|
|
<div id="tab-account">
|
|
<div class="buddies-container">
|
|
<h3>Buddies</h3>
|
|
<ul id="buddies" size="10"></ul>
|
|
</div>
|
|
<div class="ignores-container">
|
|
<h3>Ignores</h3>
|
|
<ul id="ignores" size="10"></ul>
|
|
</div>
|
|
<div class="userinfo-container">
|
|
<h3>User info</h3>
|
|
<span id="userinfo"></span>
|
|
</div>
|
|
<div class="missingfeatures-container">
|
|
<h3>Missing features</h3>
|
|
<span id="features"></span>
|
|
</div>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script src="js/jquery-1.11.3.js"></script>
|
|
<script src="js/jquery-ui-1.11.4.js"></script>
|
|
<script src="js/long.js"></script>
|
|
<script src="js/bytebuffer.js"></script>
|
|
<script src="js/protobuf.js"></script>
|
|
<script src="webclient.js"></script>
|
|
|
|
<script>
|
|
$("#tabs").tabs();
|
|
$("#tabs").tabs("disable").tabs("enable", "tab-login");
|
|
$("#loading").hide();
|
|
$("#tabs").show();
|
|
|
|
$( "#host" ).autocomplete({
|
|
source: [
|
|
// add custom servers here
|
|
"cockatrice.woogerworks.com",
|
|
"vps.poixen.com",
|
|
"chickatrice.net",
|
|
"127.0.0.1"
|
|
]
|
|
});
|
|
|
|
$( document ).ready(function() {
|
|
|
|
function ts2time(ts) {
|
|
var d = new Date(Number(ts));
|
|
return ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2) + ':' + ('0' + d.getSeconds()).slice(-2);
|
|
}
|
|
|
|
function getTime() {
|
|
var d = new Date();
|
|
return ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2) + ':' + ('0' + d.getSeconds()).slice(-2);
|
|
}
|
|
|
|
function htmlEscape(msg) {
|
|
return $("<div>").text(msg).html();
|
|
}
|
|
|
|
function htmlSanitize(msg) {
|
|
var div = $("<div>").html(msg);
|
|
|
|
// remove all tags except some
|
|
var tagsWhitelist = "br,a,img,center,b,font";
|
|
$(div).find("*").not(tagsWhitelist).each(function() {
|
|
$(this).replaceWith(this.innerHTML);
|
|
});
|
|
|
|
// remove all attributes except some
|
|
var attributesWhitelist = ["href","color"];
|
|
|
|
$(div).find("*").each(function() {
|
|
var attributes = this.attributes;
|
|
var i = attributes.length;
|
|
while( i-- ) {
|
|
var attr = attributes[i];
|
|
if( $.inArray(attr.name,attributesWhitelist) == -1 )
|
|
this.removeAttributeNode(attr);
|
|
}
|
|
});
|
|
|
|
// permit only some protocols in href
|
|
var hrefWhitelist = ["http://","https://","ftp://","//"];
|
|
|
|
$(div).find("[href]").each(function() {
|
|
var attributeValue = $(this).attr('href');
|
|
for(var protocol in hrefWhitelist)
|
|
if(attributeValue.indexOf(hrefWhitelist[protocol]) == 0)
|
|
return;
|
|
|
|
$(this).removeAttr('href');
|
|
});
|
|
|
|
return $(div).html();
|
|
}
|
|
|
|
function timeAgoToInterval(secs)
|
|
{
|
|
var days = Math.floor(secs / 86400);
|
|
var years = Math.floor(days / 365);
|
|
days -= years * 365;
|
|
var txt = '';
|
|
|
|
switch(years)
|
|
{
|
|
case 0:
|
|
break
|
|
case 1:
|
|
txt += '1 year ';
|
|
break;
|
|
default:
|
|
txt += years + ' years ';
|
|
break;
|
|
}
|
|
|
|
switch(days)
|
|
{
|
|
case 0:
|
|
txt += '0 days ';
|
|
case 1:
|
|
txt += '1 day ';
|
|
break;
|
|
default:
|
|
txt += days + ' days ';
|
|
break;
|
|
}
|
|
|
|
return txt;
|
|
}
|
|
|
|
function decodeUserLevel(id) {
|
|
var levels = WebClient.pb.ServerInfo_User.UserLevelFlag;
|
|
if (id & levels.IsAdmin)
|
|
return "Administrator";
|
|
else if (id & levels.IsModerator)
|
|
return "Moderator";
|
|
else if (id & levels.IsRegistered)
|
|
return "Registered user";
|
|
else
|
|
return "Unregistered user";
|
|
}
|
|
|
|
function decodeGender(id) {
|
|
var genders = WebClient.pb.ServerInfo_User.Gender;
|
|
for(var key in genders)
|
|
{
|
|
if(id == genders[key])
|
|
return key;
|
|
}
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
$("#loginnow").click(connect);
|
|
$("#port, #user, #pass").keydown(function(e) {
|
|
if (e.keyCode == 13) { connect(); }
|
|
});
|
|
|
|
function connect() {
|
|
var host = $("#host").val();
|
|
var port = $("#port").val();
|
|
if(!host.length || !port.length)
|
|
{
|
|
alert('Please enter a valid host and port.');
|
|
return;
|
|
}
|
|
|
|
var options = {
|
|
"debug": true,
|
|
"autojoinrooms" : true,
|
|
"host": host,
|
|
"port": port,
|
|
"user": $("#user").val(),
|
|
"pass": $("#pass").val(),
|
|
"statusCallback" : function(id, desc) {
|
|
$("#status").text(desc);
|
|
if(id == StatusEnum.LOGGEDIN)
|
|
{
|
|
$("#tabs").tabs("enable").tabs("option", "active", 1);
|
|
$("#loginnow").hide();
|
|
$("#quit").show();
|
|
} else {
|
|
$("#tabs").tabs("disable").tabs("enable", "tab-login").tabs("option", "active", 0);
|
|
$("#quit").hide();
|
|
$("#loginnow").show().prop("disabled", false);
|
|
// close rooms
|
|
$(".room-header, .room-container").remove();
|
|
|
|
}
|
|
},
|
|
"connectionClosedCallback" : function(id, desc) {
|
|
$("#status").text('Connection closed: ' + desc);
|
|
$("#tabs").tabs("disable").tabs("enable", "tab-login").tabs("option", "active", 0);
|
|
$("#quit").hide();
|
|
$("#loginnow").show().prop("disabled", false);
|
|
// close rooms
|
|
$(".room-header, .room-container").remove();
|
|
},
|
|
"serverMessageCallback" : function(message) {
|
|
$("#servermessages").append(htmlSanitize(message) + '<br/>');
|
|
},
|
|
"serverIdentificationCallback" : function(data) {
|
|
console.log('Connected to: ' + data.serverName + ' version ' + data.serverVersion + ' protocol ' + data.protocolVersion);
|
|
},
|
|
"serverShutdownCallback" : function(data) {
|
|
$("#info-dialog").text('The server is going to be restarted in ' + data.minutes + ' minute(s).\nAll running games will be lost.\nReason for shutdown: ' + data.reason);
|
|
$("#info-dialog").dialog();
|
|
},
|
|
"notifyUserCallback" : function(data) {
|
|
switch(data.type)
|
|
{
|
|
case WebClient.pb.Event_NotifyUser.NotificationType.PROMOTED:
|
|
$("#info-dialog").text('You have been promoted to moderator. Please log out and back in for changes to take effect.');
|
|
$("#info-dialog").dialog();
|
|
break;
|
|
case WebClient.pb.Event_NotifyUser.NotificationType.WARNING:
|
|
$("#info-dialog").text('You have received a warning due to ' + data.warningReason + '.\nPlease refrain from engaging in this activity or further actions may be taken against you. If you have any questions, please private message a moderator.');
|
|
$("#info-dialog").dialog();
|
|
break;
|
|
}
|
|
},
|
|
|
|
"userInfoCallback" : function(data) {
|
|
$("#userinfo").empty();
|
|
$.each(data.userInfo, function(key, value) {
|
|
// filter out inherited properties
|
|
if (!data.userInfo.hasOwnProperty(key))
|
|
return true;
|
|
|
|
// filter out empty values
|
|
if(value === null)
|
|
return true;
|
|
|
|
switch(key)
|
|
{
|
|
case 'avatarBmp':
|
|
$('#userinfo').prepend("<img id='avatar' src='data:image/JPEG;base64," + value.toBase64() + "' /><br/>");
|
|
break;
|
|
case 'accountageSecs':
|
|
$('#userinfo').append('Registered since: ' + timeAgoToInterval(value) + '<br/>');
|
|
break;
|
|
case 'userLevel':
|
|
$('#userinfo').append('User level: ' + decodeUserLevel(value) + '<br/>');
|
|
break;
|
|
case 'gender':
|
|
$('#userinfo').append('Gender: ' + decodeGender(value) + '<br/>');
|
|
break;
|
|
default:
|
|
$('#userinfo').append(key + ': ' + value + '<br/>');
|
|
break;
|
|
}
|
|
});
|
|
|
|
$('#buddies').empty();
|
|
$.each(data.buddyList, function(key, value) {
|
|
debugger;
|
|
$('#buddies').append('<li>' + value.name + '</li>');
|
|
});
|
|
$("#buddies").selectable();
|
|
|
|
$('#ignores').empty();
|
|
$.each(data.ignoreList, function(key, value) {
|
|
$('#ignores').append('<li>' + value.name + '</li>');
|
|
});
|
|
$("#ignores").selectable();
|
|
|
|
$("#features").empty();
|
|
$.each(data.missingFeatures, function(key, value) {
|
|
$('#features').append(value + '<br/>');
|
|
});
|
|
},
|
|
"listRoomsCallback" : function(rooms) {
|
|
// hide
|
|
//$("#roomslist").text(JSON.stringify(rooms, null, 4));
|
|
},
|
|
"errorCallback" : function(id, desc) {
|
|
$("#error-dialog").text(desc);
|
|
$("#error-dialog").dialog();
|
|
},
|
|
"joinRoomCallback" : function(room) {
|
|
$("div#tabs > ul").append(
|
|
"<li class='room-header'><a href='#tab-room-" + room["roomId"] + "'>" + room["name"] + "</a></li>"
|
|
);
|
|
$("div#tabs").append(
|
|
"<div class='room-container' id='tab-room-" + room["roomId"] + "'>" +
|
|
"<div class='userlist-container'>" +
|
|
"<h3>Userlist</h3>" +
|
|
"<ul class=\"userlist\" size=\"10\"></ul>" +
|
|
"</div><div class='chat-container'>" +
|
|
"<h3>Chat</h3>" +
|
|
"<div class=\"output\"></div>" +
|
|
"<br/><input type=\"text\" class=\"input\" />" +
|
|
"<button class=\"say\">say</button>" +
|
|
"</div></div><div class='clearfix'></div>"
|
|
);
|
|
$("div#tabs").tabs("refresh");
|
|
|
|
$("#tab-room-" + room["roomId"] + " .userlist").empty();
|
|
$.each(room["userList"], function(key, value) {
|
|
$("#tab-room-" + room["roomId"] + " .userlist").append('<li>' + value.name + '</li>');
|
|
});
|
|
$("#tab-room-" + room["roomId"] + " .userlist").selectable();
|
|
|
|
$("#tab-room-" + room["roomId"] + " .say").click(function() {
|
|
var msg = $("#tab-room-" + room["roomId"] + " .input").val();
|
|
$("#tab-room-" + room["roomId"] + " .input").val("");
|
|
WebClient.roomSay(room["roomId"], msg);
|
|
});
|
|
$("#tab-room-" + room["roomId"] + " .input").keydown(function(e) {
|
|
if (e.keyCode == 13) {
|
|
var msg = $("#tab-room-" + room["roomId"] + " .input").val();
|
|
$("#tab-room-" + room["roomId"] + " .input").val("");
|
|
WebClient.roomSay(room["roomId"], msg);
|
|
}
|
|
});
|
|
},
|
|
"roomMessageCallback" : function(roomId, message) {
|
|
var text;
|
|
switch(message["messageType"])
|
|
{
|
|
case WebClient.pb.Event_RoomSay.RoomMessageType.Welcome:
|
|
text = "<span class='serverwelcome'>" + htmlEscape(message["message"]) + "</span>";
|
|
break;
|
|
case WebClient.pb.Event_RoomSay.RoomMessageType.ChatHistory:
|
|
text = "<span class='chathistory'>[" + ts2time(message["timeOf"]) + "] " + htmlEscape(message["message"]) + "</span>";
|
|
break;
|
|
default:
|
|
text = "[" + getTime() + "] " + htmlEscape(message["name"]) + ": " + htmlEscape(message["message"]);
|
|
break;
|
|
}
|
|
$("#tab-room-" + roomId + " .output").append(text + '<br/>');
|
|
},
|
|
};
|
|
|
|
$(this).prop("disabled", true);
|
|
WebClient.connect(options);
|
|
};
|
|
|
|
$("#quit").click(function() {
|
|
WebClient.disconnect();
|
|
});
|
|
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|