Compare commits
No commits in common. "main" and "0.9.5" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,3 @@ hint-report/
|
||||
.csslintrc
|
||||
coverage/
|
||||
tmp/
|
||||
*.geany
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
# sr2ini – a simple initiative tracker for Shadowrun 2e
|
||||
# sr2ini
|
||||
|
||||
sr2ini is a lightweight, single-page initiative tracker for the TTRPG Shadowrun in its 2nd edition. The app helps DMs and players to manage fights by tracking each combatant's initiative, order of action, damage (stun and physical), and wound modifiers. It was written specifically for mobile use and can be installed as a web app.
|
||||
Simple Initiative tracker for Shadowrun 2e.
|
||||
66
TODO.md
66
TODO.md
@ -118,16 +118,22 @@
|
||||
- x color scheme beim Favicon anpassen
|
||||
- https://realfavicongenerator.net/
|
||||
- see also here: https://github.com/audreyfeldroy/favicon-cheat-sheet
|
||||
|
||||
- x Mauszeiger soll Finger werden, wenn er über combatant-name/ini/dice-and-rea hovert
|
||||
- x actions-menu erscheint nicht direkt unter dem Button
|
||||
- beide dropdowns sind gerade garbled
|
||||
- x im FP3T Tor Browser kann ich rauszoomen, bis ich die ganzen damage monitors und action menus sehe -> verhindern!
|
||||
- action-menu und damage-monitor sliden jetzt nicht mehr rein, sondern bleiben an Ort und Stelle
|
||||
- das sollte die Sache verhindern
|
||||
- x warum fkt. das Ganze nicht als Webapp?
|
||||
- Firefox (android) sieht die Seite nicht als installable an
|
||||
- Webmanifest ist aber da und scheint auch in Ordnung zu sein (sagt Firefox on Linux)
|
||||
- x favicon checken: https://realfavicongenerator.net/favicon_checker
|
||||
|
||||
|
||||
### open
|
||||
|
||||
- unter die GPL stellen
|
||||
- https://www.gnu.org/licenses/gpl-howto.html
|
||||
|
||||
- sr2ini_ynh auf neue Version bringen
|
||||
- manifest: Version, tarball URL und sha256 ersetzen
|
||||
- README.md: Version ersetzen
|
||||
- ggf. doc/screenshots/sr2ini-screenshot.jpg ersetzen (960x640)
|
||||
- favicon checken: https://realfavicongenerator.net/favicon_checker
|
||||
- jetzt fkt. immer noch nicht die URLs im Icon manifest
|
||||
- x Links zu den versch. favicons fkt. nicht: sie lauten /… statt /sr2ini/…
|
||||
- x Lösung: parcel build braucht als --public-url "./" (statt "/"), dann werden die Links korrekt erzeugt
|
||||
@ -142,40 +148,26 @@
|
||||
- CORS-Fehler im Firefox vermeiden: about:config -> content.cors.disable = true
|
||||
- letztes Problem (hoffentlich): die Links zu den android-chrome-XYZxXYZ Icons im site.webmanifest stimmen nicht
|
||||
- hab site.manifest nach src/ verschoben und die Links angepasst -> jetzt scheint's zu gehen
|
||||
- x focus-related stuff
|
||||
- x enter key doesn't work right away after clicking add button
|
||||
- x wenn ein damage monitor offen ist und ich auf add combatant clicke, springt der Fokus nicht zuverlässig ins erste input feld
|
||||
- x after pressing damage level button, focus moves to first table row act button
|
||||
- it's probably b/c I resort the table
|
||||
- x Geheimfunktion, um Eclipse, Solitaire, Pi und Q zu adden: hold navbar title
|
||||
- x refactor (in neuem Branch):
|
||||
- jede combatant tablerow kriegt eine unique #id
|
||||
- Funktionen holen sich ihre Infos Infos nicht mehr aus dem DOM, sondern kriegen sie als Parameter übergeben
|
||||
- tablerow id
|
||||
- table
|
||||
- modal
|
||||
- …
|
||||
|
||||
|
||||
### open
|
||||
|
||||
- focus trapping im modal fkt. nur rückwärts (shift-tab), aber nicht vorwärts
|
||||
- wenn ich in einem modal mit Tab durchgehe und zu den Buttons ganz unten komme, bewegt sich der untere Rand des Modals ab und auf
|
||||
- comments with general info in source files?
|
||||
- unter die GPL stellen
|
||||
- https://www.gnu.org/licenses/gpl-howto.html
|
||||
|
||||
- sr2ini_ynh auf neue Version bringen
|
||||
- manifest: Version, tarball URL und sha256 ersetzen
|
||||
- README.md: Version ersetzen
|
||||
- ggf. doc/screenshots/sr2ini-screenshot.jpg ersetzen (960x640)
|
||||
|
||||
- Deployment:
|
||||
- CI/CD: es gibt Jenkins für Yunohost
|
||||
- hier ist ein Tutorial, um Jenkins und Gitea miteinander bekannt zu machen: https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins
|
||||
- Jenkins Doc: https://www.jenkins.io/doc/book/using/best-practices/
|
||||
- ist aber wohl mit Kanonen auf Spatzen
|
||||
- use minified libraries (aug-ui, bs, jq)
|
||||
- focus-related stuff
|
||||
- enter key doesn't work right away after clicking add button
|
||||
- after pressing damage button, focus moves to first table row act button
|
||||
- it's probably b/c I resort the table
|
||||
- wenn ein damage monitor offen ist und ich auf add combatant clicke, springt der Fokus nicht zuverlässig ins erste input feld
|
||||
- focus trapping im modal fkt. nur rückwärts (shift-tab), aber nicht vorwärts
|
||||
- zumindest im Chrome; FF ungetestet
|
||||
- im FP3T Tor Browser kann ich rauszoomen, bis ich die ganzen damage monitors und action menus sehe -> verhindern!
|
||||
- action-menu und damage-monitor sliden jetzt nicht mehr rein, sondern bleiben an Ort und Stelle
|
||||
- das sollte die Sache verhindern
|
||||
- warum fkt. das Ganze nicht als Webapp?
|
||||
- Firefox (android) sieht die Seite nicht als installable an
|
||||
- Webmanifest ist aber da und scheint auch in Ordnung zu sein (sagt Firefox on Linux)
|
||||
- comments with general info in source files?
|
||||
|
||||
|
||||
## Feature Requests
|
||||
@ -186,6 +178,8 @@
|
||||
- sr2ini.js: test combatant
|
||||
- git: user.name, user.email
|
||||
- git commits, ggf. tags
|
||||
- Seite als Web App auf FF4And installable machen
|
||||
- mal sehen …
|
||||
- Animationen? Transitions?
|
||||
- deployment: dist/* soll direkt auf hermes hochgeladen werden
|
||||
- HTML soll nicht in eine Zeile umgedingst werden, das sieht doch nicht aus
|
||||
@ -196,6 +190,7 @@
|
||||
- falls ja: .htmlnanorc anlegen, s. https://parceljs.org/languages/html/#minification und https://htmlnano.netlify.app/modules#collapsewhitespace
|
||||
- nicetohave: Wenn ich rea editiere, könnte sich die ini automatisch anpassen -> da müsste ich aber die Würfelergebnisse für speichern
|
||||
- nicetohave: Anzeige, wieviele Aktionen einer hat u.d wieviele davon schon verbraucht sind
|
||||
- Sache mit dem ServiceWorker mal richtig angehen
|
||||
|
||||
- x progressive web app
|
||||
- x Service Worker einrichten, um die Dateien lokal zu cachen
|
||||
@ -236,3 +231,4 @@
|
||||
- x dafür sorgen, dass die Seite erst dann aufgebaut wird, wenn die CSS-Files geladen sind, damit man nicht den ungestylten Krams sieht -> passt schon
|
||||
- x CSS aufräumen
|
||||
- Variablen für Farben, Filter etc.
|
||||
|
||||
|
||||
11
package.json
11
package.json
@ -4,9 +4,9 @@
|
||||
"description": "Simple Initiative tracker for Shadowrun 2e",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Eclipse",
|
||||
"name": "Eclipse729",
|
||||
"email": "eclipse@unterdemradar.de",
|
||||
"url": "https://git.unterdemradar.de/eclipse"
|
||||
"url": "https://git.unterdemradar.de"
|
||||
},
|
||||
"homepage": "https://unterdemradar.de/sr2ini/",
|
||||
"license": "ISC",
|
||||
@ -32,7 +32,7 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@git.unterdemradar.de:eclipse/sr2ini.git"
|
||||
"url": "git@git.unterdemradar.de:tobias/sr2ini.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Shadowrun",
|
||||
@ -52,5 +52,10 @@
|
||||
"augmented-ui": "^2.0.0",
|
||||
"bootstrap": "^5.2.3",
|
||||
"jquery": "^3.6.3"
|
||||
},
|
||||
"comments": {
|
||||
"dependencies": {
|
||||
"@parcel/service-worker": "^2.8.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,8 +260,6 @@ header.navbar {
|
||||
|
||||
--aug-border-bottom: 0px;
|
||||
--aug-border-right: 0px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
tr:last-of-type td,
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
<!-- navbar -->
|
||||
<div class="container">
|
||||
<header class="navbar navbar-expand" data-augmented-ui="tl-2-clip-x tr-clip-y bl-clip-y br-2-clip-x b-scoop-x both">
|
||||
<span id="navbar-title" class="navbar-brand ps-4">SR2 Initiative Tracker</span>
|
||||
<span class="navbar-brand ps-4">SR2 Initiative Tracker</span>
|
||||
<nav class="container-fluid justify-content-end" aria-label="Main navigation">
|
||||
<button type="submit" class="sr2-button" id="add-combatant-button" title="Add combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal"><svg viewbox="0 0 512 512"><use href="#add" /></svg>
|
||||
</button>
|
||||
@ -70,8 +70,8 @@
|
||||
</div>
|
||||
<div class="modal-footer" data-augmented-ui="inlay">
|
||||
<button type="button" class="sr2-button" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="sr2-button" id="confirm-modal-new-round-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
<button type="button" class="sr2-button display-none" id="confirm-modal-remove-combatant-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
<button type="submit" class="sr2-button" id="confirm-modal-new-round-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
<button type="submit" class="sr2-button display-none" id="confirm-modal-remove-combatant-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,8 +85,8 @@
|
||||
<h2 class="modal-title">Add New Combatant</h2>
|
||||
<button type="button" class="sr2-button" data-bs-dismiss="modal" aria-label="Close">✖</button>
|
||||
</div>
|
||||
<form id="combatant-form" name="combatant-modal-form" class="was-validated" onsubmit="return false;">
|
||||
<div class="modal-body" data-augmented-ui="inlay">
|
||||
<form id="combatant-form" name="combatant-modal-form" class="was-validated" onsubmit="return false;">
|
||||
<div>
|
||||
<input type="text" maxlength="40" class="form-control form-control-sm" id="combatant-modal-name" form="combatant-form" placeholder="Name" required>
|
||||
</div>
|
||||
@ -108,14 +108,14 @@
|
||||
<input type="range" class="form-range" min="0" max="10" value="0" id="combatant-modal-physical" list="damage-level">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer" data-augmented-ui="inlay">
|
||||
<button type="button" class="sr2-button" id="combatant-modal-cancel-button" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="sr2-button" id="combatant-modal-add-apply-button">Apply</button>
|
||||
<button type="button" class="sr2-button" id="combatant-modal-add-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
<button type="button" class="sr2-button display-none" id="combatant-modal-edit-ok-button" data-bs-dismiss="modal">OK</button>
|
||||
<button type="submit" class="sr2-button" id="combatant-modal-add-apply-button">Apply</button>
|
||||
<button type="submit" class="sr2-button" id="combatant-modal-add-ok-button" >OK</button>
|
||||
<button type="submit" class="sr2-button display-none" id="combatant-modal-edit-ok-button" >OK</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -190,7 +190,7 @@
|
||||
<!-- footer -->
|
||||
<div class="footer-container container">
|
||||
<footer data-augmented-ui="tl-clip br-clip both">
|
||||
<p><a href="https://git.unterdemradar.de/eclipse/sr2ini" tabindex="-1" title="sr2ini">sr2ini</a> | Copyright (C) 2022-23 by <a href="https://git.unterdemradar.de/eclipse">Eclipse</a> | background by <a href="https://www.deviantart.com/xxaries1970xx" tabindex="-1" title="xxAries1970xx on DeviantArt">xxAries1970xx</a></p>
|
||||
<p><a href="https://git.unterdemradar.de/tobias/sr2ini" tabindex="-1" title="sr2ini">sr2ini</a> | Copyright (C) 2023 by Eclipse729 | background by <a href="https://www.deviantart.com/xxaries1970xx" tabindex="-1" title="xxAries1970xx on DeviantArt">xxAries1970xx</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
422
src/js/sr2ini.js
422
src/js/sr2ini.js
@ -1,9 +1,26 @@
|
||||
/* *****************
|
||||
// Register Service Worker
|
||||
if (navigator && navigator.serviceWorker) {
|
||||
navigator.serviceWorker.register(
|
||||
new URL("service-worker.js", import.meta.url),
|
||||
{type: "module"}
|
||||
).then( (registration) => {
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
}, (err) => {
|
||||
console.log('ServiceWorker registration failed: ', err);
|
||||
});
|
||||
} else {
|
||||
console.error("Service workers are not supported.");
|
||||
}
|
||||
***************** */
|
||||
|
||||
|
||||
/*
|
||||
* import libraries
|
||||
*/
|
||||
|
||||
const $ = require("../../node_modules/jquery/dist/jquery.js");
|
||||
const bs = require("../../node_modules/bootstrap/js/dist/modal.js");
|
||||
const $ = require("../../node_modules/jquery/dist/jquery.js");
|
||||
|
||||
|
||||
/*
|
||||
@ -13,7 +30,7 @@ const bs = require("../../node_modules/bootstrap/js/dist/modal.js");
|
||||
const DAMAGE_PENALTY = [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4];
|
||||
const DAMAGE_NIVEAU = ["", "L", "M", "S", "D"];
|
||||
|
||||
const $COMBATANT_TABLE_ROW = $($.parseHTML([
|
||||
const COMBATANT_TABLE_ROW = [
|
||||
'<tr class="combatant-row" data-true-ini="">\n',
|
||||
'<td class="combatant-name" title="Combatant\'s name" data-bs-toggle="modal" data-bs-target="#combatant-modal" data-augmented-ui="both"></td>\n',
|
||||
'<td class="combatant-ini" title="Effective initiative (w/ wound penalties)" data-bs-toggle="modal" data-bs-target="#combatant-modal" data-augmented-ui="both"></td>\n',
|
||||
@ -24,7 +41,20 @@ const $COMBATANT_TABLE_ROW = $($.parseHTML([
|
||||
'</div>\n',
|
||||
'<div class="damage-dropdown">\n',
|
||||
'<button type="button" class="sr2-button damage-button" title="Take damage"><svg viewbox="0 0 512 512"><use href="#take-damage" /></svg></button>\n',
|
||||
'<div class="damage-monitor" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop both">\n',
|
||||
'</div>\n',
|
||||
'<div class="actions-dropdown">\n',
|
||||
'<button type="button" class="sr2-button actions-button" title="More actions"><svg viewbox="0 0 512 512"><use href="#more-actions" /</svg></button>\n',
|
||||
'<div class="actions-menu" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop both">\n',
|
||||
'<button type="button" class="sr2-button edit-button" title="Edit combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#edit" /></svg></button>\n',
|
||||
'<button type="button" class="sr2-button clone-button" title="Clone combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#clone" /></svg></button>\n',
|
||||
'<button type="button" class="sr2-button remove-button" title="Remove combatant" data-bs-toggle="modal" data-bs-target="#confirm-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#delete" /></svg></button>\n',
|
||||
'</div>\n',
|
||||
'</div>\n',
|
||||
'</td>\n',
|
||||
'</tr>'].join("");
|
||||
|
||||
const DAMAGE_MONITOR_HTML = [
|
||||
'<div class="damage-monitor" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop both">\n',
|
||||
'<table>\n',
|
||||
'<tr><td><button type="button" class="damage-stun active" title="Light stun damage" tabindex="-1">L</button></td><td><button type="button" class="damage-physical active" title="Light physical damage" tabindex="-1">L</button></td></tr>\n',
|
||||
'<tr><td><button type="button" class="damage-stun active" tabindex="-1"> </button></td><td><button type="button" class="damage-physical active" tabindex="-1"> </button></td></tr>\n',
|
||||
@ -37,39 +67,16 @@ const $COMBATANT_TABLE_ROW = $($.parseHTML([
|
||||
'<tr><td><button type="button" class="damage-stun active" tabindex="-1"> </button></td><td><button type="button" class="damage-physical active" tabindex="-1"> </button></td></tr>\n',
|
||||
'<tr><td><button type="button" class="damage-stun active" title="K.O." tabindex="-1"><svg viewbox="0 0 512 512"><use href="#ko" /></svg></button></td><td><button type="button" class="damage-physical active" title="Dead" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#dead" /></svg></button></td></tr>\n',
|
||||
'</table>\n',
|
||||
'</div>\n',
|
||||
'</div>\n',
|
||||
'<div class="actions-dropdown">\n',
|
||||
'<button type="button" class="sr2-button more-actions-button" title="More actions"><svg viewbox="0 0 512 512"><use href="#more-actions" /</svg></button>\n',
|
||||
'<div class="actions-menu" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop both">\n',
|
||||
'<button type="button" class="sr2-button edit-button" title="Edit combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#edit" /></svg></button>\n',
|
||||
'<button type="button" class="sr2-button clone-button" title="Clone combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#clone" /></svg></button>\n',
|
||||
'<button type="button" class="sr2-button remove-button" title="Remove combatant" data-bs-toggle="modal" data-bs-target="#confirm-modal" tabindex="-1"><svg viewbox="0 0 512 512"><use href="#delete" /></svg></button>\n',
|
||||
'</div>\n',
|
||||
'</div>\n',
|
||||
'</td>\n',
|
||||
'</tr>'].join("")));
|
||||
'</div>'].join("");
|
||||
|
||||
const $STUN_BADGE_HTML = $($.parseHTML('<sup><span class="badge bg-warning translate-middle stun-badge" title="Stun damage niveau"></span></sup>'));
|
||||
const $PHYSICAL_BADGE_HTML = $($.parseHTML('<sub><span class="badge bg-danger translate-middle physical-badge" title="Physical damage niveau"></span></sub>'));
|
||||
const STUN_BADGE_HTML = '<sup><span class="badge bg-warning translate-middle stun-badge" title="Stun damage niveau"></span></sup>';
|
||||
const PHYSICAL_BADGE_HTML = '<sub><span class="badge bg-danger translate-middle physical-badge" title="Physical damage niveau"></span></sub>';
|
||||
|
||||
|
||||
/*
|
||||
* helper class and functions
|
||||
* helper functions
|
||||
*/
|
||||
|
||||
// this class generates unique IDs
|
||||
// thx to stackoverflow user user1005939 (https://stackoverflow.com/questions/26203453/jquery-generate-unique-ids#comment128736848_33226136)
|
||||
class IDGenerator {
|
||||
#id = 0;
|
||||
|
||||
get next() { return this.#id++; }
|
||||
}
|
||||
|
||||
// IDGenerator instance that will be used to generate combatant IDs
|
||||
var idGen = new IDGenerator();
|
||||
|
||||
|
||||
// roll for initiative with the given reaction and number of ini dice
|
||||
function rollForInitiative(dice, rea) {
|
||||
if (isNaN(parseInt(dice)) || isNaN(parseInt(rea))) {
|
||||
@ -103,61 +110,28 @@ function whoGoesFirst(a, b) {
|
||||
|
||||
// compute a combatant's effective ini value (modified by wound penalties)
|
||||
function getEffectiveIni(tr) {
|
||||
let $tr = $(tr);
|
||||
// return 0 if combatant is K.O. or dead
|
||||
if ($tr.hasClass("ko-or-dead")) {
|
||||
return -1;
|
||||
if ($(tr).hasClass("ko-or-dead")) {
|
||||
return 0;
|
||||
}
|
||||
// otherwise compute effective ini (true ini minus wound penalties)
|
||||
let effectiveIni = parseInt($tr.attr("data-true-ini")) - DAMAGE_PENALTY[parseInt($tr.attr("data-damage-stun")) || 0] - DAMAGE_PENALTY[parseInt($tr.attr("data-damage-physical")) || 0];
|
||||
let effectiveIni = parseInt($(tr).attr("data-true-ini")) - DAMAGE_PENALTY[parseInt($(tr).attr("data-damage-stun")) || 0] - DAMAGE_PENALTY[parseInt($(tr).attr("data-damage-physical")) || 0];
|
||||
return Math.max(effectiveIni, 0);
|
||||
}
|
||||
|
||||
function getStatsFromCombatantModal() {
|
||||
return {
|
||||
name: $("#combatant-modal-name").val().trim(),
|
||||
ini: $("#combatant-modal-ini").val().trim(),
|
||||
dice: $("#combatant-modal-dice").val().trim(),
|
||||
rea: $("#combatant-modal-rea").val().trim(),
|
||||
stun: $("#combatant-modal-stun").val() || "0",
|
||||
physical: $("#combatant-modal-physical").val() || "0"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function addTestCombatants() {
|
||||
// add test combatant for testing purposes (duh)
|
||||
function addTestCombatant() {
|
||||
// Eclipse
|
||||
// $("#add-combatant-button").click();
|
||||
$("#combatant-modal-name").val("Eclipse");
|
||||
$("#combatant-modal-dice").val("3");
|
||||
$("#combatant-modal-rea").val("6");
|
||||
$("#combatant-modal-stun").val("0");
|
||||
$("#combatant-modal-physical").val("0");
|
||||
handleCombatantModalAddApplyButtonClick();
|
||||
// Solitaire
|
||||
$("#combatant-modal-name").val("Solitaire");
|
||||
$("#combatant-modal-dice").val("3");
|
||||
$("#combatant-modal-rea").val("17");
|
||||
$("#combatant-modal-stun").val("0");
|
||||
$("#combatant-modal-physical").val("0");
|
||||
handleCombatantModalAddApplyButtonClick();
|
||||
// Q
|
||||
$("#combatant-modal-name").val("Q");
|
||||
$("#combatant-modal-dice").val("2");
|
||||
$("#combatant-modal-rea").val("9");
|
||||
$("#combatant-modal-stun").val("0");
|
||||
$("#combatant-modal-physical").val("0");
|
||||
handleCombatantModalAddApplyButtonClick();
|
||||
// Pie
|
||||
$("#combatant-modal-name").val("Pie");
|
||||
$("#combatant-modal-dice").val("3");
|
||||
$("#combatant-modal-rea").val("19");
|
||||
$("#combatant-modal-stun").val("0");
|
||||
$("#combatant-modal-physical").val("0");
|
||||
handleCombatantModalAddApplyButtonClick();
|
||||
$("#combatant-modal-dice").val(3);
|
||||
$("#combatant-modal-rea").val(6);
|
||||
// $("#combatant-modal-ini").val(12);
|
||||
addCombatant();
|
||||
// setTimeout( () => $("#combatant-modal-add-ok-button").click(), 500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Event handler functions
|
||||
*/
|
||||
@ -166,9 +140,10 @@ function addTestCombatants() {
|
||||
function handleActButtonClick(event) {
|
||||
// reduce ini by 10 but not lower than 0
|
||||
let ini = Math.max(parseInt($(event.target).parents(".combatant-row").attr("data-true-ini")) - 10, 0);
|
||||
// set new ini value
|
||||
$(event.target).parents(".combatant-row").attr("data-true-ini", ini);
|
||||
// resort table
|
||||
updateTable($("#combatants-table"));
|
||||
sortTable();
|
||||
}
|
||||
|
||||
// click handler for add button
|
||||
@ -177,16 +152,15 @@ function handleAddButtonClick(event) {
|
||||
$("#combatant-modal .modal-title").text("Add Combatant");
|
||||
$("#combatant-modal-add-ok-button, #combatant-modal-add-apply-button").removeClass("display-none");
|
||||
$("#combatant-modal-edit-ok-button").addClass("display-none");
|
||||
// clear values
|
||||
$("#combatant-modal-stun, #combatant-modal-physical").val("0");
|
||||
// $("#combatant-modal-name #combatant-modal-ini #combatant-modal-dice #combatant-modal-rea").val("");
|
||||
// preset values
|
||||
// set default values
|
||||
$("#combatant-modal-name").val("Goon 1");
|
||||
$("#combatant-modal-dice").val("2");
|
||||
$("#combatant-modal-rea").val("7");
|
||||
// set damage sliders to zero
|
||||
$("#combatant-modal-stun, #combatant-modal-physical").val("0");
|
||||
// add handler for enter key
|
||||
$("#combatant-modal input[id*='combatant-modal']").off("keydown");
|
||||
$("#combatant-modal input[id*='combatant-modal']").on("keydown", e => {
|
||||
$("#combatant-modal input[id*='combatant-modal']").on("keydown", (e) => {
|
||||
if (e.which == 13 || e.which == 10) {
|
||||
handleCombatantModalAddOkButtonClick(e);
|
||||
}
|
||||
@ -221,55 +195,25 @@ function handleCloneButtonClick(event) {
|
||||
|
||||
// click handler for combatant modal OK button (add mode)
|
||||
function handleCombatantModalAddOkButtonClick(event) {
|
||||
// validate
|
||||
if ( ! validateCombatant($("#combatant-form").get(0))) {
|
||||
return false;
|
||||
}
|
||||
// hide modal
|
||||
if (validateCombatant()) {
|
||||
bs.getInstance($("#combatant-modal")).hide();
|
||||
// everything else can be handled by the apply button handler
|
||||
handleCombatantModalAddApplyButtonClick(event);
|
||||
addCombatant();
|
||||
}
|
||||
}
|
||||
|
||||
// click handler for combatant modal Apply button (add mode)
|
||||
function handleCombatantModalAddApplyButtonClick(event) {
|
||||
// validate
|
||||
if ( ! validateCombatant($("#combatant-form").get(0))) {
|
||||
return false;
|
||||
if (validateCombatant()) {
|
||||
addCombatant();
|
||||
}
|
||||
// prepare new table row
|
||||
let $tr = $COMBATANT_TABLE_ROW.clone();
|
||||
$tr.attr("id", idGen.next);
|
||||
$tr.find(".act-button").on("click", handleActButtonClick);
|
||||
$tr.find(".damage-button").on("click", handleDamageButtonClick);
|
||||
$tr.find(".damage-stun, .damage-physical").on("click", handleDamageLevelClick);
|
||||
$tr.find(".more-actions-button").on("click", handleMoreActionsButtonClick);
|
||||
$tr.find(".edit-button, .combatant-name, .combatant-ini, .combatant-dice-and-rea").on("click", handleEditButtonClick);
|
||||
$tr.find(".clone-button").on("click", handleCloneButtonClick);
|
||||
$tr.find(".remove-button").on("click", handleRemoveButtonClick);
|
||||
// update table row with stats from modal
|
||||
$tr = updateCombatantTablerow(getStatsFromCombatantModal(), $tr);
|
||||
// append row to table
|
||||
$("#combatants-table").append($tr);
|
||||
// update (and sort) table
|
||||
updateTable($("#combatants-table"));
|
||||
}
|
||||
|
||||
// click handler for combatant modal OK button (edit mode)
|
||||
function handleCombatantModalEditOkButtonClick(event) {
|
||||
// validate
|
||||
if ( ! validateCombatant($("#combatant-form").get(0)) ) {
|
||||
return false;
|
||||
}
|
||||
// hide modal
|
||||
if (validateCombatant()) {
|
||||
bs.getInstance($("#combatant-modal")).hide();
|
||||
// update table row
|
||||
let id = $("#combatant-modal").data("row-id"),
|
||||
$tr = updateCombatantTablerow(getStatsFromCombatantModal(), $(".combatant-row#" + id));
|
||||
// update table
|
||||
updateTable($("#combatants-table"));
|
||||
// clean up
|
||||
$("#combatant-modal").data("row-id", "");
|
||||
editCombatant();
|
||||
}
|
||||
}
|
||||
|
||||
// click handler for damage buttons; basically toggles visibility of .damage-monitor
|
||||
@ -278,7 +222,7 @@ function handleDamageButtonClick(event) {
|
||||
let seenAtClick = $(event.target).parents(".damage-dropdown").find(".damage-monitor").hasClass("seen");
|
||||
// hide all damage monitors and actions menus
|
||||
$(".damage-monitor.seen, .actions-menu.seen").removeClass("seen").find("button").attr("tabindex", "-1");
|
||||
// if targeted damage monitor was hidden before, show it now
|
||||
// if targeted dm was hidden before, show it now
|
||||
if (! seenAtClick) {
|
||||
$(event.target).parents(".damage-dropdown").find(".damage-monitor").addClass("seen").find("button").attr("tabindex", "0");
|
||||
}
|
||||
@ -287,7 +231,6 @@ function handleDamageButtonClick(event) {
|
||||
|
||||
// handle click on damage level button in damage monitor and apply damage to combatant
|
||||
function handleDamageLevelClick(event) {
|
||||
// find button
|
||||
let $btn = $(event.target).is("button") ? $(event.target) : $(event.target).closest("button");
|
||||
// retrieve new damage level and type from button position and "damage-[type]" class
|
||||
let damageLevel = $btn.parent().parent().index();
|
||||
@ -296,21 +239,18 @@ function handleDamageLevelClick(event) {
|
||||
}
|
||||
let damageType = $btn.attr("class").split(" ").filter(cls => cls.substr(0, 7) == "damage-" ? cls : false).toString().substr(7);
|
||||
// add damage level to table row as as data attribute
|
||||
$btn.parents(".combatant-row").attr("data-damage-" + damageType, damageLevel);
|
||||
$btn.parents("tr.combatant-row").attr("data-damage-" + damageType, damageLevel);
|
||||
// select/unselect damage buttons above/below
|
||||
$btn.toggleClass("active");
|
||||
$btn.parent().parent().prevAll().find(".damage-" + damageType).removeClass("active");
|
||||
$btn.parent().parent().nextAll().find(".damage-" + damageType).addClass("active");
|
||||
updateTable($("#combatants-table"));
|
||||
$btn.focus();
|
||||
$btn.parent().parent().prevAll().find("button.damage-" + damageType).removeClass("active");
|
||||
$btn.parent().parent().nextAll().find("button.damage-" + damageType + ":not(.active)").addClass("active");
|
||||
sortTable();
|
||||
}
|
||||
|
||||
// click handler for edit buttons
|
||||
function handleEditButtonClick(event) {
|
||||
// save ID of row being edited
|
||||
// here it's okay to use the jQuery data() function (which is not the same as using a data attribute) b/c this value is only used with JS, not with HTML or CSS
|
||||
// find current table row
|
||||
let $tr = $(event.target).parents(".combatant-row");
|
||||
$("#combatant-modal").data("row-id", $tr.attr("id"));
|
||||
// restyle modal
|
||||
$("#combatant-modal .modal-title").text("Edit Combatant");
|
||||
$("#combatant-modal-edit-ok-button").removeClass("display-none");
|
||||
@ -322,6 +262,8 @@ function handleEditButtonClick(event) {
|
||||
$("#combatant-modal-ini").val($tr.attr("data-true-ini"));
|
||||
$("#combatant-modal-stun").val($tr.attr("data-damage-stun") || "0");
|
||||
$("#combatant-modal-physical").val($tr.attr("data-damage-physical") || "0");
|
||||
// mark which row is being edited
|
||||
$("#combatant-modal").data("row", $(".combatant-row").index($tr)); // here it's okay to use the jQuery data() function (which is not the same as using a data attribute) b/c this value is used only in this script and not via HTML or CSS
|
||||
// add handler for enter key
|
||||
$("#combatant-modal input[id*='combatant-modal']").off("keydown");
|
||||
$("#combatant-modal input[id*='combatant-modal']").on("keydown", (e) => {
|
||||
@ -335,12 +277,14 @@ function handleEditButtonClick(event) {
|
||||
function handleMoreActionsButtonClick(event) {
|
||||
// get visibility status at click time
|
||||
let seenAtClick = $(event.target).parents(".actions-dropdown").find(".actions-menu").hasClass("seen");
|
||||
|
||||
// hide all damage monitors
|
||||
$(".actions-menu.seen, .damage-monitor.seen").removeClass("seen").find("button").attr("tabindex", "-1");
|
||||
// if targeted actions menu was seen before, show it now
|
||||
// if targeted dm was seen before, show it now
|
||||
if (! seenAtClick) {
|
||||
$(event.target).parents(".actions-dropdown").find(".actions-menu").addClass("seen").find("button").attr("tabindex", "0");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -362,13 +306,12 @@ function handleNewRoundButtonClick(event) {
|
||||
|
||||
// click handler for remove buttons
|
||||
function handleRemoveButtonClick(event) {
|
||||
// mark which row is being removed
|
||||
let id = $(event.target).parents(".combatant-row").attr("id");
|
||||
$("#confirm-modal").data("row-id", id); // again, here it's okay to use jQuery .data() method (see handleEditButtonClick())
|
||||
// restyle modal
|
||||
$("#confirm-modal .modal-title").text("Remove Combatant");
|
||||
$("#confirm-modal-remove-combatant-ok-button").removeClass("display-none");
|
||||
$("#confirm-modal-new-round-ok-button").addClass("display-none");
|
||||
// mark which row is being removed
|
||||
$("#confirm-modal").data("row", $(".combatant-row").index($(event.target).parents(".combatant-row"))); // here it's okay to use .data() b/c HTML/CSS does not care about this value
|
||||
// add handler for enter key
|
||||
$("#confirm-modal").off("keydown");
|
||||
$("#confirm-modal").on("keydown", (e) => {
|
||||
@ -384,31 +327,70 @@ function handleRemoveButtonClick(event) {
|
||||
* Main functions
|
||||
*/
|
||||
|
||||
|
||||
function updateCombatantTablerow(stats, $tr) {
|
||||
// add new combatant
|
||||
function addCombatant() {
|
||||
// roll for initiative if necessary
|
||||
let ini = (stats["ini"] == "") ? rollForInitiative(stats["dice"], stats["rea"]) : stats["ini"];
|
||||
// populate table row with combatant stats
|
||||
$tr.find(".combatant-name").text(stats["name"]);
|
||||
let ini = $("#combatant-modal-ini").val().trim();
|
||||
ini = (ini != "") ? ini : rollForInitiative($("#combatant-modal-dice").val(), $("#combatant-modal-rea").val());
|
||||
// construct jQuery object for table row
|
||||
let $tr = $($.parseHTML(COMBATANT_TABLE_ROW));
|
||||
$tr.find(".damage-dropdown").append($.parseHTML(DAMAGE_MONITOR_HTML));
|
||||
// populate table row with values from modal
|
||||
$tr.attr("data-true-ini", ini);
|
||||
$tr.find(".combatant-dice").attr("data-combatant-dice", stats["dice"]);
|
||||
$tr.find(".combatant-rea").attr("data-combatant-rea", stats["rea"]);
|
||||
// set initial damage levels
|
||||
$tr.attr("data-damage-stun", stats["stun"]);
|
||||
$tr.find(".damage-stun").addClass("active").slice(0, parseInt(stats["stun"])).removeClass("active");
|
||||
$tr.attr("data-damage-physical", stats["physical"]);
|
||||
$tr.find(".damage-physical").addClass("active").slice(0, parseInt(stats["physical"])).removeClass("active");
|
||||
// done
|
||||
return $tr;
|
||||
$tr.find(".combatant-name").text($("#combatant-modal-name").val().trim());
|
||||
$tr.find(".combatant-dice").attr("data-combatant-dice", $("#combatant-modal-dice").val().trim());
|
||||
$tr.find(".combatant-rea").attr("data-combatant-rea", $("#combatant-modal-rea").val().trim());
|
||||
// retrieve initial damage levels
|
||||
$tr.attr("data-damage-stun", $("#combatant-modal-stun").val() || "0");
|
||||
$tr.find(".damage-stun").addClass("active").slice(0, parseInt($tr.attr("data-damage-stun")) || 0).removeClass("active");
|
||||
$tr.attr("data-damage-physical", $("#combatant-modal-physical").val() || "0");
|
||||
$tr.find(".damage-physical").addClass("active").slice(0, parseInt($tr.attr("data-damage-physical")) || 0).removeClass("active");
|
||||
// add event handlers
|
||||
$tr.find("button.act-button").on("click", handleActButtonClick);
|
||||
$tr.find("button.damage-button").on("click", handleDamageButtonClick);
|
||||
$tr.find("button.actions-button").on("click", handleMoreActionsButtonClick);
|
||||
$tr.find("button.edit-button, .combatant-name, .combatant-ini, .combatant-dice-and-rea").on("click", handleEditButtonClick);
|
||||
$tr.find("button.clone-button").on("click", handleCloneButtonClick);
|
||||
$tr.find("button.remove-button").on("click", handleRemoveButtonClick);
|
||||
$tr.find(".damage-stun, .damage-physical").on("click", handleDamageLevelClick);
|
||||
// append row to table and sort
|
||||
$("#combatants-table").append($tr);
|
||||
sortTable();
|
||||
}
|
||||
|
||||
// edit combatant
|
||||
function editCombatant() {
|
||||
// get values
|
||||
let name = $("#combatant-modal-name").val().trim();
|
||||
let ini = $("#combatant-modal-ini").val().trim();
|
||||
let dice = $("#combatant-modal-dice").val().trim();
|
||||
let rea = $("#combatant-modal-rea").val().trim();
|
||||
// roll for initiative if ini is empty
|
||||
ini = (ini != "") ? ini : rollForInitiative(dice, rea);
|
||||
// get correct row
|
||||
let index = parseInt($("#combatant-modal").data("row"));
|
||||
let $tr = $("tr.combatant-row").eq(index);
|
||||
// set new values
|
||||
$tr.attr("data-true-ini", ini);
|
||||
$tr.find(".combatant-name").text(name);
|
||||
$tr.find(".combatant-dice").attr("data-combatant-dice", dice);
|
||||
$tr.find(".combatant-rea").attr("data-combatant-rea", rea);
|
||||
$tr.attr("data-damage-stun", $("#combatant-modal-stun").val() || "0");
|
||||
$tr.find(".damage-stun").addClass("active").slice(0, parseInt($tr.attr("data-damage-stun")) || 0).removeClass("active");
|
||||
$tr.attr("data-damage-physical", $("#combatant-modal-physical").val() || "0");
|
||||
$tr.find(".damage-physical").addClass("active").slice(0, parseInt($tr.attr("data-damage-physical")) || 0).removeClass("active");
|
||||
// sort table
|
||||
sortTable();
|
||||
// clean up
|
||||
$("#combatant-modal").data("row", "");
|
||||
}
|
||||
|
||||
// remove combatant
|
||||
function removeCombatant() {
|
||||
// remove correct row
|
||||
let id = $("#confirm-modal").data("row-id");
|
||||
$(".combatant-row#" + id).remove();
|
||||
// update table
|
||||
updateTable($("#combatants-table"));
|
||||
let index = parseInt($("#confirm-modal").data("row"));
|
||||
$(".combatant-row").eq(index).remove();
|
||||
sortTable();
|
||||
// clean up
|
||||
$("#confirm-modal").data("row", "");
|
||||
}
|
||||
@ -421,94 +403,98 @@ function startNewRound() {
|
||||
}
|
||||
// reset ini values
|
||||
$(".combatant-row").each(function () {
|
||||
let $this = $(this);
|
||||
if ($this.find(".combatant-dice").attr("data-combatant-dice") == "") {
|
||||
$this.attr("data-true-ini", 1);
|
||||
if ($(this).find(".combatant-dice").attr("data-combatant-dice") == "") {
|
||||
$(this).attr("data-true-ini", 1);
|
||||
} else {
|
||||
$this.attr("data-true-ini", rollForInitiative(parseInt($this.find(".combatant-dice").attr("data-combatant-dice")), parseInt($this.find(".combatant-rea").attr("data-combatant-rea"))));
|
||||
$(this).attr("data-true-ini", rollForInitiative(parseInt($(this).find(".combatant-dice").attr("data-combatant-dice")), parseInt($(this).find(".combatant-rea").attr("data-combatant-rea"))));
|
||||
}
|
||||
});
|
||||
// resort table
|
||||
updateTable($("#combatants-table"));
|
||||
sortTable();
|
||||
}
|
||||
|
||||
// update combatants' table's effective inis, contextual classes, and order
|
||||
function updateTable(table) {
|
||||
let $table = $(table),
|
||||
$rows = $table.find(".combatant-row");
|
||||
// do some clean up: remove contextual classes, remove effective ini and damage badges
|
||||
$rows.removeClass("ko-or-dead max-ini zero-ini");
|
||||
$table.find(".combatant-ini").empty();
|
||||
$table.find(".stun-badge .physical-badge").remove();
|
||||
// sort combatants by ini value and add contextual classes
|
||||
function sortTable() {
|
||||
// do some clean up: remove previous classes from rows, remove effective ini and damage badges
|
||||
$(".combatant-row").removeClass("ko-or-dead max-ini zero-ini"); //REGULAR_INI
|
||||
$(".combatant-ini").empty();
|
||||
// disable all act buttons
|
||||
$table.find(".act-button").prop("disabled", true).attr("aria-disabled", "true");
|
||||
// mark KO/death with class
|
||||
$rows.each(function(i) {
|
||||
let $this = $(this);
|
||||
if (parseInt($this.attr("data-damage-stun")) == 10 || parseInt($this.attr("data-damage-physical")) == 10) {
|
||||
$this.addClass("ko-or-dead");
|
||||
$(".combatant-row").find(".act-button").prop("disabled", true).attr("aria-disabled", "true");
|
||||
// mark KO or death with class
|
||||
$(".combatant-row").each(function() {
|
||||
if (parseInt($(this).attr("data-damage-stun")) == 10 || parseInt($(this).attr("data-damage-physical")) == 10) {
|
||||
$(this).addClass("ko-or-dead");
|
||||
}
|
||||
});
|
||||
// compute highest effective ini while writing effective ini to each row
|
||||
let iniMax = Math.max.apply(null, $.map($rows, (tr, i) => {
|
||||
let $tr = $(tr);
|
||||
$tr.find(".combatant-ini").text($tr.hasClass("ko-or-dead") ? 0 : getEffectiveIni($tr));
|
||||
return parseInt($tr.find(".combatant-ini").text());
|
||||
// compute highest effective ini
|
||||
let iniMax = Math.max.apply(null, $.map($(".combatant-row"), function (tr, i) {
|
||||
// write current effective ini to table row
|
||||
$(tr).find(".combatant-ini").text($(tr).hasClass("ko-or-dead") ? 0 : getEffectiveIni($(tr)));
|
||||
return $(tr).find(".combatant-ini").text();
|
||||
}));
|
||||
// iterate over rows to add damage badges and contextual classes
|
||||
$rows.each(function(i) {
|
||||
let $this = $(this);
|
||||
// add damage badges and contextual classes
|
||||
$(".combatant-row").each(function () {
|
||||
// damage badges
|
||||
if ($this.attr("data-damage-stun") && $this.attr("data-damage-stun") != "0") {
|
||||
$this.find(".combatant-ini").append($STUN_BADGE_HTML.clone());
|
||||
$this.find(".stun-badge").append(DAMAGE_NIVEAU[DAMAGE_PENALTY[$this.attr("data-damage-stun")]]);
|
||||
if ($(this).attr("data-damage-stun") && $(this).attr("data-damage-stun") != "0") {
|
||||
$(this).find(".combatant-ini").append($.parseHTML(STUN_BADGE_HTML));
|
||||
$(this).find(".stun-badge").append(DAMAGE_NIVEAU[DAMAGE_PENALTY[$(this).attr("data-damage-stun")]]);
|
||||
}
|
||||
if ($this.attr("data-damage-physical") && $this.attr("data-damage-physical") != "0") {
|
||||
$this.find(".combatant-ini").append($PHYSICAL_BADGE_HTML.clone());
|
||||
$this.find(".physical-badge").append(DAMAGE_NIVEAU[DAMAGE_PENALTY[$this.attr("data-damage-physical")]]);
|
||||
if ($(this).attr("data-damage-physical") && $(this).attr("data-damage-physical") != "0") {
|
||||
$(this).find(".combatant-ini").append($.parseHTML(PHYSICAL_BADGE_HTML));
|
||||
$(this).find(".physical-badge").append(DAMAGE_NIVEAU[DAMAGE_PENALTY[$(this).attr("data-damage-physical")]]);
|
||||
}
|
||||
// K.O./dead -> done
|
||||
if ($this.hasClass("ko-or-dead")) {
|
||||
// K.O./dead -> do nothing
|
||||
if ($(this).hasClass("ko-or-dead")) {
|
||||
return true;
|
||||
}
|
||||
// ini = zero -> set class and done
|
||||
if (parseInt($this.find(".combatant-ini").text()) == 0) {
|
||||
$this.addClass("zero-ini");
|
||||
// ini = zero -> set contextual class
|
||||
if (parseInt($(this).find(".combatant-ini").text()) == 0) {
|
||||
$(this).addClass("zero-ini");
|
||||
return true;
|
||||
}
|
||||
// ini = max and non-zero -> set class, enable act-button
|
||||
if (parseInt($this.find(".combatant-ini").text()) == iniMax && iniMax > 0) {
|
||||
$this.addClass("max-ini").find(".act-button").prop("disabled", false).removeAttr("aria-disabled");
|
||||
// ini = max and non-zero -> enable act-button
|
||||
if (parseInt($(this).find(".combatant-ini").text()) == iniMax && iniMax > 0) {
|
||||
$(this).addClass("max-ini").find(".act-button").prop("disabled", false).removeAttr("aria-disabled");
|
||||
return true;
|
||||
}
|
||||
})
|
||||
// sort rows and append them in new order
|
||||
rows = $rows.toArray().sort(whoGoesFirst);
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
$table.append($(rows[i]).css("z-index", 50-i));
|
||||
let $rows = $(".combatant-row").toArray().sort(whoGoesFirst);
|
||||
for (let i = 0; i < $rows.length; i++) {
|
||||
$("#combatants-table").append($rows[i]);
|
||||
$($rows[i]).css("z-index", 50-i).css("position", "relative");
|
||||
}
|
||||
return $table;
|
||||
return;
|
||||
}
|
||||
|
||||
// validate a combatant row form by checking for all conditions, including regular HTML5 validation
|
||||
function validateCombatant(form) {
|
||||
function validateCombatant() {
|
||||
// do standard HTML5 form validation first
|
||||
// (makes sure that name is not empty and that all other values are numbers within their individual ranges)
|
||||
if ( ! form.reportValidity() ) {
|
||||
if ( ! $("#combatant-form").get(0).reportValidity() ) {
|
||||
return false;
|
||||
}
|
||||
// get input values
|
||||
let ini = $(form).find("#combatant-modal-ini").get(0).value.trim(),
|
||||
dice = $(form).find("#combatant-modal-dice").get(0).value.trim(),
|
||||
rea = $(form).find("#combatant-modal-rea").get(0).value.trim();
|
||||
// get input elements
|
||||
let inputElements = {
|
||||
name: $("#combatant-modal-name").get(0),
|
||||
ini: $("#combatant-modal-ini").get(0),
|
||||
dice: $("#combatant-modal-dice").get(0),
|
||||
rea: $("#combatant-modal-rea").get(0)
|
||||
};
|
||||
// now for some custom validation; first we need to get the input values
|
||||
let ini = inputElements["ini"].value.trim();
|
||||
let dice = inputElements["dice"].value.trim();
|
||||
let rea = inputElements["rea"].value.trim();
|
||||
// invalidate if ini, dice and rea are all empty
|
||||
if (ini == "" && (dice == "" || rea == "")) {
|
||||
$(form).find("#combatant-modal-ini").get(0).setCustomValidity("Values required for either initiative, or dice and reaction, or all three");
|
||||
inputElements["ini"].setCustomValidity("Values required for either initiative, or dice and reaction, or all three");
|
||||
inputElements["ini"].reportValidity();
|
||||
return false;
|
||||
}
|
||||
// invalidate if dice or rea is empty but not both
|
||||
if ((dice == "") != (rea == "")) {
|
||||
$(form).find("#combatant-modal-ini").get(0).setCustomValidity("Values required for both dice and reaction, or none (in which case ini is required)");
|
||||
inputElements["dice"].setCustomValidity("Values required for both dice and reaction, or none (in which case ini is required)");
|
||||
inputElements["dice"].reportValidity();
|
||||
return false;
|
||||
}
|
||||
// ok then
|
||||
@ -528,10 +514,16 @@ $(document).ready(function () {
|
||||
$("#combatant-modal-add-apply-button").on("click", handleCombatantModalAddApplyButtonClick);
|
||||
$("#combatant-modal-add-ok-button").on("click", handleCombatantModalAddOkButtonClick);
|
||||
$("#combatant-modal-edit-ok-button").on("click", handleCombatantModalEditOkButtonClick);
|
||||
$("#confirm-modal-new-round-ok-button").on("click", startNewRound);
|
||||
$("#confirm-modal-remove-combatant-ok-button").on("click", removeCombatant);
|
||||
// add event handler removing custom validity messages in combatant modal
|
||||
$("#combatant-modal-dice #combatant-modal-rea #combatant-modal-ini").on("input", (event) => event.target.setCustomValidity(""));
|
||||
$("#confirm-modal-new-round-ok-button").on("click", () => {
|
||||
startNewRound();
|
||||
});
|
||||
$("#confirm-modal-remove-combatant-ok-button").on("click", () => {
|
||||
removeCombatant();
|
||||
});
|
||||
// add event handler to certain input elements that removes any custom validity message
|
||||
$("#combatant-modal-dice #combatant-modal-rea #combatant-modal-ini").on("input", (event) => {
|
||||
event.target.setCustomValidity("");
|
||||
});
|
||||
// add event listeners to damage sliders in combatant modal
|
||||
$("#combatant-modal-stun").on("input change", () => {
|
||||
if ($("#combatant-modal-stun").val() == "10") {
|
||||
@ -552,10 +544,9 @@ $(document).ready(function () {
|
||||
}
|
||||
});
|
||||
// always focus name input field when combatant modal appears
|
||||
// (need to use vanilla JS b/c jQuery can't seem to attach event handler correctly)
|
||||
document.getElementById('combatant-modal').addEventListener('shown.bs.modal', () => $('#combatant-modal-name').focus());
|
||||
$('#combatant-modal').on('shown.bs.modal', () => $('#combatant-modal-name').focus());
|
||||
// always empty input fields when combatant modal disappears
|
||||
document.getElementById('combatant-modal').addEventListener('hidden.bs.modal', () => $("input[id*='combatant-modal']").val(""));
|
||||
$("#combatant-modal").on('hidden.bs.modal', () => $("input[id*='combatant-modal']").val(""));
|
||||
// Hide damage monitors and actions menus after click somewhere else
|
||||
$("html").on("click", (e) => {
|
||||
if ($(e.target).parents(".damage-monitor").length == 0) {
|
||||
@ -565,16 +556,7 @@ $(document).ready(function () {
|
||||
$(".actions-menu.seen").removeClass("seen");
|
||||
}
|
||||
});
|
||||
// add test combatants when title is held for one second
|
||||
// thx to stackoverflow user Šime Vidas (https://stackoverflow.com/a/6091129)
|
||||
$("#navbar-title").mousedown(function(e) {
|
||||
clearTimeout(this.downTimer);
|
||||
this.downTimer = setTimeout(function() {
|
||||
addTestCombatants();
|
||||
}, 1000);
|
||||
}).mouseup(function(e) {
|
||||
clearTimeout(this.downTimer);
|
||||
});
|
||||
addTestCombatant();
|
||||
});
|
||||
|
||||
module.exports = { rollForInitiative, validateCombatant, whoGoesFirst, getEffectiveIni };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user