merged feature/user_management into master
This commit is contained in:
commit
dcc9472906
@ -1,199 +0,0 @@
|
||||
class GameServerConnection
|
||||
{
|
||||
constructor(ip, port)
|
||||
{
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.player = null;
|
||||
this.socket = null;
|
||||
this.registered = false;
|
||||
|
||||
this.game_manager = null;
|
||||
this.connected = false;
|
||||
}
|
||||
|
||||
set_player(p)
|
||||
{
|
||||
this.player = p;
|
||||
}
|
||||
|
||||
set_game_manager(gm)
|
||||
{
|
||||
this.game_manager = gm;
|
||||
}
|
||||
|
||||
is_registered()
|
||||
{
|
||||
return this.registered;
|
||||
}
|
||||
|
||||
is_connected()
|
||||
{
|
||||
return this.connected;
|
||||
}
|
||||
|
||||
on_open(callback_func)
|
||||
{
|
||||
// TODO
|
||||
console.log("connected to " + this.ip + ":" + this.port);
|
||||
this.connected = true;
|
||||
callback_func();
|
||||
}
|
||||
|
||||
on_close()
|
||||
{
|
||||
this.game_manager.end_game_listener()
|
||||
}
|
||||
|
||||
on_error()
|
||||
{
|
||||
console.log("error in websocket connection");
|
||||
this.game_manager.connection_error_listener();
|
||||
}
|
||||
|
||||
on_message(event)
|
||||
{
|
||||
var json_msg = event.data;
|
||||
var msg = JSON.parse(json_msg);
|
||||
|
||||
if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data"))
|
||||
{
|
||||
console.log("received wrong formatted message");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(msg.type)
|
||||
{
|
||||
case "register_response":
|
||||
this.on_register_response(msg.data);
|
||||
break;
|
||||
|
||||
case "game_starts":
|
||||
this.on_game_starts(msg.data);
|
||||
break;
|
||||
|
||||
case "move":
|
||||
this.on_move(msg.data);
|
||||
break;
|
||||
|
||||
case "move_response":
|
||||
this.on_move_response(msg.data);
|
||||
break;
|
||||
|
||||
case "end_game":
|
||||
this.on_end_game(msg.data);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
on_register_response(data)
|
||||
{
|
||||
var success = data.success;
|
||||
this.game_manager.register_response_listener(success);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
this.socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
on_game_starts(data)
|
||||
{
|
||||
var op_name = data.opponent_name;
|
||||
var is_first_move = data.is_first_move;
|
||||
|
||||
this.game_manager.start_game_listener(op_name, is_first_move);
|
||||
}
|
||||
|
||||
on_move(data)
|
||||
{
|
||||
var sub_x = data.sub_x;
|
||||
var sub_y = data.sub_y;
|
||||
var x = data.x;
|
||||
var y = data.y;
|
||||
|
||||
this.game_manager.move_listener(sub_x, sub_y, x, y);
|
||||
}
|
||||
|
||||
on_move_response(data)
|
||||
{
|
||||
if (data.success)
|
||||
{
|
||||
console.log("move accepted");
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error("move not accepted");
|
||||
}
|
||||
}
|
||||
|
||||
on_end_game(data)
|
||||
{
|
||||
this.game_manager.end_game_listener();
|
||||
this.close();
|
||||
}
|
||||
|
||||
connect(callback_func)
|
||||
{
|
||||
this.socket = new WebSocket("wss://" + this.ip + ":" + this.port);
|
||||
this.socket.onmessage = (e => this.on_message(e));
|
||||
this.socket.onopen = (() => this.on_open(callback_func));
|
||||
this.socket.onerror = (() => this.on_error());
|
||||
this.socket.onclose = (() => this.on_close());
|
||||
}
|
||||
|
||||
send_move(sub_x, sub_y, x, y)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "move",
|
||||
data: {
|
||||
sub_x: "" + sub_x,
|
||||
sub_y: "" + sub_y,
|
||||
x: "" + x,
|
||||
y: "" + y
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
register()
|
||||
{
|
||||
// register for game queue
|
||||
var msg_object = {
|
||||
type: "register",
|
||||
data: {
|
||||
id: this.player.get_id(),
|
||||
name: this.player.get_name()
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
send_disconnect()
|
||||
{
|
||||
if (!this.is_connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var msg_object = {
|
||||
type: "end_game",
|
||||
data: {
|
||||
msg: ""
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
close()
|
||||
{
|
||||
if (this.is_connected)
|
||||
{
|
||||
this.is_connected = false;
|
||||
this.socket.close();
|
||||
}
|
||||
}
|
||||
}
|
33
grid.js
33
grid.js
@ -1,9 +1,9 @@
|
||||
class Grid
|
||||
{
|
||||
constructor(n, grid_container_div, tile_width, tile_height, ground_color)
|
||||
constructor(n, parent, tile_width, tile_height, ground_color)
|
||||
{
|
||||
this.n = n;
|
||||
this.grid_container_div = grid_container_div;
|
||||
this.grid_container_div = null;
|
||||
this.tile_width = tile_width;
|
||||
this.tile_height = tile_height;
|
||||
this.ground_color = ground_color;
|
||||
@ -11,6 +11,8 @@ class Grid
|
||||
this.won_player = null;
|
||||
this.n_complete_subgrids = 0;
|
||||
|
||||
this.parent = parent;
|
||||
|
||||
this.subgrids = []
|
||||
|
||||
console.log("create grid of size " + this.n);
|
||||
@ -20,6 +22,10 @@ class Grid
|
||||
|
||||
create()
|
||||
{
|
||||
this.grid_container_div = document.createElement("div");
|
||||
this.grid_container_div.className = "grid-container";
|
||||
this.parent.appendChild(this.grid_container_div);
|
||||
|
||||
var x,y;
|
||||
for (y = 0; y < this.n; y++)
|
||||
{
|
||||
@ -49,7 +55,10 @@ class Grid
|
||||
{
|
||||
this.check_win(sub_x, sub_y, x, y);
|
||||
this.check_complete(sub_x, sub_y, x, y);
|
||||
this.click_callback(sub_x, sub_y, x, y);
|
||||
if (this.click_callback != null)
|
||||
{
|
||||
this.click_callback(sub_x, sub_y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
player_change_listener(player)
|
||||
@ -81,7 +90,7 @@ class Grid
|
||||
|
||||
check_complete(sub_x, sub_y, x, y)
|
||||
{
|
||||
if (this.subgrids[sub_x][sub_y].is_won() || this.subgrids[sub_x][sub_y].is_draw())
|
||||
if (this.subgrids[sub_y][sub_x].is_won() || this.subgrids[sub_y][sub_x].is_draw())
|
||||
{
|
||||
this.n_complete_subgrids++;
|
||||
}
|
||||
@ -211,6 +220,22 @@ class Grid
|
||||
}
|
||||
}
|
||||
|
||||
unblock_all_non_completed()
|
||||
{
|
||||
var x,y;
|
||||
for (y = 0; y < this.n; y++)
|
||||
{
|
||||
for (x = 0; x < this.n; x++)
|
||||
{
|
||||
if (this.subgrids[y][x].is_won() || this.subgrids[y][x].is_draw())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
this.subgrids[y][x].unblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block(x,y)
|
||||
{
|
||||
this.subgrids[y][x].block();
|
||||
|
BIN
icon.png
BIN
icon.png
Binary file not shown.
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 19 KiB |
20
index.html
20
index.html
@ -2,29 +2,25 @@
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
<meta name="theme-color" content="#7e57c2" />
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="icon" href="icon.png" type="image/png"/>
|
||||
<script defer src="site.js"></script>
|
||||
<title>ultimate tictactoe</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-container" class="main-container">
|
||||
<div id="grid-container" class="grid-container"></div>
|
||||
<div id="sidebar-container" class="sidebar-container">
|
||||
<div id="create-game-container" class="create-game-container"></div>
|
||||
<div id="setting-container" class="setting-container"></div>
|
||||
<div id="control-container" class="control-container"></div>
|
||||
<div id="info-container" class="info-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main-container" class="main-container"></div>
|
||||
<script src="tools.js"></script>
|
||||
<script src="settings.js"></script>
|
||||
<script src="player.js"></script>
|
||||
<script src="tile.js"></script>
|
||||
<script src="grid.js"></script>
|
||||
<script src="subgrid.js"></script>
|
||||
<script src="game_manager.js"></script>
|
||||
<script src="game_server_connection.js"></script>
|
||||
<script src="sidebar.js"></script>
|
||||
<script src="local_match_manager.js"></script>
|
||||
<script src="online_match_manager.js"></script>
|
||||
<script src="websocket_connection.js"></script>
|
||||
<script src="infobar.js"></script>
|
||||
<script src="infocontainer.js"></script>
|
||||
<script src="main.js"></script>
|
||||
|
||||
</body>
|
||||
|
15
infobar.js
Normal file
15
infobar.js
Normal file
@ -0,0 +1,15 @@
|
||||
class Infobar
|
||||
{
|
||||
constructor(parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.container = document.createElement("div");
|
||||
this.container.className = "infobar-container";
|
||||
this.parent.appendChild(this.container);
|
||||
}
|
||||
|
||||
create_infocontainer()
|
||||
{
|
||||
return new Infocontainer(this.container);
|
||||
}
|
||||
}
|
76
infocontainer.js
Normal file
76
infocontainer.js
Normal file
@ -0,0 +1,76 @@
|
||||
class Infocontainer
|
||||
{
|
||||
constructor(parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.container = document.createElement("div");
|
||||
this.container.className = "info-container";
|
||||
this.parent.appendChild(this.container);
|
||||
}
|
||||
|
||||
create_button(text)
|
||||
{
|
||||
var b = document.createElement("button");
|
||||
b.className = "infobar-button";
|
||||
b.appendChild(document.createTextNode(text));
|
||||
this.container.appendChild(b)
|
||||
return b;
|
||||
}
|
||||
|
||||
create_input(placeholder, pw=false)
|
||||
{
|
||||
var i = document.createElement("input");
|
||||
i.className = "infobar-input";
|
||||
i.placeholder = placeholder;
|
||||
i.type = pw ? "password" : "text";
|
||||
|
||||
this.container.appendChild(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
create_label(text)
|
||||
{
|
||||
var l = document.createElement("label");
|
||||
l.className = "infobar-label";
|
||||
l.innerHTML = text;
|
||||
this.container.appendChild(l);
|
||||
return l;
|
||||
}
|
||||
|
||||
create_double_button(text, option)
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.className = "option-button-container";
|
||||
var b1 = document.createElement("button");
|
||||
var b2 = document.createElement("button");
|
||||
|
||||
b1.style.width = "10%";
|
||||
|
||||
b1.className = "infobar-button";
|
||||
b2.className = "infobar-button";
|
||||
|
||||
b1.style.width = "80%";
|
||||
b2.style.width = "20%";
|
||||
|
||||
|
||||
b1.appendChild(document.createTextNode(text));
|
||||
b2.appendChild(document.createTextNode(option));
|
||||
|
||||
div.appendChild(b1);
|
||||
div.appendChild(b2);
|
||||
|
||||
this.container.appendChild(div);
|
||||
|
||||
return [div, b1,b2];
|
||||
}
|
||||
|
||||
hide()
|
||||
{
|
||||
this.container.style.display = "none";
|
||||
}
|
||||
|
||||
show()
|
||||
{
|
||||
this.container.style.display = "inline-block";
|
||||
}
|
||||
}
|
72
local_match_manager.js
Normal file
72
local_match_manager.js
Normal file
@ -0,0 +1,72 @@
|
||||
class LocalMatchManager
|
||||
{
|
||||
constructor(grid, status_label, control_container)
|
||||
{
|
||||
this.grid = grid;
|
||||
this.status_label = status_label;
|
||||
|
||||
this.control_container = control_container;
|
||||
|
||||
this.control_container.show();
|
||||
|
||||
this.local_player_a = new Player("red player", 255,0,0);
|
||||
this.local_player_b = new Player("green player", 0,255,0);
|
||||
this.is_local_player_a = false;
|
||||
|
||||
this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l));
|
||||
|
||||
this.grid.deactivate_all();
|
||||
this.grid.unblock_all();
|
||||
|
||||
|
||||
this.toggle_local_player();
|
||||
}
|
||||
|
||||
click_listener(sub_x, sub_y, x,y)
|
||||
{
|
||||
// check whether the game is over:
|
||||
if (grid.is_won())
|
||||
{
|
||||
this.status_label.innerHTML = "" + grid.get_won_player().get_name() + " has won.";
|
||||
this.end_game();
|
||||
}
|
||||
else if (grid.is_complete())
|
||||
{
|
||||
this.status_label.innerHTML = "Draw. Everybody looses!";
|
||||
this.end_game(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.toggle_local_player();
|
||||
this.grid.block_all()
|
||||
if (this.grid.subgrids[y][x].is_draw() || this.grid.subgrids[y][x].is_won())
|
||||
{
|
||||
this.grid.unblock_all_non_completed();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.grid.subgrids[y][x].unblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggle_local_player()
|
||||
{
|
||||
this.is_local_player_a = !this.is_local_player_a;
|
||||
var next_player = this.is_local_player_a ? this.local_player_a : this.local_player_b;
|
||||
|
||||
this.status_label.innerHTML = "" + "it's " + next_player.get_name() + "'s turn...";
|
||||
this.grid.player_change_listener(next_player);
|
||||
}
|
||||
|
||||
end_game(closed_by_player = true)
|
||||
{
|
||||
if (closed_by_player)
|
||||
{
|
||||
this.status_label.innerHTML = "Game Over. Game Closed";
|
||||
}
|
||||
this.grid.block_all();
|
||||
}
|
||||
|
||||
|
||||
}
|
304
main.js
304
main.js
@ -3,18 +3,304 @@ var n = style.getPropertyValue("--tictactoe_n");
|
||||
var tilesize = style.getPropertyValue("--tile-size");
|
||||
var default_opacity = style.getPropertyValue("--opacity");
|
||||
var ground_color = style.getPropertyValue("--ground-color");
|
||||
var main_container = document.getElementById("main-container");
|
||||
|
||||
var create_game_container = document.getElementById("create-game-container");
|
||||
var setting_container = document.getElementById("setting-container");
|
||||
var control_container = document.getElementById("control-container");
|
||||
var info_container = document.getElementById("info-container");
|
||||
|
||||
var grid = new Grid(n, document.getElementById("grid-container"), tilesize, tilesize, ground_color);
|
||||
var server_connection = new GameServerConnection(server_url, server_port);
|
||||
var game_manager = new GameManager(grid, server_connection);
|
||||
var sidebar = new Sidebar(create_game_container, setting_container, control_container, info_container, game_manager);
|
||||
var main_menu = new Infobar(main_container);
|
||||
var grid = new Grid(n, main_container, tilesize, tilesize, ground_color);
|
||||
var sub_menu = new Infobar(main_container);
|
||||
|
||||
|
||||
// fill containers with buttons and containers:
|
||||
|
||||
// empty dummy container on top (to force other containers to be at the bottom)
|
||||
dummy_main = main_menu.create_infocontainer();
|
||||
dummy_sub = sub_menu.create_infocontainer();
|
||||
|
||||
// start container:
|
||||
create_game_container = main_menu.create_infocontainer();
|
||||
create_game_container.create_label("Start Local Game");
|
||||
b_local_game = create_game_container.create_button("Local Game");
|
||||
|
||||
|
||||
|
||||
// register container:
|
||||
register_container = main_menu.create_infocontainer();
|
||||
register_container.create_label("Login to play online");
|
||||
i_register_username = register_container.create_input("username");
|
||||
i_register_pw = register_container.create_input("password", true);
|
||||
b_register = register_container.create_button("register/login");
|
||||
//register_container.create_label("(creates new account for a new username)");
|
||||
|
||||
// logout:
|
||||
logout_container = main_menu.create_infocontainer();
|
||||
l_username = logout_container.create_label("logged in as: ");
|
||||
b_logout = logout_container.create_button("logout");
|
||||
|
||||
|
||||
// fill subcontainer:
|
||||
match_slot_container = sub_menu.create_infocontainer();
|
||||
match_slot_container.create_label("Running Matches<br>(click to open)");
|
||||
|
||||
|
||||
// local match control:
|
||||
match_control = sub_menu.create_infocontainer();
|
||||
b_end_game = match_control.create_button("Close Match");
|
||||
|
||||
|
||||
// search match:
|
||||
search_match_container = sub_menu.create_infocontainer();
|
||||
search_match_container.create_label("Create Online Match");
|
||||
b_match_search = search_match_container.create_button("random match");
|
||||
|
||||
l_match_op = search_match_container.create_input("player name");
|
||||
b_match_invite = search_match_container.create_button("invite player");
|
||||
|
||||
search_match_container.create_label("Invite friends:")
|
||||
|
||||
|
||||
|
||||
//status:
|
||||
status_container = main_menu.create_infocontainer();
|
||||
l_status_head = status_container.create_label("Status:");
|
||||
l_status = status_container.create_label("select gamemode. click <br> <a href=https://en.wikipedia.org/wiki/Ultimate_tic-tac-toe#Rules>[here]</a> for the rules!");
|
||||
|
||||
|
||||
// global vars:
|
||||
|
||||
game_manager = null;
|
||||
|
||||
logged_in = false;
|
||||
|
||||
// connection stuff:
|
||||
|
||||
var connection = null;
|
||||
var session_id = null;
|
||||
|
||||
|
||||
// cookies:
|
||||
function get_cookie(cname) {
|
||||
var name = cname + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function set_cookie(cname, cvalue, exdays) {
|
||||
var d = new Date();
|
||||
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
|
||||
var expires = "expires="+d.toUTCString();
|
||||
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
||||
}
|
||||
|
||||
function check_cookie(cname) {
|
||||
var tmp = get_cookie(cname);
|
||||
if (tmp != "") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// global funcs:
|
||||
|
||||
disable_all_containers = function()
|
||||
{
|
||||
create_game_container.hide();
|
||||
register_container.hide();
|
||||
logout_container.hide();
|
||||
match_slot_container.hide();
|
||||
search_match_container.hide();
|
||||
match_control.hide();
|
||||
status_container.hide();
|
||||
|
||||
dummy_main.hide();
|
||||
dummy_sub.hide();
|
||||
}
|
||||
|
||||
|
||||
end_local_game = function()
|
||||
{
|
||||
disable_all_containers();
|
||||
create_game_container.show();
|
||||
status_container.show();
|
||||
if (logged_in)
|
||||
{
|
||||
logout_container.show();
|
||||
search_match_container.show();
|
||||
match_slot_container.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
register_container.show();
|
||||
}
|
||||
|
||||
game_manager = null;
|
||||
}
|
||||
|
||||
on_close_click = function() {
|
||||
if (game_manager != null)
|
||||
{
|
||||
game_manager.end_game();
|
||||
end_local_game();
|
||||
}
|
||||
else if (connection != null)
|
||||
{
|
||||
connection.on_close_click();
|
||||
match_control.hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
start_local_game = function()
|
||||
{
|
||||
console.log("clicked");
|
||||
disable_all_containers();
|
||||
match_control.show();
|
||||
dummy_main.show();
|
||||
dummy_sub.show();
|
||||
|
||||
status_container.show();
|
||||
|
||||
game_manager = new LocalMatchManager(grid, l_status, match_control, end_local_game);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// connection stuff:
|
||||
|
||||
login_callback = function()
|
||||
{
|
||||
logged_in = true;
|
||||
if (game_manager != null)
|
||||
{
|
||||
game_manager.end_game();
|
||||
|
||||
}
|
||||
end_local_game();
|
||||
l_username.innerHTML = "logged in as: " + connection.player.get_name();
|
||||
|
||||
set_cookie("sessionid", connection.session_id, 30);
|
||||
|
||||
}
|
||||
|
||||
logout = function()
|
||||
{
|
||||
logged_in = false;
|
||||
if (connection != null)
|
||||
{
|
||||
|
||||
connection.close();
|
||||
if (check_cookie("sessionid"))
|
||||
{
|
||||
// delete session:
|
||||
session_id = get_cookie("sessionid");
|
||||
set_cookie("sessionid", session_id, -100);
|
||||
session_id = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
connection = null;
|
||||
grid.unblock_all();
|
||||
grid.deactivate_all();
|
||||
grid.block_all();
|
||||
end_local_game();
|
||||
}
|
||||
|
||||
reconnect = function()
|
||||
{
|
||||
if (check_cookie("sessionid"))
|
||||
{
|
||||
session_id = get_cookie("sessionid");
|
||||
if (connection != null)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, search_match_container, login_callback, on_connection_error);
|
||||
connection.reconnect(session_id);
|
||||
}
|
||||
}
|
||||
|
||||
on_connection_error = function()
|
||||
{
|
||||
connection = null;
|
||||
logout();
|
||||
}
|
||||
|
||||
login = function(){
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, search_match_container, login_callback, on_connection_error);
|
||||
connection.connect(i_register_username.value.toLowerCase(), i_register_pw.value);
|
||||
}
|
||||
|
||||
search_match = function()
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
connection.send_match_request(null);
|
||||
}
|
||||
}
|
||||
|
||||
invite_player = function()
|
||||
{
|
||||
if (connection != null)
|
||||
{
|
||||
if (l_match_op.value == "")
|
||||
{
|
||||
l_status.innerHTML = "choose your opponent first!";
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.send_match_request(l_match_op.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// initiate stuff and connect events:
|
||||
|
||||
end_local_game();
|
||||
|
||||
|
||||
b_local_game.addEventListener("click", start_local_game);
|
||||
b_end_game.addEventListener("click", on_close_click);
|
||||
b_register.addEventListener("click", login);
|
||||
b_logout.addEventListener("click", logout);
|
||||
|
||||
b_match_search.addEventListener("click", search_match);
|
||||
b_match_invite.addEventListener("click", invite_player);
|
||||
|
||||
reconnect();
|
||||
|
||||
// register resize event:
|
||||
|
||||
window.addEventListener("resize", function() {
|
||||
var tilesize = getComputedStyle(document.body).getPropertyValue("--tile-size");
|
||||
grid.on_screen_orientation_change(tilesize, tilesize);
|
||||
})
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
window.onfocus = function() {
|
||||
if (session_id != null && connection == null)
|
||||
{
|
||||
reconnect();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
"display": "standalone",
|
||||
"start_url": "/website/ultimate_tictactoe/",
|
||||
"scope": "/website/ultimate_tictactoe/",
|
||||
"theme_color": "#4650e2",
|
||||
"background_color": "#1e2477",
|
||||
"theme_color": "#7e57c2",
|
||||
"background_color": "#31364A",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon.png",
|
||||
|
257
online_match_manager.js
Normal file
257
online_match_manager.js
Normal file
@ -0,0 +1,257 @@
|
||||
class OnlineMatchManager
|
||||
{
|
||||
constructor(grid, status_label, matches_container, control_container, game_server_connection, match_id, match_state, player_name)
|
||||
{
|
||||
this.grid = grid;
|
||||
this.status_label = status_label;
|
||||
|
||||
this.match_id = match_id;
|
||||
|
||||
this.game_server_connection = game_server_connection;
|
||||
|
||||
|
||||
this.match_state = match_state;
|
||||
this.player_name = player_name
|
||||
|
||||
var player_a = this.match_state.player_a;
|
||||
var player_b = this.match_state.player_b;
|
||||
|
||||
this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0);
|
||||
this.local_player = new Player(this.player_name, 0,255,0);
|
||||
|
||||
// create match button in match list:
|
||||
this.control_container = control_container;
|
||||
this.matches_container = matches_container;
|
||||
|
||||
var tmp = matches_container.create_double_button("" + this.online_opponent.get_name(), "+")
|
||||
|
||||
this.match_button = tmp[1];
|
||||
this.match_button_div = tmp[0];
|
||||
this.match_button_option = tmp[2];
|
||||
|
||||
if (this.game_server_connection.is_friend(this.online_opponent.get_name()))
|
||||
{
|
||||
this.match_button_option.disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.match_button_option.addEventListener("click", () => {
|
||||
this.game_server_connection.send_friend_request(this.online_opponent.get_name());
|
||||
this.match_button_option.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
this.match_button.addEventListener("click", () => this.open_match());
|
||||
|
||||
if (this.online_opponent.get_name() == this.match_state.active_player)
|
||||
{
|
||||
this.match_button.className = "infobar-button-red";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.match_button.className = "infobar-button-green"
|
||||
}
|
||||
|
||||
this.is_closed = false;
|
||||
|
||||
}
|
||||
|
||||
click_listener(sub_x, sub_y, x,y)
|
||||
{
|
||||
this.grid.block_all();
|
||||
|
||||
this.game_server_connection.send_move(sub_x, sub_y, x, y, this.match_id);
|
||||
|
||||
this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move";
|
||||
}
|
||||
|
||||
on_user_close()
|
||||
{
|
||||
|
||||
// send end match message:
|
||||
if (!this.match_state.game_over)
|
||||
{
|
||||
this.game_server_connection.send_end_match(this.match_id);
|
||||
}
|
||||
|
||||
if (this.match_button_div != null)
|
||||
{
|
||||
clearInner(this.match_button_div)
|
||||
this.matches_container.container.removeChild(this.match_button_div);
|
||||
this.match_button_div = null;
|
||||
}
|
||||
this.status_label.innerHTML = "match is closed";
|
||||
this.control_container.hide();
|
||||
this.is_closed = true;
|
||||
|
||||
}
|
||||
|
||||
remove_match()
|
||||
{
|
||||
if (this.match_button_div != null)
|
||||
{
|
||||
clearInner(this.match_button_div);
|
||||
this.matches_container.container.removeChild(this.match_button_div);
|
||||
this.match_button_div = null;
|
||||
}
|
||||
}
|
||||
|
||||
update_match_state(match_state)
|
||||
{
|
||||
this.match_state = match_state;
|
||||
|
||||
if (this.online_opponent.get_name() == this.match_state.active_player)
|
||||
{
|
||||
this.match_button.className = "infobar-button-red";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.match_button.className = "infobar-button-green"
|
||||
}
|
||||
|
||||
if (this.match_state.active_player == this.local_player.get_name())
|
||||
{
|
||||
this.game_server_connection.notify("your turn against " + this.online_opponent.get_name());
|
||||
}
|
||||
}
|
||||
|
||||
on_focus_loose()
|
||||
{
|
||||
if (this.online_opponent.get_name() == this.match_state.active_player)
|
||||
{
|
||||
this.match_button.className = "infobar-button-red";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.match_button.className = "infobar-button-green"
|
||||
}
|
||||
}
|
||||
|
||||
open_match()
|
||||
{
|
||||
this.grid.register_click_callback(null);
|
||||
|
||||
this.grid.deactivate_all();
|
||||
this.grid.unblock_all();
|
||||
|
||||
this.match_button.className = "infobar-button-active";
|
||||
|
||||
this.game_server_connection.set_active_match(this.match_id);
|
||||
|
||||
this.control_container.show();
|
||||
|
||||
var complete_field = this.match_state.complete_field;
|
||||
var global_field = this.match_state.global_field;
|
||||
|
||||
var sub_x = null;
|
||||
var sub_y = null;
|
||||
var x = null;
|
||||
var y = null;
|
||||
|
||||
if (this.match_state.last_move != null)
|
||||
{
|
||||
sub_x = this.match_state.last_move.sub_x;
|
||||
sub_y = this.match_state.last_move.sub_y;
|
||||
x = this.match_state.last_move.x;
|
||||
y = this.match_state.last_move.y;
|
||||
}
|
||||
|
||||
var game_over = this.match_state.game_over;
|
||||
var player_won = this.match_state.player_won;
|
||||
var current_player_name = this.match_state.active_player;
|
||||
|
||||
var player_a = this.match_state.player_a;
|
||||
var player_b = this.match_state.player_b;
|
||||
|
||||
console.log(game_over);
|
||||
console.log(current_player);
|
||||
|
||||
var FIELD_EMPTY = 0
|
||||
var FIELD_USER = player_a == this.player_name ? 1 : 2;
|
||||
var FIELD_OPPONENT = player_a == this.player_name ? 2 : 1;
|
||||
var FIELD_DRAW = 3
|
||||
|
||||
this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0);
|
||||
this.local_player = new Player(this.player_name, 0,255,0);
|
||||
|
||||
var i,j;
|
||||
for(j = 0; j < 9; j++)
|
||||
{
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
var si = Math.floor(i / 3);
|
||||
var sj = Math.floor(j / 3);
|
||||
if (complete_field[j][i] == FIELD_USER)
|
||||
{
|
||||
this.grid.subgrids[sj][si].player_change_listener(this.local_player);
|
||||
this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click();
|
||||
}
|
||||
if (complete_field[j][i] == FIELD_OPPONENT)
|
||||
{
|
||||
this.grid.subgrids[sj][si].player_change_listener(this.online_opponent);
|
||||
this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.grid.block_all();
|
||||
this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l));
|
||||
|
||||
if (game_over && player_won != null)
|
||||
{
|
||||
if (player_won == this.player_name)
|
||||
{
|
||||
this.status_label.innerHTML = "Congratulation, you won!";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.status_label.innerHTML = "Game over, you lost!";
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(game_over)
|
||||
{
|
||||
if (this.grid.is_complete())
|
||||
{
|
||||
this.status_label.innerHTML = "Draw. Everyone looses!";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.status_label.innerHTML = "Game was closed by server or opponent";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var current_player = this.player_name == current_player_name ? this.local_player : this.online_opponent;
|
||||
this.grid.player_change_listener(current_player);
|
||||
|
||||
|
||||
if (this.player_name == current_player_name)
|
||||
{
|
||||
|
||||
if (this.match_state.last_move != null)
|
||||
{
|
||||
if (this.grid.subgrids[y][x].is_won() || this.grid.subgrids[y][x].is_draw())
|
||||
{
|
||||
this.grid.unblock_all_non_completed();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.grid.unblock(x,y);
|
||||
}
|
||||
this.status_label.innerHTML = "It's your turn!";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.grid.unblock_all();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
var server_protocol = "ws://"
|
||||
var server_url = "127.0.0.1";
|
||||
var server_port = "5556";
|
||||
|
||||
var home = "https://the-cake-is-a-lie.net/website/ultimate_tictactoe/";
|
||||
var rel_home = "/website/ultimate_tictactoe";
|
||||
var server_url = "the-cake-is-a-lie.net";
|
||||
var server_port = "5555";
|
||||
var rel_home = "/website/ultimate_tictactoe";
|
184
sidebar.js
184
sidebar.js
@ -1,184 +0,0 @@
|
||||
class Sidebar
|
||||
{
|
||||
constructor(create_game_container, setting_container, control_container, info_container, game_manager)
|
||||
{
|
||||
this.create_game_container = create_game_container;
|
||||
this.setting_container = setting_container;
|
||||
this.control_container = control_container;
|
||||
this.info_container = info_container;
|
||||
|
||||
this.game_manager = game_manager;
|
||||
|
||||
this.fill_containers();
|
||||
this.bind_events();
|
||||
|
||||
this.activate_create_game();
|
||||
this.activate_setting();
|
||||
this.activate_info();
|
||||
}
|
||||
|
||||
create_button(text)
|
||||
{
|
||||
var b = document.createElement("button");
|
||||
b.className = "sidebar-button";
|
||||
b.appendChild(document.createTextNode(text));
|
||||
return b;
|
||||
}
|
||||
|
||||
create_input(text)
|
||||
{
|
||||
var i = document.createElement("input");
|
||||
i.className = "sidebar-input";
|
||||
i.type = "text";
|
||||
i.value = text;
|
||||
return i;
|
||||
}
|
||||
|
||||
create_label(text)
|
||||
{
|
||||
var l = document.createElement("label");
|
||||
l.className = "sidebar-label";
|
||||
l.innerHTML = text;
|
||||
return l;
|
||||
}
|
||||
|
||||
fill_containers()
|
||||
{
|
||||
|
||||
// create new game area:
|
||||
this.create_game_container.appendChild(this.create_label("Choose game type"));
|
||||
this.b_local = this.create_button("local game")
|
||||
this.create_game_container.appendChild(this.b_local);
|
||||
|
||||
this.b_remote = this.create_button("remote game");
|
||||
this.create_game_container.appendChild(this.b_remote);
|
||||
|
||||
this.create_game_container.style.display = "none";
|
||||
|
||||
|
||||
// settings area
|
||||
this.setting_container.appendChild(this.create_label("select online name:"));
|
||||
|
||||
this.i_player_name = this.create_input("");
|
||||
this.setting_container.appendChild(this.i_player_name);
|
||||
|
||||
this.setting_container.style.display = "none";
|
||||
|
||||
// control area:
|
||||
|
||||
this.b_end_game = this.create_button("end game");
|
||||
this.control_container.appendChild(this.b_end_game);
|
||||
|
||||
this.control_container.style.display = "none";
|
||||
|
||||
|
||||
// status area:
|
||||
this.status_title = this.create_label("");
|
||||
this.info_container.appendChild(this.status_title);
|
||||
|
||||
this.status_text = this.create_label("select gamemode. <br> <a href=https://en.wikipedia.org/wiki/Ultimate_tic-tac-toe#Rules>here are the rules </a>");
|
||||
this.info_container.appendChild(this.status_text);
|
||||
|
||||
this.info_container.style.display = "none";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bind_events()
|
||||
{
|
||||
// TODO
|
||||
this.game_manager.register_game_mode_change_listener((c) => this.game_mode_change_listener(c));
|
||||
this.game_manager.register_status_change_listener((c,t=null) => this.status_change_listener(c, t));
|
||||
|
||||
this.b_local.addEventListener("click", () => this.game_manager.start_local_game());
|
||||
this.b_end_game.addEventListener("click", () => this.game_manager.end_game(true));
|
||||
this.b_remote.addEventListener("click", () => this.game_manager.register_remote_game(this.get_player_name()));
|
||||
}
|
||||
|
||||
set_status(text)
|
||||
{
|
||||
this.status_text.innerHTML = text;
|
||||
}
|
||||
|
||||
get_player_name()
|
||||
{
|
||||
return this.i_player_name.value;
|
||||
}
|
||||
|
||||
activate_create_game()
|
||||
{
|
||||
this.create_game_container.style.display = "inline-block";
|
||||
}
|
||||
|
||||
activate_setting()
|
||||
{
|
||||
this.setting_container.style.display = "inline-block";
|
||||
}
|
||||
|
||||
activate_control()
|
||||
{
|
||||
this.control_container.style.display = "inline-block";
|
||||
}
|
||||
|
||||
activate_info()
|
||||
{
|
||||
this.info_container.style.display = "inline-block";
|
||||
}
|
||||
|
||||
deactivate_create_game()
|
||||
{
|
||||
this.create_game_container.style.display = "none";
|
||||
}
|
||||
|
||||
deactivate_setting()
|
||||
{
|
||||
this.setting_container.style.display = "none";
|
||||
}
|
||||
|
||||
deactivate_control()
|
||||
{
|
||||
this.control_container.style.display = "none";
|
||||
}
|
||||
|
||||
deactivate_info()
|
||||
{
|
||||
this.info_container.style.display = "none";
|
||||
}
|
||||
|
||||
game_mode_change_listener(gamemode)
|
||||
{
|
||||
if (gamemode == "none")
|
||||
{
|
||||
this.activate_create_game();
|
||||
this.activate_setting();
|
||||
this.deactivate_control();
|
||||
this.activate_info();
|
||||
return
|
||||
}
|
||||
if (gamemode == "local")
|
||||
{
|
||||
this.deactivate_create_game();
|
||||
this.deactivate_setting();
|
||||
this.activate_control();
|
||||
this.activate_info();
|
||||
}
|
||||
if (gamemode == "remote")
|
||||
{
|
||||
this.deactivate_create_game();
|
||||
this.deactivate_setting();
|
||||
this.activate_control();
|
||||
this.activate_info();
|
||||
}
|
||||
}
|
||||
|
||||
status_change_listener(statustext, title=null)
|
||||
{
|
||||
this.status_text.innerHTML = statustext;
|
||||
if (title != null)
|
||||
{
|
||||
this.status_title.innerHTML = "<p>" + title + "</p>";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
271
style.css
271
style.css
@ -4,7 +4,7 @@ html, body {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: rgb(30, 36, 119) ;
|
||||
background: rgb(49, 54, 74) ;
|
||||
outline: 0;
|
||||
position: relative;
|
||||
}
|
||||
@ -15,21 +15,36 @@ body {
|
||||
--tile-size: calc((100vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin));
|
||||
--opacity: 1;
|
||||
--border-radius: 1vh;
|
||||
--sidebar-width: 25vh;
|
||||
--ground-color: rgb(30, 36, 119) ;
|
||||
--sidebar-width: 26vh;
|
||||
--ground-color: rgb(41, 45, 62) ;
|
||||
--board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) );
|
||||
--sidebar-height: calc(var(--board-size) - 2 * var(--border-radius));
|
||||
}
|
||||
|
||||
/* override settings on portrait mode: */
|
||||
@media (orientation: portrait) {
|
||||
@media (max-aspect-ratio: 16/10) {
|
||||
|
||||
:root{
|
||||
--button-margin: 0.35vh;
|
||||
--tile-size: calc(((70vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)));
|
||||
--border-radius: 0.7vh;
|
||||
--sidebar-width: 18.2vh;
|
||||
--board-size: calc((var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin)));
|
||||
--sidebar-height: calc(var(--board-size) - 2 * var(--border-radius));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* override settings on portrait mode: */
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
:root{
|
||||
--button-margin: 0.5vw;
|
||||
--tile-size: calc((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin));
|
||||
--tile-size: calc(((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)));
|
||||
--border-radius: 1vw;
|
||||
--board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) );
|
||||
--sidebar-width: calc(var(--board-size) - 2 * var(--border-radius));
|
||||
--sidebar-height: 15vw;
|
||||
--sidebar-height: 25vw;
|
||||
}
|
||||
|
||||
}
|
||||
@ -51,11 +66,11 @@ a:visited {
|
||||
}
|
||||
|
||||
/* override settings on portrait mode: */
|
||||
@media (orientation: portrait) {
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.main-container {
|
||||
white-space: normal;
|
||||
padding-top: calc(50vh - 0.5 * var(--board-size));
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -114,11 +129,11 @@ a:visited {
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
.infobar-container {
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--border-radius);
|
||||
vertical-align: top;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
background: none;
|
||||
display: inline-flex;
|
||||
justify-content: space-between;
|
||||
flex-direction:column;
|
||||
@ -129,44 +144,17 @@ a:visited {
|
||||
}
|
||||
|
||||
/* override settings on portrait mode: */
|
||||
@media (orientation: portrait) {
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.sidebar-container {
|
||||
.infobar-container {
|
||||
flex-direction:row;
|
||||
padding: none;
|
||||
min-height: var(--sidebar-height);
|
||||
height: calc((100vh - var(--board-size)) * 0.5 - 2* var(--border-radius));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.create-game-container {
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--border-radius);
|
||||
top: 0;
|
||||
background: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.control-container {
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--border-radius);
|
||||
top: 0;
|
||||
background: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.setting-container {
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--border-radius);
|
||||
top: 0;
|
||||
background: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.info-container {
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--border-radius);
|
||||
@ -176,78 +164,183 @@ a:visited {
|
||||
text-align: center;
|
||||
background: none;
|
||||
white-space: normal;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.sidebar-label {
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.info-container{
|
||||
width: calc(0.3 * var(--sidebar-width));
|
||||
}
|
||||
}
|
||||
|
||||
.infobar-label {
|
||||
color: rgba(224, 217, 235, 0.8);
|
||||
font-size: calc(2 * var(--border-radius));
|
||||
width: calc(var(--sidebar-width) - 4 * var(--border-radius));
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
.sidebar-label
|
||||
{
|
||||
width: calc(var(--sidebar-width) * 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(3 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
width: calc(var(--sidebar-width) - 4 * var(--border-radius));
|
||||
vertical-align: middle;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
|
||||
.sidebar-button{
|
||||
width: calc(0.25 * var(--sidebar-width));
|
||||
height: calc(0.3 * var(--sidebar-height));
|
||||
}
|
||||
.option-button-container
|
||||
{
|
||||
border-radius: 0%;
|
||||
margin: 0%;
|
||||
top: 0%;
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
padding: none;
|
||||
}
|
||||
|
||||
|
||||
.sidebar-button:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.sidebar-button:active {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.sidebar-input {
|
||||
.infobar-button {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(126,87,194, 0.2) ;
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(3 * var(--border-radius));
|
||||
font-size: calc(2.8 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
width: calc(var(--sidebar-width) - 4 * var(--border-radius));
|
||||
vertical-align: middle;
|
||||
/* width: calc(var(--sidebar-width) - 4 * var(--border-radius)); */
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.sidebar-input{
|
||||
height: calc(0.3 * var(--sidebar-height));
|
||||
width: calc(0.25 * var(--sidebar-width));
|
||||
.infobar-button{
|
||||
height: calc(0.18 * var(--sidebar-height));
|
||||
}
|
||||
}
|
||||
|
||||
.infobar-button-green {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(0, 255, 0, 0.2);
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(2.8 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.infobar-button-green{
|
||||
height: calc(0.18 * var(--sidebar-height));
|
||||
}
|
||||
}
|
||||
|
||||
.infobar-button-red {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(255, 0, 0, 0.2);
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(2.8 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.infobar-button-red{
|
||||
height: calc(0.18 * var(--sidebar-height));
|
||||
}
|
||||
}
|
||||
|
||||
.infobar-button-active {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(126,87,194, 0.8) ;
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(2.8 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.infobar-button-active{
|
||||
height: calc(0.18 * var(--sidebar-height));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.infobar-button:hover {
|
||||
background: rgba(126,87,194, 0.5);
|
||||
}
|
||||
|
||||
.infobar-button:active {
|
||||
background: rgba(126,87,194, 0.8);
|
||||
}
|
||||
|
||||
.infobar-button:disabled {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
color: rgb(64,64,64);
|
||||
}
|
||||
|
||||
.infobar-input {
|
||||
border-radius: var(--border-radius);
|
||||
margin: var(--border-radius);
|
||||
border: none;
|
||||
outline: 0;
|
||||
transition-duration: 0.3s;
|
||||
background: rgba(126,87,194, 0.2);
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: calc(3 * var(--border-radius));
|
||||
height: calc(4 * var(--border-radius));
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.infobar-input::placeholder {
|
||||
color: rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
.infobar-input{
|
||||
height: calc(0.18 * var(--sidebar-height));
|
||||
}
|
||||
}
|
73
sw.js
73
sw.js
@ -1,37 +1,44 @@
|
||||
|
||||
self.addEventListener('install', function(e) {
|
||||
e.waitUntil(
|
||||
caches.open('your-magic-cache').then(function(cache) {
|
||||
return cache.addAll([
|
||||
'/website/ultimate_tictactoe/',
|
||||
'/website/ultimate_tictactoe/index.html',
|
||||
'/website/ultimate_tictactoe/manifest.json',
|
||||
'/website/ultimate_tictactoe/icon.png',
|
||||
'/website/ultimate_tictactoe/LICENSE',
|
||||
'/website/ultimate_tictactoe/main.js',
|
||||
'/website/ultimate_tictactoe/grid.js',
|
||||
'/website/ultimate_tictactoe/game_manager.js',
|
||||
'/website/ultimate_tictactoe/game_server_connection.js',
|
||||
'/website/ultimate_tictactoe/sidebar.js',
|
||||
'/website/ultimate_tictactoe/settings.js',
|
||||
'/website/ultimate_tictactoe/subgrid.js',
|
||||
'/website/ultimate_tictactoe/tile.js',
|
||||
'/website/ultimate_tictactoe/README.md',
|
||||
'/website/ultimate_tictactoe/site.js',
|
||||
'/website/ultimate_tictactoe/style.css',
|
||||
]);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(event) {
|
||||
event.respondWith(
|
||||
caches.match(event.request).then(function(response) {
|
||||
return response || fetch(event.request);
|
||||
})
|
||||
);
|
||||
var home = "https://the-cake-is-a-lie.net/website/ultimate_tictactoe/";
|
||||
var rel_home = "/website/ultimate_tictactoe";
|
||||
|
||||
self.addEventListener('install', function (e) {
|
||||
e.waitUntil(
|
||||
caches.open('your-magic-cache').then(function (cache) {
|
||||
return cache.addAll([
|
||||
'/website/ultimate_tictactoe/',
|
||||
'/website/ultimate_tictactoe/tools.js',
|
||||
'/website/ultimate_tictactoe/index.html',
|
||||
'/website/ultimate_tictactoe/manifest.json',
|
||||
'/website/ultimate_tictactoe/icon.png',
|
||||
'/website/ultimate_tictactoe/LICENSE',
|
||||
'/website/ultimate_tictactoe/main.js',
|
||||
'/website/ultimate_tictactoe/grid.js',
|
||||
'/website/ultimate_tictactoe/local_match_manager.js',
|
||||
'/website/ultimate_tictactoe/online_match_manager.js',
|
||||
'/website/ultimate_tictactoe/websocket_connection.js',
|
||||
'/website/ultimate_tictactoe/infobar.js',
|
||||
'/website/ultimate_tictactoe/infocontainer.js',
|
||||
'/website/ultimate_tictactoe/settings.js',
|
||||
'/website/ultimate_tictactoe/subgrid.js',
|
||||
'/website/ultimate_tictactoe/tile.js',
|
||||
'/website/ultimate_tictactoe/README.md',
|
||||
'/website/ultimate_tictactoe/site.js',
|
||||
'/website/ultimate_tictactoe/style.css',
|
||||
]);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function (event) {
|
||||
event.respondWith(
|
||||
caches.match(event.request).then(function (response) {
|
||||
return response || fetch(event.request);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', function (event) {
|
||||
console.log ("push message clicked");
|
||||
});
|
||||
event.notification.close();
|
||||
clients.openWindow(home);
|
||||
});
|
13
tools.js
Normal file
13
tools.js
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
function clear(node) {
|
||||
while (node.hasChildNodes()) {
|
||||
clear(node.firstChild);
|
||||
}
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
|
||||
function clearInner(node) {
|
||||
while (node.hasChildNodes()) {
|
||||
clear(node.firstChild);
|
||||
}
|
||||
}
|
519
websocket_connection.js
Normal file
519
websocket_connection.js
Normal file
@ -0,0 +1,519 @@
|
||||
class WebsocketConnection
|
||||
{
|
||||
constructor(ip, port, grid, status_label, matches_container, control_container, search_container, login_callback_func, error_callback_func)
|
||||
{
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.session_id = null;
|
||||
this.player = new Player("player", 128, 0,0);
|
||||
this.socket = null;
|
||||
this.registered = false;
|
||||
|
||||
this.grid = grid;
|
||||
this.status_label = status_label;
|
||||
this.matches_container = matches_container;
|
||||
this.control_container = control_container;
|
||||
this.search_container = search_container;
|
||||
|
||||
this.active_match = null;
|
||||
|
||||
this.connected = false;
|
||||
|
||||
this.current_end_button = null;
|
||||
|
||||
this.login_callback_func = login_callback_func;
|
||||
|
||||
this.openmatches = {};
|
||||
this.error_callback_func = error_callback_func;
|
||||
|
||||
this.closed_by_user = false;
|
||||
|
||||
|
||||
this.friends = [];
|
||||
|
||||
this.friend_name_divs = [];
|
||||
|
||||
matches_container.hide();
|
||||
|
||||
}
|
||||
|
||||
set_player(p)
|
||||
{
|
||||
this.player = p;
|
||||
}
|
||||
|
||||
set_game_manager(gm)
|
||||
{
|
||||
this.game_manager = gm;
|
||||
}
|
||||
|
||||
is_registered()
|
||||
{
|
||||
return this.registered;
|
||||
}
|
||||
|
||||
is_connected()
|
||||
{
|
||||
return this.connected;
|
||||
}
|
||||
|
||||
is_friend(friend)
|
||||
{
|
||||
return this.friends.includes(friend);
|
||||
}
|
||||
|
||||
on_open(username, pw)
|
||||
{
|
||||
|
||||
this.connected = true;
|
||||
this.login(username, pw)
|
||||
}
|
||||
|
||||
on_reopen(session_id)
|
||||
{
|
||||
|
||||
this.connected = true;
|
||||
this.relogin(session_id);
|
||||
}
|
||||
|
||||
on_close(login_failed=false)
|
||||
{
|
||||
for (var key in this.openmatches)
|
||||
{
|
||||
this.openmatches[key].remove_match();
|
||||
}
|
||||
this.openmatches = {};
|
||||
|
||||
// remove complete friend list:
|
||||
var n = this.friend_name_divs.length;
|
||||
|
||||
var i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
clearInner(this.friend_name_divs[i]);
|
||||
this.search_container.container.removeChild(this.friend_name_divs[i]);
|
||||
this.friend_name_divs[i] = null;
|
||||
}
|
||||
this.friend_name_divs = [];
|
||||
this.friends = [];
|
||||
|
||||
var login_failed = !this.registered;
|
||||
this.registered = false;
|
||||
this.connected = false;
|
||||
if (!this.closed_by_user && !login_failed)
|
||||
{
|
||||
this.status_label.innerHTML = "connection to server closed";
|
||||
this.error_callback_func();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
on_error()
|
||||
{
|
||||
for (var key in this.openmatches)
|
||||
{
|
||||
this.openmatches[key].remove_match();
|
||||
}
|
||||
this.openmatches = {};
|
||||
|
||||
// remove complete friend list:
|
||||
var n = this.friend_name_divs.length;
|
||||
|
||||
var i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
clearInner(this.friend_name_divs[i]);
|
||||
this.search_container.container.removeChild(this.friend_name_divs[i]);
|
||||
this.friend_name_divs[i] = null;
|
||||
}
|
||||
this.friend_name_divs = [];
|
||||
this.friends = [];
|
||||
|
||||
console.log("error in websocket connection");
|
||||
this.registered = false;
|
||||
this.connected = false;
|
||||
if (!this.closed_by_user)
|
||||
{
|
||||
this.status_label.innerHTML = "connection to server lost";
|
||||
this.error_callback_func();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
on_message(event)
|
||||
{
|
||||
var json_msg = event.data;
|
||||
var msg = JSON.parse(json_msg);
|
||||
|
||||
if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data"))
|
||||
{
|
||||
console.log("received wrong formatted message");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("raw_msg: " + json_msg);
|
||||
|
||||
switch(msg.type)
|
||||
{
|
||||
case "login_response":
|
||||
this.on_register_response(msg.data);
|
||||
break;
|
||||
|
||||
case "reconnect_response":
|
||||
this.on_reconnect_response(msg.data);
|
||||
break;
|
||||
|
||||
case "match_update":
|
||||
this.on_match_update(msg.data);
|
||||
break;
|
||||
|
||||
case "match_request_response":
|
||||
this.on_match_request_response(msg.data);
|
||||
break;
|
||||
|
||||
case "friend_request_response":
|
||||
this.on_friend_request_response(msg.data);
|
||||
break;
|
||||
|
||||
case "unfriend_request_response":
|
||||
this.on_unfriend_request_response(msg.data);
|
||||
break;
|
||||
|
||||
case "friends_update":
|
||||
this.on_friends_update(msg.data);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_active_match(id)
|
||||
{
|
||||
for (var key in this.openmatches)
|
||||
{
|
||||
if (key == id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
this.openmatches[key].on_focus_loose();
|
||||
}
|
||||
this.active_match = id;
|
||||
}
|
||||
|
||||
on_close_click()
|
||||
{
|
||||
if (this.active_match != null && (this.active_match in this.openmatches))
|
||||
{
|
||||
this.openmatches[this.active_match].on_user_close();
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (this.current_end_button != null)
|
||||
{
|
||||
this.control_container.container.deleteChild(this.current_end_button);
|
||||
this.current_end_button = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
on_match_update(data)
|
||||
{
|
||||
var id = data.id
|
||||
var match_state = data.match_state;
|
||||
|
||||
if (match_state == null)
|
||||
{
|
||||
// checking whether we can delete our dict object
|
||||
if (id in this.openmatches)
|
||||
{
|
||||
delete this.openmatches[id];
|
||||
if (this.active_match == id)
|
||||
{
|
||||
if (this.current_end_button != null)
|
||||
{
|
||||
this.control_container.container.deleteChild(this.current_end_button);
|
||||
this.current_end_button = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (id in this.openmatches)
|
||||
{
|
||||
this.openmatches[id].update_match_state(match_state)
|
||||
if (this.active_match == id)
|
||||
{
|
||||
this.openmatches[id].open_match();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!match_state.game_over)
|
||||
{
|
||||
this.openmatches[id] = new OnlineMatchManager(this.grid, this.status_label, this.matches_container, this.control_container, this, id, match_state, this.player.get_name());
|
||||
if (match_state.last_move == null)
|
||||
{
|
||||
this.notify("new Game against " + this.openmatches[id].online_opponent.get_name());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
on_register_response(data)
|
||||
{
|
||||
if (data.success)
|
||||
{
|
||||
this.registered = true;
|
||||
this.session_id = data.id;
|
||||
this.login_callback_func();
|
||||
}
|
||||
this.status_label.innerHTML = data.msg;
|
||||
|
||||
}
|
||||
|
||||
on_reconnect_response(data)
|
||||
{
|
||||
if (data.success)
|
||||
{
|
||||
this.registered = true;
|
||||
this.session_id = data.id;
|
||||
this.player.set_name(data.user);
|
||||
this.login_callback_func();
|
||||
}
|
||||
|
||||
this.status_label.innerHTML = data.msg;
|
||||
}
|
||||
|
||||
on_match_request_response(data)
|
||||
{
|
||||
if (data.success)
|
||||
{
|
||||
this.status_label.innerHTML = "match request sent";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.status_label.innerHTML = "could not send request: " + data.msg;
|
||||
}
|
||||
}
|
||||
|
||||
on_friend_request_response(data)
|
||||
{
|
||||
this.status_label.innerHTML = data.msg;
|
||||
}
|
||||
|
||||
on_unfriend_request_response(data)
|
||||
{
|
||||
this.status_label.innerHTML = data.msg;
|
||||
}
|
||||
|
||||
on_friends_update(data)
|
||||
{
|
||||
this.friends = data.friends;
|
||||
|
||||
// remove complete friend list:
|
||||
var n = this.friend_name_divs.length;
|
||||
|
||||
var i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
clearInner(this.friend_name_divs[i]);
|
||||
this.search_container.container.removeChild(this.friend_name_divs[i]);
|
||||
this.friend_name_divs[i] = null;
|
||||
}
|
||||
this.friend_name_divs = [];
|
||||
// rebuild friend list:
|
||||
n = this.friends.length;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
var tmp = this.search_container.create_double_button("" + this.friends[i], "-");
|
||||
|
||||
tmp[1].name = this.friends[i];
|
||||
tmp[2].name = this.friends[i];
|
||||
tmp[1].connection = this;
|
||||
tmp[2].connection = this;
|
||||
|
||||
|
||||
tmp[1].addEventListener("click", function() {
|
||||
this.connection.send_match_request(this.name);
|
||||
});
|
||||
|
||||
tmp[2].addEventListener("click", function (){
|
||||
this.connection.send_unfriend_request(this.name);
|
||||
});
|
||||
|
||||
this.friend_name_divs.push(tmp[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
connect(username, pw)
|
||||
{
|
||||
this.socket = new WebSocket(server_protocol + this.ip + ":" + this.port);
|
||||
this.socket.onmessage = (e => this.on_message(e));
|
||||
this.socket.onopen = (() => this.on_open(username, pw));
|
||||
this.socket.onerror = (() => this.on_error());
|
||||
this.socket.onclose = (() => this.on_close());
|
||||
}
|
||||
|
||||
reconnect(session_id)
|
||||
{
|
||||
for (var key in this.openmatches)
|
||||
{
|
||||
this.openmatches[key].remove_match();
|
||||
}
|
||||
this.openmatches = {};
|
||||
this.socket = new WebSocket(server_protocol + this.ip + ":" + this.port);
|
||||
this.socket.onmessage = (e => this.on_message(e));
|
||||
this.socket.onopen = (() => this.on_reopen(session_id));
|
||||
this.socket.onerror = (() => this.on_error());
|
||||
this.socket.onclose = (() => this.on_close());
|
||||
}
|
||||
|
||||
send_move(sub_x, sub_y, x, y, match_id)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "move",
|
||||
data: {
|
||||
id: match_id,
|
||||
sub_x: "" + sub_x,
|
||||
sub_y: "" + sub_y,
|
||||
x: "" + x,
|
||||
y: "" + y
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
send_end_match(match_id)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "end_match",
|
||||
data: {
|
||||
id: match_id,
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
|
||||
}
|
||||
|
||||
send_match_request(player_name)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "match_request",
|
||||
data: {
|
||||
player: player_name
|
||||
}
|
||||
};
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
send_friend_request(friend_name)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "friend_request",
|
||||
data: {
|
||||
user: friend_name
|
||||
}
|
||||
};
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
send_unfriend_request(friend_name)
|
||||
{
|
||||
var msg_object = {
|
||||
type: "unfriend_request",
|
||||
data: {
|
||||
user: friend_name
|
||||
}
|
||||
};
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
login(username, pw)
|
||||
{
|
||||
this.player.set_name(username);
|
||||
// register for game queue
|
||||
var msg_object = {
|
||||
type: "login",
|
||||
data: {
|
||||
name: this.player.get_name(),
|
||||
pw: pw
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
relogin(session_id)
|
||||
{
|
||||
for (var key in this.openmatches)
|
||||
{
|
||||
this.openmatches[key].remove_match();
|
||||
}
|
||||
// register for game queue
|
||||
var msg_object = {
|
||||
type: "reconnect",
|
||||
data: {
|
||||
id: session_id
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
send_disconnect()
|
||||
{
|
||||
if (!this.is_connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var msg_object = {
|
||||
type: "end_game",
|
||||
data: {
|
||||
msg: ""
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.send(JSON.stringify(msg_object));
|
||||
}
|
||||
|
||||
close()
|
||||
{
|
||||
this.status_label.innerHTML = "logged out";
|
||||
this.closed_by_user = true;
|
||||
this.socket.close();
|
||||
}
|
||||
|
||||
notify(text) {
|
||||
|
||||
if (document.hasFocus())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Notification.requestPermission(function(result) {
|
||||
if (result === 'granted') {
|
||||
navigator.serviceWorker.ready.then(function(registration) {
|
||||
registration.showNotification(text, {
|
||||
icon: './icon.png',
|
||||
vibrate: [200, 200],
|
||||
tag: "tictactoe-notification"
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user