add everything necessary to be able to calculate skills interactive.

added new route to main to handle skill field update
added new handler to work with htmx requests for skill calculation
made skill fields readonly
adapted templates for reloading of skills only
This commit is contained in:
Patryk Hegenberg 2023-12-12 20:56:55 +01:00
parent 7ed139ff97
commit 206b5bb506
6 changed files with 644 additions and 473 deletions

View file

@ -5,6 +5,7 @@ import (
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
"strings"
) )
// AddMonster is a http.HandlerFunc that adds a new monster to the Monsters slice. // AddMonster is a http.HandlerFunc that adds a new monster to the Monsters slice.
@ -67,7 +68,7 @@ func parseMonster(r *http.Request) model.Monster {
Name: r.FormValue("name"), Name: r.FormValue("name"),
Source: r.FormValue("source"), Source: r.FormValue("source"),
Size: []string{r.FormValue("size")}, Size: []string{r.FormValue("size")},
Type: r.FormValue("type"), Type: strings.ToLower(r.FormValue("type")),
Alignment: []string{r.FormValue("alignment")}, Alignment: []string{r.FormValue("alignment")},
AC: []model.AC{ AC: []model.AC{
{ {

View file

@ -31,6 +31,7 @@ func FormHandler(content embed.FS, monsters *[]model.Monster) http.HandlerFunc {
"templates/footer.html", "templates/footer.html",
"templates/monsterForm.html", "templates/monsterForm.html",
"templates/monster.html", "templates/monster.html",
"templates/skills.html",
"templates/monsterTable.html", "templates/monsterTable.html",
} }
tmpl, err := template.ParseFS(content, templateFiles...) tmpl, err := template.ParseFS(content, templateFiles...)

View file

@ -0,0 +1,142 @@
package handlers
import (
"embed"
"html/template"
"log"
"net/http"
"strconv"
)
// SkillCalculationHandler ist ein http.HandlerFunc, der von htmx getriggert wird,
// wenn der Benutzer Einträge in bestimmten Feldern macht, und dann die Skill-Felder befüllt.
func SkillCalculationHandler(content embed.FS) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Print("SkillCalculationHandler called")
// Überprüfen Sie, ob die Anfrage eine POST-Anfrage ist.
if r.Method != http.MethodPost {
log.Print("Method not allowed")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Parse Formulardaten.
err := r.ParseForm()
if err != nil {
log.Printf("Error parsing form data: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmplFiles := []string{"templates/base.html", "templates/header.html", "templates/skills.html", "templates/main.html", "templates/footer.html", "templates/about.html"}
tmpl, err := template.ParseFS(content, tmplFiles...)
if err != nil {
log.Printf("Template parsing error: %v\n", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
str := parseFieldValue(r.FormValue("str"))
dex := parseFieldValue(r.FormValue("dex"))
int := parseFieldValue(r.FormValue("int"))
cha := parseFieldValue(r.FormValue("cha"))
wis := parseFieldValue(r.FormValue("wis"))
cr := parseFieldValue(r.FormValue("cr"))
crBonus := calcBonus(cr)
skillValues := map[string]string{
"acrobatics": strconv.Itoa(calcAbilityScore(dex) + crBonus),
"animalHandling": strconv.Itoa(calcAbilityScore(wis) + crBonus),
"arcana": strconv.Itoa(calcAbilityScore(int) + crBonus),
"athletics": strconv.Itoa(calcAbilityScore(str) + crBonus),
"deception": strconv.Itoa(calcAbilityScore(cha) + crBonus),
"history": strconv.Itoa(calcAbilityScore(int) + crBonus),
"insight": strconv.Itoa(calcAbilityScore(wis) + crBonus),
"intimidation": strconv.Itoa(calcAbilityScore(cha) + crBonus),
"investigation": strconv.Itoa(calcAbilityScore(int) + crBonus),
"medicine": strconv.Itoa(calcAbilityScore(wis) + crBonus),
"nature": strconv.Itoa(calcAbilityScore(int) + crBonus),
"perception": strconv.Itoa(calcAbilityScore(wis) + crBonus),
"performance": strconv.Itoa(calcAbilityScore(cha) + crBonus),
"persuasion": strconv.Itoa(calcAbilityScore(cha) + crBonus),
"religion": strconv.Itoa(calcAbilityScore(int) + crBonus),
"sleightOfHand": strconv.Itoa(calcAbilityScore(dex) + crBonus),
"stealth": strconv.Itoa(calcAbilityScore(dex) + crBonus),
"survival": strconv.Itoa(calcAbilityScore(wis) + crBonus),
}
err = tmpl.ExecuteTemplate(w, "skills", skillValues)
if err != nil {
log.Printf("Template execution error: %v\n", err)
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
}
func calcBonus(cr int) int {
if cr >= 0 && cr < 5 {
return 2
} else if cr >= 5 && cr < 9 {
return 3
} else if cr >= 9 && cr < 14 {
return 4
} else if cr >= 14 && cr < 18 {
return 5
} else if cr >= 18 && cr < 21 {
return 6
} else if cr >= 21 && cr < 25 {
return 7
} else if cr >= 25 && cr < 28 {
return 8
} else if cr >= 28 && cr < 31 {
return 9
} else {
return 0
}
}
func calcAbilityScore(val int) int {
if val < 2 {
return -5
} else if val >= 2 && val < 4 {
return -4
} else if val >= 4 && val < 6 {
return -3
} else if val >= 6 && val < 8 {
return -2
} else if val >= 8 && val < 10 {
return -1
} else if val >= 10 && val < 12 {
return 0
} else if val >= 12 && val < 14 {
return 1
} else if val >= 14 && val < 16 {
return 2
} else if val >= 16 && val < 18 {
return 3
} else if val >= 18 && val < 20 {
return 4
} else if val >= 20 && val < 22 {
return 5
} else if val >= 22 && val < 24 {
return 6
} else if val >= 24 && val < 26 {
return 7
} else if val >= 26 && val < 28 {
return 8
} else if val >= 28 && val < 30 {
return 9
} else {
return 10
}
}
func parseFieldValue(value string) int {
val, err := strconv.Atoi(value)
if err != nil {
log.Printf("Error converting field value to integer: %v", err)
return 0
}
return val
}

View file

@ -36,6 +36,7 @@ func main() {
routes.HandleFunc("/about", handlers.AboutHandler(content)) routes.HandleFunc("/about", handlers.AboutHandler(content))
routes.HandleFunc("/contact", handlers.ContactHandler(content)) routes.HandleFunc("/contact", handlers.ContactHandler(content))
routes.HandleFunc("/monsterTable", handlers.MonsterTableHandler(content, &Monsters)) routes.HandleFunc("/monsterTable", handlers.MonsterTableHandler(content, &Monsters))
routes.HandleFunc("/calculate-skills", handlers.SkillCalculationHandler(content))
// Print the message indicating that 'static' has been included. // Print the message indicating that 'static' has been included.
log.Printf("Eingebunden is %v\n", static) log.Printf("Eingebunden is %v\n", static)

View file

@ -4,8 +4,7 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="name">Monster Name:</label> <label for="name">Monster Name:</label>
<div class="control"> <div class="control">
<input type="text" name="name" required placeholder="Type here" <input type="text" name="name" required placeholder="Type here" class="input input-bordered w-full max-w-xs">
class="input input-bordered w-full max-w-xs">
</div> </div>
</div> </div>
</div> </div>
@ -107,7 +106,7 @@
</div> </div>
<div class="tile is-parent"> <div class="tile is-parent">
<div class="tile is-child field"> <div class="tile is-child field">
<label for="burrow">burrow:</label> <label for="burrow">Burrow:</label>
<div class="control"> <div class="control">
<input type="number" name="burrow" required class="input input-bordered w-full max-w-xs"> <input type="number" name="burrow" required class="input input-bordered w-full max-w-xs">
</div> </div>
@ -148,7 +147,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="str">Str:</label> <label for="str">Str:</label>
<div class="control"> <div class="control">
<input type="number" name="str" required class="input input-bordered w-full max-w-xs"> <input type="number" name="str" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -156,7 +156,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="dex">Dex:</label> <label for="dex">Dex:</label>
<div class="control"> <div class="control">
<input type="number" name="dex" required class="input input-bordered w-full max-w-xs"> <input type="number" name="dex" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -164,7 +165,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="con">Con:</label> <label for="con">Con:</label>
<div class="control"> <div class="control">
<input type="number" name="con" required class="input input-bordered w-full max-w-xs"> <input type="number" name="con" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -172,7 +174,9 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="cr">CR:</label> <label for="cr">CR:</label>
<div class="control"> <div class="control">
<input type="text" name="cr" required class="input input-bordered w-full max-w-xs"> <input type="text" name="cr" required class="input input-bordered w-full max-w-xs" hx-post="/calculate-skills"
hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML" hx-target="#skills"
hx-swap="outerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -182,7 +186,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="int">Int:</label> <label for="int">Int:</label>
<div class="control"> <div class="control">
<input type="number" name="int" required class="input input-bordered w-full max-w-xs"> <input type="number" name="int" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -190,7 +195,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="wis">Wis:</label> <label for="wis">Wis:</label>
<div class="control"> <div class="control">
<input type="number" name="wis" required class="input input-bordered w-full max-w-xs"> <input type="number" name="wis" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -198,7 +204,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="cha">Cha:</label> <label for="cha">Cha:</label>
<div class="control"> <div class="control">
<input type="number" name="cha" required class="input input-bordered w-full max-w-xs"> <input type="number" name="cha" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -206,7 +213,8 @@
<div class="tile is-child field"> <div class="tile is-child field">
<label for="passive">Passive:</label> <label for="passive">Passive:</label>
<div class="control"> <div class="control">
<input type="number" name="passive" required class="input input-bordered w-full max-w-xs"> <input type="number" name="passive" required class="input input-bordered w-full max-w-xs"
hx-post="/calculate-skills" hx-trigger="keyup changed delay:100ms" hx-target="#skills" hx-swap="innerHTML">
</div> </div>
</div> </div>
</div> </div>
@ -274,175 +282,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card tile is-ancestor is-vertical"> <div id="skills" class="card tile is-ancestor is-vertical">
<header class="card-header"> {{ template "skills" }}
<p class="card-header-title">
Skill
</p>
</header>
<div class="card-content">
<div class="content">
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="acrobatics">Acrobatics:</label>
<div class="control">
<input type="text" name="acrobatics" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="animalHandling">Animal Handling:</label>
<div class="control">
<input type="text" name="animalHandling" required
class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="arcana">Arcana:</label>
<div class="control">
<input type="text" name="arcana" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="athletics">Athletics:</label>
<div class="control">
<input type="text" name="athletics" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="deception">Deception:</label>
<div class="control">
<input type="text" name="deception" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="history">History:</label>
<div class="control">
<input type="text" name="history" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="insight">Insight:</label>
<div class="control">
<input type="text" name="insight" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="intimidation">Intimidation:</label>
<div class="control">
<input type="text" name="intimidation" required
class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="investigation">Investigation:</label>
<div class="control">
<input type="text" name="investigation" required
class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="medicine">Medicine:</label>
<div class="control">
<input type="text" name="medicine" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="nature">Nature:</label>
<div class="control">
<input type="text" name="nature" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="performance">Performance:</label>
<div class="control">
<input type="text" name="performance" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="perception">Perception:</label>
<div class="control">
<input type="text" name="perception" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="stealth">Stealth:</label>
<div class="control">
<input type="text" name="stealth" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="persuasion">Persuasion:</label>
<div class="control">
<input type="text" name="persuasion" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="sleightOfHand">Sleight of Hand:</label>
<div class="control">
<input type="text" name="sleightOfHand" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="religion">Religion:</label>
<div class="control">
<input type="text" name="religion" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="survival">Survival:</label>
<div class="control">
<input type="text" name="survival" required class="input input-bordered w-full max-w-xs">
</div>
</div>
</div>
</div>
</div>
</div>
</div> </div>
<div class="tile is-ancestor"> <div class="tile is-ancestor">
<div class="tile is-parent"> <div class="tile is-parent">

185
templates/skills.html Normal file
View file

@ -0,0 +1,185 @@
{{ define "skills" }}
<header class="card-header">
<p class="card-header-title">
Skill
</p>
</header>
<div class="card-content">
<div class="content">
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="acrobatics">Acrobatics:</label>
<div class="control">
<input type="text" name="acrobatics" required class="input input-bordered w-full max-w-xs" value="{{
.acrobatics }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="animalHandling">Animal Handling:</label>
<div class="control">
<input type="text" name="animalHandling" required class="input input-bordered w-full max-w-xs"
value="{{ .animalHandling }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="arcana">Arcana:</label>
<div class="control">
<input type="text" name="arcana" required class="input input-bordered w-full max-w-xs" value="{{ .arcana }}"
readonly>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="athletics">Athletics:</label>
<div class="control">
<input type="text" name="athletics" required class="input input-bordered w-full max-w-xs"
value="{{ .athletics }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="deception">Deception:</label>
<div class="control">
<input type="text" name="deception" required class="input input-bordered w-full max-w-xs"
value="{{ .deception }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="history">History:</label>
<div class="control">
<input type="text" name="history" required class="input input-bordered w-full max-w-xs"
value="{{ .history }}" readonly>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="insight">Insight:</label>
<div class="control">
<input type="text" name="insight" required class="input input-bordered w-full max-w-xs"
value="{{ .insight }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="intimidation">Intimidation:</label>
<div class="control">
<input type="text" name="intimidation" required class="input input-bordered w-full max-w-xs"
value="{{ .intimidation }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="investigation">Investigation:</label>
<div class="control">
<input type="text" name="investigation" required class="input input-bordered w-full max-w-xs"
value="{{ .investigation }}" readonly>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="medicine">Medicine:</label>
<div class="control">
<input type="text" name="medicine" required class="input input-bordered w-full max-w-xs"
value="{{ .medicine }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="nature">Nature:</label>
<div class="control">
<input type="text" name="nature" required class="input input-bordered w-full max-w-xs" value="{{ .nature }}"
readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="performance">Performance:</label>
<div class="control">
<input type="text" name="performance" required class="input input-bordered w-full max-w-xs"
value="{{ .performance }}" readonly>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="perception">Perception:</label>
<div class="control">
<input type="text" name="perception" required class="input input-bordered w-full max-w-xs"
value="{{ .perception }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="stealth">Stealth:</label>
<div class="control">
<input type="text" name="stealth" required class="input input-bordered w-full max-w-xs"
value="{{ .stealth }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="persuasion">Persuasion:</label>
<div class="control">
<input type="text" name="persuasion" required class="input input-bordered w-full max-w-xs"
value="{{ .persuasion }}" readonly>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child field">
<label for="sleightOfHand">Sleight of Hand:</label>
<div class="control">
<input type="text" name="sleightOfHand" required class="input input-bordered w-full max-w-xs"
value="{{.sleightOfHand }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="religion">Religion:</label>
<div class="control">
<input type="text" name="religion" required class="input input-bordered w-full max-w-xs"
value="{{ .religion }}" readonly>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child field">
<label for="survival">Survival:</label>
<div class="control">
<input type="text" name="survival" required class="input input-bordered w-full max-w-xs"
value="{{ .survival }}" readonly>
</div>
</div>
</div>
</div>
</div>
</div>
{{ end }}