Browse Source

Changes via Javascript work.

feature/js
Daniel Perelman 2 years ago
parent
commit
28ab47e5e4
3 changed files with 157 additions and 24 deletions
  1. +121
    -16
      fear_tracker/templates/game.html
  2. +1
    -0
      fear_tracker/urls.py
  3. +35
    -8
      fear_tracker/views.py

+ 121
- 16
fear_tracker/templates/game.html View File

@@ -150,6 +150,9 @@
clone.querySelector("." + suffix).name = prefix + suffix;
clone.querySelector("." + suffix + "-orig").name = prefix + suffix + "-orig";
});
for(let el of clone.querySelectorAll('select')) {
el.addEventListener("change", formElementChanged);
}
effDiv.appendChild(clone);
}
function addEmptyEffects(clearAll) {
@@ -188,7 +191,6 @@
if(oldStatus.hash == newStatus.hash) return true;
if(oldStatus.phase_id != newStatus.phase_id
|| oldStatus.turn != newStatus.turn) {
// Reload for new phase.
addEmptyEffects(true);
}

@@ -214,6 +216,10 @@
}
document.getElementById(prefix + "ready-orig").value = ready;
document.getElementById(prefix + "ready").checked = ready;

for(let el of document.querySelectorAll(".player-" + ord + " select")) {
el.disabled = ready;
}
} else if(pkey == "total_fear") {
let total_fear = player[pkey];
for(let el of document.getElementsByClassName(prefix + "total-fear")) {
@@ -260,25 +266,124 @@
return true;
{% endblock %}
}
setInterval(function() {
fetch(new Request("{% url 'status' access_code=access_code %}"
+ statusObj.hash + "/"))
.then(response => {
if(response.status === 304) {
// TODO Just skip the next step?
return statusObj;
var activeRequests = new Set();
function formElementChanged(e) {
let form = document.forms[0];
let el = e.target;
let name = el.name;
let origName = name + "-orig";
let origEl = form.elements[origName];

let newValue = el.type == "checkbox" ? el.checked : el.value;
let oldValue = origEl.value;

el.disabled = true;
if(el.name.endsWith("ready") && newValue) {
let ord = name.split("-")[1];
// If marking a player ready, disable all selects immediately.
for(let el of document.querySelectorAll(".player-" + ord + " select")) {
el.disabled = true;
}
}

activeRequests.add(el);
statusObj.hash = '';

// From https://stackoverflow.com/a/5588435
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i];
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}

fetch("{% url 'update_game' access_code=access_code %}",
{
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-CSRFToken": getCookie("csrftoken"),
},
body: name + "=" + newValue + "&" + origName + "=" + oldValue
+ "&game_turn=" + statusObj["turn"]
+ "&game_phase=" + statusObj["phase_id"]
+ "&phase_name=" + statusObj["phase"]
+ "&csrfmiddlewaretoken=" + form.elements["csrfmiddlewaretoken"].value,
}).then(response => response.json()
).then(data => {
if("success" in data && data["success"]) {
form.elements[origName].value = newValue;
} else {
var updatedValue = oldValue;
if("value" in data) {
let updatedValue = data['value'];
origEl.value = updatedValue;
}
if(el.type == "checkbox") {
el.checked = updatedValue == "true";
} else {
return response.json();
el.value = updatedValue;
}
})
.then(data => {
if(!handleNewStatus(statusObj, data)) {
document.getElementById("button-refresh").click();

if("errors" in data) {
alert(data["errors"]);
} else {
statusObj = data;
alert("Unknown error: " + data);
}
});
}, 5000);
}
el.disabled = false;
activeRequests.delete(el);
});
}
window.addEventListener("DOMContentLoaded", e => {
for(let updateButton of document.getElementsByClassName("update-button")) {
updateButton.disabled = true;
updateButton.style.display = "none";
}
let form = document.forms[0];
for(let el of form.elements) {
if(el.type == 'checkbox' && !el.name.endsWith("visible")) {
el.addEventListener("change", formElementChanged);
}
}
for(let el of document.querySelectorAll('select')) {
el.addEventListener("change", formElementChanged);
}

setInterval(function() {
if(activeRequests.size != 0) return;
fetch(new Request("{% url 'status' access_code=access_code %}"
+ (statusObj.hash != ""
? statusObj.hash + "/"
: "")))
.then(response => {
if(response.status === 304) {
// TODO Just skip the next step?
return statusObj;
} else {
return response.json();
}
})
.then(data => {
if(activeRequests.size != 0) return;
if(!handleNewStatus(statusObj, data)) {
document.getElementById("button-refresh").click();
} else {
statusObj = data;
}
});
}, 5000);
});
</script>
{% endif %}
{% endblock %}

+ 1
- 0
fear_tracker/urls.py View File

@@ -24,6 +24,7 @@ urlpatterns = [
path('new/', views.new_game, name='new_game'),
url(r'^(?P<access_code>[a-zA-Z]{6})/', include([
path('', views.game, name='game'),
path('update/', views.update_game, name='update_game'),
path('qr/', views.qr_code, name='qr_code'),
path('status/', views.status, name='status'),
url('^status/(?P<hashcode>[a-z0-9]{64})/',


+ 35
- 8
fear_tracker/views.py View File

@@ -8,7 +8,8 @@ import qrcode
from django.db import transaction
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.views.decorators.http import require_safe, require_http_methods
from django.views.decorators.http import require_safe, require_http_methods,\
require_POST
from django.urls import reverse

from .forms import NewGameForm, JoinGameForm, PlayerFormSet
@@ -153,10 +154,21 @@ def game_status_object(game, current_phase=None, players_with_fear=None):
return status_obj


@transaction.atomic
@lookup_access_code
@require_POST
def update_game(request, game):
return handle_game_request(request, game, update=True)


@transaction.atomic
@lookup_access_code
@require_http_methods(["HEAD", "GET", "POST"])
def game(request, game):
return handle_game_request(request, game, update=False)


def handle_game_request(request, game, update):
# TODO Should check if game is over and redirect to summary table view.

players = load_players(game)
@@ -169,14 +181,17 @@ def game(request, game):
'towns': 'towns_destroyed',
'cities': 'cities_destroyed',
}
current_value = None
current_phase = game.get_current_phase()
if request.method == 'POST':
post_data = request.POST

correct_phase =\
current_phase.game_turn == int(request.POST['game_turn'])\
and current_phase.game_phase == int(request.POST['game_phase'])
advance_phase = 'advance' in request.POST
revert_phase = 'revert' in request.POST
for key, value in request.POST.items():
current_phase.game_turn == int(post_data['game_turn'])\
and current_phase.game_phase == int(post_data['game_phase'])
advance_phase = 'advance' in post_data
revert_phase = 'revert' in post_data
for key, value in post_data.items():
sections = key.split('-')
if key in ['csrfmiddlewaretoken',
'update', 'advance', 'revert',
@@ -184,7 +199,7 @@ def game(request, game):
or sections[-1] == 'orig':
pass
elif sections[0] == 'player':
orig_value = request.POST.get(key + '-orig', None)
orig_value = post_data.get(key + '-orig', None)
player_ord = int(sections[1])
player = players[player_ord]
if sections[2] == 'visible':
@@ -214,7 +229,7 @@ def game(request, game):
f"from {orig} to {amount} " +
"was not processed.")
elif not correct_phase or advance_phase:
old_phase = request.POST['phase_name']
old_phase = post_data['phase_name']
errors.append(
f"{player.name} " +
f"({player.get_spirit_name()})'s " +
@@ -261,6 +276,18 @@ def game(request, game):
for player in players.values():
player.ready = True

if update:
if errors:
res = {
'success': False,
'errors': '\n'.join(errors)
}
if current_value is not None:
res['value'] = current_value
else:
res = {'success': True}
return HttpResponse(json.dumps(res))

players = get_players_with_fear(game, current_phase, players)
status_obj = game_status_object(game, current_phase, players)
status_string = json.dumps(status_obj)


Loading…
Cancel
Save