From ecd1652403638df1ce23233c568db745b744296d Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 4 Nov 2022 20:41:16 +0100 Subject: [PATCH] Ajout de notes chronologiques --- module/dialog-chronologie.js | 124 ++++++++++++++++++++++++++++++ module/grammar.js | 4 + module/rdd-calendrier.js | 78 +++++++++++++------ module/rdd-commands.js | 7 ++ module/rdd-herbes.js | 2 +- module/rdd-main.js | 7 +- module/rdd-utility.js | 2 + styles/simple.css | 12 +++ templates/calendar-template.html | 14 +++- templates/chronologie-entry.html | 4 + templates/dialog-chronologie.html | 55 +++++++++++++ 11 files changed, 281 insertions(+), 28 deletions(-) create mode 100644 module/dialog-chronologie.js create mode 100644 templates/chronologie-entry.html create mode 100644 templates/dialog-chronologie.html diff --git a/module/dialog-chronologie.js b/module/dialog-chronologie.js new file mode 100644 index 00000000..7b780d1b --- /dev/null +++ b/module/dialog-chronologie.js @@ -0,0 +1,124 @@ +import { SYSTEM_RDD } from "./constants.js"; +import { Grammar } from "./grammar.js"; + + +const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal"; + +export class DialogChronologie extends Dialog { + + static onInit() { + game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, { + name: "Dernier article de journal utilisé pour enregistrer la chronologie", + scope: "client", + config: false, + default: "", + type: String + }); + } + static async create() { + const dialogData = { + auteur: game.user.name, + isGM: game.user.isGM, + information: "", + journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID), + journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)), + dateRdD: game.system.rdd.calendrier.getCalendrier(), + heureRdD: game.system.rdd.calendrier.getCurrentHeure(), + dateReel: DialogChronologie.getCurrentDateTime() + }; + const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData); + new DialogChronologie(html).render(true); + } + + constructor(html) { + const options = { + classes: ["DialogChronologie"], + width: 500, + height: 350, + 'z-index': 99999 + }; + const conf = { + title: "Chronologie", + content: html, + buttons: { + ajout: { label: "Ajouter", callback: it => this.ajouter() }, + }, + default: "ajout" + }; + super(conf, options); + } + + static getCurrentDateTime() { + return new Date().toLocaleString("sv-SE", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit" + }).replace(" ", "T"); + } + + activateListeners(html) { + super.activateListeners(html); + } + + async ajouter() { + await this.forceValidation(); + const { journalId, journalEntry } = this.findJournal(); + // ajouter à la page ou créer une page + this.addContentToJournal(journalEntry, await this.prepareChronologieEntry()); + + this.storeLatestUsedJournalEntry(journalId); + } + + async forceValidation() { + await $("form.rdddialogchrono :input").change(); + } + + findJournal() { + const journalId = $("form.rdddialogchrono :input[name='journalId']").val(); + const journalEntry = game.journal.get(journalId); + return { journalId, journalEntry }; + } + + async prepareChronologieEntry() { + return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", this.extractJournalParameters()); + } + + extractJournalParameters() { + return { + auteur: $("form.rdddialogchrono :input[name='auteur']").val(), + information: $("form.rdddialogchrono :input[name='information']").val(), + dateRdD: { + jour: $("form.rdddialogchrono :input[name='dateRdD.jour']").val(), + moisRdD: $("form.rdddialogchrono :input[name='dateRdD.moisRdD.key']").val(), + annee: $("form.rdddialogchrono :input[name='dateRdD.annee']").val() + }, + heureRdD: $("form.rdddialogchrono :input[name='heureRdD']").val(), + dateReel: $("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ') + } + } + + addContentToJournal(journalEntry, content) { + let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, 'Chronologie')); + if (page) { + page.update({ 'text.content': content + '\n' + page.text.content }); + } + else { + journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(content)]); + } + } + + newPageChronologie(content) { + return new JournalEntryPage({ + name: 'Chronologie', + type: 'text', + title: { show: true, level: 1 }, + text: { content: content, format: 1 } + }); + } + + storeLatestUsedJournalEntry(journalId) { + game.settings.set(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, journalId); + } +} \ No newline at end of file diff --git a/module/grammar.js b/module/grammar.js index a8bd17a6..478bbae1 100644 --- a/module/grammar.js +++ b/module/grammar.js @@ -19,10 +19,14 @@ export class Grammar { return word.match(/^[aeiouy]/i) } + static equalsInsensitive(a, b) { + return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b) + } static includesLowerCaseNoAccent(value, content) { return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content)); } + /* -------------------------------------------- */ static toLowerCaseNoAccent(words) { return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words; diff --git a/module/rdd-calendrier.js b/module/rdd-calendrier.js index ffeb129d..1377b26d 100644 --- a/module/rdd-calendrier.js +++ b/module/rdd-calendrier.js @@ -8,23 +8,24 @@ import { Grammar } from "./grammar.js"; import { RdDDice } from "./rdd-dice.js"; import { Misc } from "./misc.js"; import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { DialogChronologie } from "./dialog-chronologie.js"; /* -------------------------------------------- */ const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/' const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"]; const heuresDef = { - "vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' }, - "sirene": { label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' }, - "faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' }, - "couronne": { label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' }, - "dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' }, - "epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' }, - "lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' }, - "serpent": { label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' }, - "poissonacrobate": { label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' }, - "araignee": { label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' }, - "roseau": { label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' }, - "chateaudormant": { label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' } + "vaisseau": {key:"vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' }, + "sirene": { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' }, + "faucon": { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' }, + "couronne": { key: "couronne", label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' }, + "dragon": { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' }, + "epees": { key: "epees", label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' }, + "lyre": { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' }, + "serpent": { key: "serpent", label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' }, + "poissonacrobate": { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' }, + "araignee": { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' }, + "roseau": { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' }, + "chateaudormant": { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' } }; const saisonsDef = { "printemps": { label: "Printemps" }, @@ -51,21 +52,50 @@ export class RdDCalendrier extends Application { return Object.values(heuresDef).find(h => h.heure == chiffre); } + static getSigneAs(key, value) { + const heure = (typeof value == 'string' || typeof value == 'number') && Number.isInteger(Number(value)) + ? Number(value) + : (typeof value == 'string') ? RdDCalendrier.getChiffreFromSigne(value) + : undefined + + if (heure != undefined && ['key', 'label', 'lettreFont', 'saison', 'heure', 'icon'].includes(key)) { + return RdDCalendrier.getDefSigne(heure)[key] + } + if (heure != undefined && ['webp'].includes(key)) { + return RdDCalendrier.getDefSigne(heure)['icon'].replace('svg', 'webp'); + } + console.error(`Appel à getSigneAs('${key}', ${value}) avec une clé/heure incorrects`); + return value; + + } static getChiffreFromSigne(signe) { return heuresList.indexOf(signe); } - static getCalendrier(index) { - let calendrier = { + static createCalendrierInitial() { + return { + heureRdD: 0, + minutesRelative: 0, + indexJour: 0, + annee: 0, + moisRdD: 0, + moisLabel: heuresDef["vaisseau"].label, + jour: 0 + } + } + + getCalendrier(index) { + index = index ?? this.getCurrentDayIndex(); + const moisRdD = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN; + return { heureRdD: 0, // Index dans heuresList / heuresDef[x].heure minutesRelative: 0, indexJour: index, annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)), - moisRdD: Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN, + moisRdD: RdDCalendrier.getDefSigne(moisRdD), + moisLabel: RdDCalendrier.getDefSigne(moisRdD).label, jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage } - calendrier.moisLabel = RdDCalendrier.getDefSigne(calendrier.moisRdD).label; - return calendrier; } constructor() { @@ -78,7 +108,7 @@ export class RdDCalendrier extends Application { } // Calendrier - this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.getCalendrier(0)); + this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.createCalendrierInitial()); this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN); this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN; @@ -107,13 +137,13 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ getDateFromIndex(index) { - const date = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex()); - return (date.jour + 1) + ' ' + RdDCalendrier.getDefSigne(date.moisRdD).label; + const dateRdD = this.getCalendrier(index); + return (dateRdD.jour + 1) + ' ' + RdDCalendrier.getDefSigne(dateRdD.moisRdD).label; } /* -------------------------------------------- */ - getNumericDateFromIndex(index = undefined) { - const dateRdD = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex()); + getDayMonthFromIndex(index = undefined) { + const dateRdD = this.getCalendrier(index); return { day: dateRdD.jour + 1, month: heuresList[dateRdD.moisRdD] @@ -264,7 +294,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ async incrementerJour() { const index = this.getCurrentDayIndex() + 1; - this.calendrier = RdDCalendrier.getCalendrier(index); + this.calendrier = this.getCalendrier(index); await this.rebuildListeNombreAstral(); } @@ -536,6 +566,8 @@ export class RdDCalendrier extends Application { this.updateDisplay(); + html.find('.ajout-chronologie').click(ev => DialogChronologie.create()); + html.find('.calendar-btn').click(ev => this.onCalendarButton(ev)); html.find('.calendar-btn-edit').click(ev => { diff --git a/module/rdd-commands.js b/module/rdd-commands.js index 8d1cca3d..a8388a29 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -1,5 +1,6 @@ /* -------------------------------------------- */ +import { DialogChronologie } from "./dialog-chronologie.js"; import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js"; import { DialogStress } from "./dialog-stress.js"; import { Grammar } from "./grammar.js"; @@ -114,6 +115,11 @@ export class RdDCommands {
/stress 6 Glou Paulo : Distribue 6 points de Stress au personnage Paulon ou au personnage joueur Paulo, à cause d'un Glou` }); + rddCommands.registerCommand({ + path: ["/chrono"], func: (content, msg, params) => DialogChronologie.create(), + descr: `Enregistre une entrée de chronologie dans un article de journal` + }); + game.system.rdd.commands = rddCommands; } } @@ -404,5 +410,6 @@ export class RdDCommands { async getMeteo(msg, params) { return await RdDMeteo.getMeteo(); } + } diff --git a/module/rdd-herbes.js b/module/rdd-herbes.js index 32abaebc..8b091647 100644 --- a/module/rdd-herbes.js +++ b/module/rdd-herbes.js @@ -42,7 +42,7 @@ export class RdDHerbes extends Item { formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7); formData.jourMoisOptions = RdDCalendrier.buildJoursMois(); formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex(); - formData.splitDate = game.system.rdd.calendrier.getNumericDateFromIndex(formData.system.prdate); + formData.splitDate = game.system.rdd.calendrier.getDayMonthFromIndex(formData.system.prdate); } /* -------------------------------------------- */ diff --git a/module/rdd-main.js b/module/rdd-main.js index 638a84a4..12331097 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -36,6 +36,7 @@ import { RdDPossession } from "./rdd-possession.js"; import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js"; import { Misc } from "./misc.js"; import { Migrations } from './migrations.js'; +import { DialogChronologie } from "./dialog-chronologie.js"; /* -------------------------------------------- */ /* Foundry VTT Initialization */ @@ -77,7 +78,7 @@ Hooks.once("init", async function () { name: "calendrier", scope: "world", config: false, - default: RdDCalendrier.getCalendrier(0), + default: RdDCalendrier.createCalendrierInitial(), type: Object }); @@ -107,6 +108,8 @@ Hooks.once("init", async function () { default: RdDCalendrier.createCalendrierPos(), type: Object }); + + /* -------------------------------------------- */ game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { name: "Supprimer les dialogues de combat", @@ -140,6 +143,8 @@ Hooks.once("init", async function () { default: "aucun" }); + DialogChronologie.onInit(); + /* -------------------------------------------- */ // Set an initiative formula for the system CONFIG.Combat.initiative = { diff --git a/module/rdd-utility.js b/module/rdd-utility.js index f9d8e57e..c427fad6 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -14,6 +14,7 @@ import { RdDPossession } from "./rdd-possession.js"; import { RdDNameGen } from "./rdd-namegen.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { RdDActor } from "./actor.js"; +import { RdDCalendrier } from "./rdd-calendrier.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -279,6 +280,7 @@ export class RdDUtility { Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord)); Handlebars.registerHelper('typeTmr-name', coord => TMRUtility.typeTmrName(coord)); + Handlebars.registerHelper('signeHeure', (key, heure) => RdDCalendrier.getSigneAs(key, heure)); Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionelles.isUsing(option)); Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name))); diff --git a/styles/simple.css b/styles/simple.css index 802ee2d0..37d4738b 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -636,6 +636,18 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) { margin-bottom: 0.2rem; } +form.rdddialogchrono input[type=datetime-local] { + min-width: 20px; + padding: 0; + background: rgba(0, 0, 0, 0.05); + border: 1px solid var(--color-border-dark); + width: calc(100% - 2px); + height: var(--form-field-height); + margin: 0; + color: var(--color-text-dark-primary); + border-radius: 3px; +} + .window-app .window-content, .window-app.sheet .window-content .sheet-body{ background: rgb(245,245,240) url(img/bg_left.webp) no-repeat left top; } diff --git a/templates/calendar-template.html b/templates/calendar-template.html index cde29a9b..13951d34 100644 --- a/templates/calendar-template.html +++ b/templates/calendar-template.html @@ -5,7 +5,7 @@ {{/if}}
-

Jour {{jourMois}} de {{nomMois}} ({{nomSaison}})

+

Jour {{jourMois}} de {{nomMois}} ({{nomSaison}})

{{#if isGM}} @@ -20,8 +20,16 @@
{{/if}}
-

{{nomHeure}} {{nomHeure}}

-

{{minutesRelative}} minutes

+ {{#if isGM}} + + {{nomHeure}} {{nomHeure}} + +

{{minutesRelative}} minutes

+ {{else}} + + {{nomHeure}} {{nomHeure}} + + {{/if}}
{{#if isGM}}
diff --git a/templates/chronologie-entry.html b/templates/chronologie-entry.html new file mode 100644 index 00000000..eca3ca3a --- /dev/null +++ b/templates/chronologie-entry.html @@ -0,0 +1,4 @@ +

{{dateRdD.jour}} {{signeHeure 'label' dateRdD.moisRdD}}, an {{dateRdD.annee}} à l'heure de {{signeHeure 'label' heureRdD}}

+

{{information}}

+

Par {{auteur}} ({{dateReel}})

+
diff --git a/templates/dialog-chronologie.html b/templates/dialog-chronologie.html new file mode 100644 index 00000000..dc6cd03e --- /dev/null +++ b/templates/dialog-chronologie.html @@ -0,0 +1,55 @@ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + + +
+
+ + +
+
+ + +
+
+
\ No newline at end of file