Migrate from protobuf.js 5.x to 6.x (remove long.js and bytebuffer.js) Upgrade jQuery from 1.x to 3.x Upgrade jQueryUI to 1.12.x Use minimized version of js libraries Disable debug messages Fix default value for Event_RoomSay’s RoomMessageType field
406 lines
13 KiB
HTML
Executable file
406 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.12.1.min.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-3.2.1.min.js"></script>
|
|
<script src="js/jquery-ui-1.12.1.min.js"></script>
|
|
<script src="js/protobuf-6.7.0.min.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",
|
|
"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)
|
|
{
|
|
$(this).attr('target', '_blank');
|
|
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";
|
|
}
|
|
|
|
$("#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": false,
|
|
"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," + btoa(String.fromCharCode.apply(null, value)) + "' /><br/>");
|
|
break;
|
|
case 'accountageSecs':
|
|
$('#userinfo').append('Registered since: ' + timeAgoToInterval(value) + '<br/>');
|
|
break;
|
|
case 'userLevel':
|
|
$('#userinfo').append('User level: ' + decodeUserLevel(value) + '<br/>');
|
|
break;
|
|
case 'name':
|
|
$('#userinfo').append('Name: ' + value + '<br/>');
|
|
break;
|
|
case 'realName':
|
|
$('#userinfo').append('Real name: ' + value + '<br/>');
|
|
break;
|
|
case 'country':
|
|
$('#userinfo').append('Country: ' + value + '<br/>');
|
|
break;
|
|
case 'privlevel':
|
|
$('#userinfo').append('Privilege: ' + value + '<br/>');
|
|
break;
|
|
case 'id':
|
|
case 'serverId':
|
|
// don't output these fields
|
|
break;
|
|
default:
|
|
$('#userinfo').append(key + ': ' + value + '<br/>');
|
|
break;
|
|
}
|
|
});
|
|
|
|
$('#buddies').empty();
|
|
$.each(data.buddyList, function(key, value) {
|
|
$('#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>
|