You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
ygdc/assets/js/views/xoi.js.bak

499 lines
16 KiB

import { nextTick, reactive, ref, computed, onMounted, onUnmounted } from "vue";
import { state } from "../stateMgr.js";
import { getQuery } from "../kirby.js";
import { initSubState, ArrowVerticalKeyHandler, ArrowHorizontalKeyHandler, NumberKeyHandler } from "../handlers.js";
const html = (v) => { return v[0] };
function initView(view){
const back = state.view;
state.back.push(() => { state.view = back });
state.backActive.push(state.activeIndex);
state.view = view;
}
const togo = {
props: ['togo'],
setup(props) {
return { }
},
template: html`
<div class="bigToGo">{{ togo }}</div>
`
}
const game = {
props: ['players', 'currentleg', 'max', 'sendvisit', 'modelValue', 'overlay'],
setup(props, context) {
const length = computed(() => props.currentleg?.visits.length );
const visits = computed(() => props.currentleg? props.currentleg.visits:undefined );
const loop = computed(() => Math.max(length.value?length.value+(length.value?length.value%2:0):0,18) );
const getPlayerVisits = (uuid) => {
const vs = visits.value.filter((v) => v.player == uuid);
if (vs.length < 9) {
for (var i = vs.length; i < 9; i++) {
vs.push({ "sum": "", "toGo":["",""]})
}
} else if (vs.length*2 < visits.value.length) {
vs.push({ "sum": "", "toGo":["",""]});
}
return vs;
}
const check_remove = (event) => {
if (!event.repeat && event.target.value.length < 1) {
context.emit('removeLastVisit', event.target);
}
}
const setup = ref(false);
const setupEnter = () => {
setup.value = true;
}
const confirmEnter = (evt) => {
if (setup.value) {
context.emit('sendvisit', evt.target)
}
setup.value = false;
}
return { length, visits, loop, getPlayerVisits, check_remove, confirmEnter, setupEnter }
},
template: html`
<div class="game">
<div class="headding">
<div class="headding points player1">Points</div>
<div class="headding toGo player1">ToGo</div>
<div class="headding rounds">Round</div>
<div class="headding points player2">Points</div>
<div class="headding toGo player2">ToGo</div>
</div>
<div class="body">
<div class="points player1"></div>
<div class="toGo player1">{{ max }}</div>
<div class="rounds">0</div>
<div class="points player2"></div>
<div class="toGo player2">{{ max }}</div>
<template v-for="j in [1,2]" v-if="players">
<template v-for="visit, i in getPlayerVisits(players[j-1].uuid)">
<template v-if="visit.toGo === undefined">
<div :class="'points player'+j+' input'"><input v-autofocus :value="modelValue"
@input="$emit('update:modelValue', $event.target.value)" @keyup.enter="confirmEnter($event)" @keydown.enter="setupEnter($event)" @keydown.backspace="check_remove($event)" v-if="!overlay"></div>
<div :class="'toGo player'+j"></div>
</template>
<template v-if="visit.toGo !== undefined">
<div :class="'points player'+j">{{ visit.sum }}</div>
<div :class="'toGo player'+j">{{ visit.toGo[j-1] }}</div>
</template>
<div class="rounds" v-if="j == 1">{{ (i+1)*3 }}</div>
</template>
</template>
</div>
</div>
`
}
const overlay = {
props: ['data'],
setup(props, context) {
const keyhandler = (event) => {
ArrowHorizontalKeyHandler(event);
NumberKeyHandler(event);
if (event.key == "Escape") {
context.emit("closeOverlay")
}
}
return { keyhandler }
},
template: html`
<div @keyup="keyhandler" class="overlay" v-if="data !== undefined" :class="{active: data.title != '' && data.text != ''}">
<div class="box">
<h1>{{ data.title }}</h1>
<p>{{ data.text }}</p>
<div class="buttons">
<component v-for="(item, index) in data.buttons" :is="item.type" v-index="index+1" @click="item.onClick" :ref="(el) => { item.ref = el }" v-bind="item.props" v-autofocus="item.autofocus"></component>
</div>
</div>
</div>
`
}
const score = {
props: ['page', 'justlegs', 'currentset', 'currentleg'],
setup(props) {
return { }
},
template: html`
<div class="score">
<div v-if="!justlegs" class="sets">
<h2 v-for="(idx) in [0,1]">{{ currentset?.points[idx] }}</h2>
<div class="info">
<h3>Best of {{ page?.sets }}</h3>
<h2>Sets</h2>
</div>
</div>
<div class="legs">
<h2 v-for="(idx) in [0,1]">{{ currentleg?.points[idx] }}</h2>
<div class="info">
<h3>Best of {{ page?.legs }}</h3>
<h2>Legs</h2>
</div>
</div>
</div>
`
}
const player = {
props: ['player', 'stats', "id"],
setup(props) {
const current_set = computed( () => props.stats?.sets[props.stats.sets.length-1]);
const current_leg = computed( () => current_set.value?.legs[current_set.value.legs.length-1]);
const getAverage = (avg) => {
return avg && avg[1] != 0 ? ((3*avg[0])/avg[1]).toFixed(1) : "-";
}
const getCheckout = (checkout) => {
return checkout && checkout[1] != 0 ? Math.round(1000*checkout[0]/checkout[1])/10 : "- "
}
const getMax = (checkouts) => {
if (checkouts && checkouts.length != 0) {
return Math.max(...checkouts);
}
return "-"
}
return { current_set, current_leg, getAverage, getCheckout, getMax }
},
template: html`
<div class="player">
<img style="width: 100%" :src="player?.img? player.img : '/assets/img/placeholder_person.png'">
<h2 class="name">{{ player?.forename }} {{ player?.surname }}</h2>
<h3 class="nickname">{{ player?.nickname }}</h3>
<div class="stats">
<div class="row header">
<div>Stat</div><div>Match</div><div>Leg</div>
</div>
<div class="row">
<div>Average:</div><div>{{ getAverage(stats?.stats[id].average) }}</div><div>{{ getAverage(current_leg?.stats[id].average) }}</div>
</div>
<div class="row">
<div>First 9:</div><div>{{ getAverage(stats?.stats[id].first9) }}</div><div>{{ getAverage(current_leg?.stats[id].first9) }}</div>
</div>
<div class="row">
<div>60+:</div><div>{{ stats?.stats[id]["60+"] }}</div><div>{{ current_leg?.stats[id]["60+"] }}</div>
</div>
<div class="row">
<div>100+:</div><div>{{ stats?.stats[id]["100+"] }}</div><div>{{ current_leg?.stats[id]["100+"] }}</div>
</div>
<div class="row">
<div>140+:</div><div>{{ stats?.stats[id]["140+"] }}</div><div>{{ current_leg?.stats[id]["140+"] }}</div>
</div>
<div class="row">
<div>180:</div><div>{{ stats?.stats[id]["180"] }}</div><div>{{ current_leg?.stats[id]["180"] }}</div>
</div>
<div class="row">
<div>Checkouts:</div><div>{{ getCheckout(stats?.stats[id].checkouts) }}%</div><div></div>
</div>
<div class="row">
<div>Best Checkout:</div><div>{{ getMax(stats?.stats[id].checkoutPoints) }}</div><div></div>
</div>
</div>
</div>
`
}
export const xoi = {
components: {
"d-togo": togo,
"d-score": score,
"d-game": game,
"d-player": player,
"d-overlay": overlay
},
setup(props, context) {
let page = ref();
const updateGame = (reset) => {
getQuery(`site.find('${state.id}')`, {
select: {
title: "page.title",
id: "page.id",
modus: "page.max",
game: "page.rounds.parseJSON",
stats: "page.stats.parseJSON",
sets: "page.sets",
legs: "page.legs",
players: {
query: "page.players.toPages",
select:{
forename: "page.forename",
surname: "page.surname",
nickname: "page.nickname",
uuid: "page.uuid",
img: "page.pic.toFile?.url"
}
}
}
}).then((res) => {
page.value = res;
if (reset != undefined) {
current_input.value = reset;
}
if (res.stats.winner){
console.log(res.stats);
let winner = "Draw";
if (res.players[0].uuid == res.stats.winner){
winner = res.players[0].forename;
} else if (res.players[1].uuid == res.stats.winner) {
winner = res.players[1].forename;
}
overlay.value = {
"title": "Game Ended",
"text": `The winner is ${winner}`,
"buttons": []
};
}
});
};
updateGame();
let game = computed(() => page.value ? page.value.game: undefined)
let current_set = computed(() => {
if (game.value != undefined) {
return game.value.sets[game.value.sets.length-1]
}
return undefined;
})
let current_leg = computed(() => {
if (current_set.value != undefined) {
return current_set.value.legs[current_set.value.legs.length-1]
}
return undefined;
})
let current_toGo = computed(() => {
if (current_leg.value != undefined) {
if (current_leg.value.visits.length < 2) {
return [page.value.modus, page.value.modus]
} else {
return current_leg.value.visits[current_leg.value.visits.length-2].toGo;
}
}
return [0,0];
})
let current_set_points = computed(() => {
if (current_set.value != undefined) {
return current_set.value.points;
}
return undefined;
});
let current_leg_points = computed(() => {
if (current_leg.value != undefined) {
return current_leg.value.points;
}
return undefined;
});
let current_player = computed(() => {
if (current_leg.value != undefined) {
const len = current_leg.value.visits.length;
return current_leg.value.visits[len-1].player == page.value.players[1].uuid;
}
return undefined;
});
const current_input = ref("");
const overlay = ref();
return { page, state, game, current_set, current_leg, current_toGo, current_set_points, current_leg_points, current_player, updateGame, current_input, overlay }
},
methods: {
async removeLastVisit(){
let last = this.current_leg.visits.length-2 >= 0 ? this.current_leg.visits[this.current_leg.visits.length-2].throws : [""];
last = last.join(",");
const response = await fetch(`/${state.id}`, {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "deleteLastThrow",
"visit": true,
}),
});
const ret = await response.json();
if (ret.status == "ok"){
this.updateGame(last);
} else {
console.log(ret);
}
},
sum(tr){
const val = tr.trim();;
if (val == "") {
return 0;
}
if (val == "SB"){
return 25;
}
if (val == "DB"){
return 50;
}
if (val[0] == "S" || val[0] == "O" || val[0] == "I"){
return parseFloat(val.substring(1));
}
if (val[0] == "D"){
return 2*parseFloat(val.substring(1));
}
if (val[0] == "T"){
return 3*parseFloat(val.substring(1));
}
if (val[0] == "M"){
return 0;
} else {
// TODO: Check for Na
return parseFloat(val);
}
},
verify(sum){
if (this.current_toGo[this.current_player*1]-sum == 0){
return 0;
} else if (sum > 180 || [179, 178, 176, 175, 173, 172, 169, 166, 163].indexOf(sum) > -1) {
return -1
} else if (this.current_toGo[this.current_player*1]-sum <= 50) {
return 1
}
},
openOverlay(overlay){
this.overlay = overlay;
},
closeOverlay(){
this.overlay = undefined;
},
checkout_question(throws){
const buttons = [];
for (var i = 1; i <= 3; i++) {
const x = i;
buttons.push({
"type": "input",
"props" : {
"type": "button",
"value": `${x} (${x})`
},
"onClick": () => {
this.closeOverlay();
this.checkouttries_question(throws, x, false);
}
})
}
this.openOverlay({
"title": "Congratulations!",
"text": `How many darts did you need?` ,
"buttons": buttons
});
},
checkouttries_question(throws, numDarts, zero=true){
const buttons = [];
for (var i = 1; i <= numDarts; i++) {
const x = i;
buttons.push({
"type": "input",
"props" : {
"type": "button",
"value": `${x} (${x})`
},
"autofocus": (i==1 && !zero),
"onClick": () => {
this.closeOverlay();
this.send_visit(throws, numDarts, x)
}
})
}
if (zero) {
buttons.push({
"type": "input",
"props" : {
"type": "button",
"value": `0 (${numDarts+1})`
},
"autofocus": true,
"onClick": () => {
this.closeOverlay();
this.send_visit(throws, numDarts, 0)
}
})
}
this.openOverlay({
"title": "Checkout Tries",
"text": `How many tries on a Checkout?` ,
"buttons": buttons
});
},
async send_visit(throws, numDarts=3, checkoutTries=0){
const response = await fetch(`/${state.id}`, {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "addThrows",
"throws": throws.value.split(","),
"checkoutTries": checkoutTries,
"numDarts": numDarts,
"done": true
}),
});
const ret = await response.json();
if (ret.status == "ok"){
this.updateGame("");
} else {
console.log(ret);
}
},
async preprocess_visit(throws){
const tr = throws.value.split(",");
let sum = 0;
tr.forEach((t, i) => {
sum += this.sum(t);
});
const res = this.verify(sum);
if (res == 0){
// Ask for num Darts
this.checkout_question(throws);
return;
} else if (res == 1){
// Ask for checkoutTries
this.checkouttries_question(throws, 3);
return;
} else if (res == -1){
this.openOverlay({
"title": "Impossible",
"text": `A score of ${sum} is not possible`,
"buttons": [{
"type": "input",
"props" : {
"type": "button",
"value": "ok"
},
"onClick" : this.closeOverlay
}]
});
return;
}
this.send_visit(throws);
}
},
template: html`
<div class="xoi">
<d-overlay @closeOverlay="closeOverlay" :data="overlay"></d-overlay>
<d-togo :togo="current_toGo[0]" class="one" :class="{'active' : current_player==0 }"></d-togo>
<d-togo :togo="current_toGo[1]" class="two" :class="{'active' : current_player==1 }"></d-togo>
<d-score :page="page" :justlegs="page && page.sets == 1" :currentset="current_set" :currentleg="current_leg"></d-score>
<d-game :overlay="overlay!=undefined" :players="page?.players" :max="page?.modus" @sendvisit="preprocess_visit" @removeLastVisit="removeLastVisit" :currentleg="current_leg" v-model="current_input"></d-game>
<d-player class="player1" :player="page?.players[0]" :stats="page?.stats" :id="0"></d-player>
<d-player class="player2" :player="page?.players[1]" :stats="page?.stats" :id="1"></d-player>
<div class="navi"></div>
</div>
`
}
export const initXoiView = (app) => {
app.component('d-xoi', xoi)
}