47442be3ef
- bouton crayon sur la fenêtre calendrier (MJ) → dialogue de note - date impériale + date réelle préremplies - append au journal configuré (créé auto si inexistant) - appendJournalNote : labels passés depuis l'ouverture (pas de re-lecture) - échappement XSS via jQuery .text().html() - onSave async + await + try/catch - sauvegarde position calendrier (client scope, debounced 300ms) - restore position au constructeur - close() async avec await settings.set - boutons note et config groupés dans .mgt2-cal-actions (flex row)
275 lines
7.9 KiB
JavaScript
275 lines
7.9 KiB
JavaScript
import { CalendarApp } from './CalendarApp.js';
|
|
import { CalendarConfigDialog } from './CalendarConfigDialog.js';
|
|
import { JournalNoteDialog } from './JournalNoteDialog.js';
|
|
import { getDefaultCalendar, formatImperialDate, formatRealDate } from './calendarDate.js';
|
|
|
|
const MODULE_ID = 'mgt2-compendium-amiral-denisov';
|
|
const ChatLogV2 = foundry.applications.sidebar.tabs.ChatLog;
|
|
|
|
let _calendarApp = null;
|
|
|
|
function readCalendar() {
|
|
return {
|
|
year: game.settings.get(MODULE_ID, 'calendarYear'),
|
|
day: game.settings.get(MODULE_ID, 'calendarDay'),
|
|
hour: game.settings.get(MODULE_ID, 'calendarHour'),
|
|
minute: game.settings.get(MODULE_ID, 'calendarMinute'),
|
|
planet: game.settings.get(MODULE_ID, 'calendarPlanet'),
|
|
};
|
|
}
|
|
|
|
async function writeCalendar(data) {
|
|
await game.settings.set(MODULE_ID, 'calendarYear', data.year);
|
|
await game.settings.set(MODULE_ID, 'calendarDay', data.day);
|
|
await game.settings.set(MODULE_ID, 'calendarHour', data.hour);
|
|
await game.settings.set(MODULE_ID, 'calendarMinute', data.minute);
|
|
await game.settings.set(MODULE_ID, 'calendarPlanet', data.planet);
|
|
}
|
|
|
|
function applyCalendar(data) {
|
|
if (_calendarApp) {
|
|
_calendarApp.updateDisplay(data);
|
|
}
|
|
}
|
|
|
|
async function broadcastCalendar(data) {
|
|
if (!game.socket?.emit) return;
|
|
game.socket.emit(`module.${MODULE_ID}`, {
|
|
_type: 'calendarSync',
|
|
...data,
|
|
});
|
|
}
|
|
|
|
function openCalendarApp() {
|
|
if (_calendarApp) {
|
|
_calendarApp.bringToTop();
|
|
return;
|
|
}
|
|
const data = readCalendar();
|
|
_calendarApp = new CalendarApp({
|
|
onConfig: () => openCalendarConfig(),
|
|
onNote: () => openJournalNote(),
|
|
onClose: () => { _calendarApp = null; },
|
|
});
|
|
_calendarApp.updateDisplay(data);
|
|
_calendarApp.render({ force: true });
|
|
}
|
|
|
|
function openCalendarConfig() {
|
|
const data = readCalendar();
|
|
const dialog = new CalendarConfigDialog({
|
|
data,
|
|
onApply: async (newData) => {
|
|
await writeCalendar(newData);
|
|
applyCalendar(newData);
|
|
broadcastCalendar(newData);
|
|
dialog.close();
|
|
},
|
|
});
|
|
dialog.render({ force: true });
|
|
}
|
|
|
|
async function appendJournalNote(content, { dateLabel, realLabel } = {}) {
|
|
if (!content) return false;
|
|
const journalName = game.settings.get(MODULE_ID, 'calendarJournalName') || 'Journal de bord';
|
|
let journal = game.journal.getName(journalName);
|
|
if (!journal) {
|
|
journal = await JournalEntry.create({ name: journalName });
|
|
if (!journal) {
|
|
ui.notifications.error('Impossible de créer le journal');
|
|
return false;
|
|
}
|
|
}
|
|
if (!dateLabel || !realLabel) {
|
|
const c = readCalendar();
|
|
dateLabel = formatImperialDate(c);
|
|
realLabel = formatRealDate();
|
|
}
|
|
const safeContent = $('<div>').text(content).html().replace(/\n/g, '<br>');
|
|
const noteHtml = `<hr>
|
|
<h3>${realLabel} — ${dateLabel}</h3>
|
|
<p>${safeContent}</p>`;
|
|
let page = journal.pages.contents[0];
|
|
if (!page) {
|
|
[page] = await journal.createEmbeddedDocuments('JournalEntryPage', [{ name: 'Notes', text: { content: '' } }]);
|
|
}
|
|
if (!page) {
|
|
ui.notifications.error('Impossible de créer une page dans le journal');
|
|
return false;
|
|
}
|
|
const existing = page.text?.content || '';
|
|
await page.update({ 'text.content': existing + '\n' + noteHtml });
|
|
ui.notifications.info(`Note ajoutée au journal « ${journalName} »`);
|
|
return true;
|
|
}
|
|
|
|
function openJournalNote() {
|
|
const calendar = readCalendar();
|
|
const dateLabel = formatImperialDate(calendar);
|
|
const realLabel = formatRealDate();
|
|
const dialog = new JournalNoteDialog({
|
|
imperialDate: dateLabel,
|
|
realDate: realLabel,
|
|
onSave: async (content) => {
|
|
const ok = await appendJournalNote(content, { dateLabel, realLabel });
|
|
if (ok) dialog.close();
|
|
},
|
|
});
|
|
dialog.render({ force: true });
|
|
}
|
|
|
|
function registerCalCommand() {
|
|
if (!ChatLogV2?.CHAT_COMMANDS) return;
|
|
ChatLogV2.CHAT_COMMANDS.cal = {
|
|
rgx: /^\/cal(?:\s+(.*))?$/i,
|
|
fn: () => {
|
|
openCalendarApp();
|
|
return false;
|
|
},
|
|
};
|
|
console.log(`${MODULE_ID} | Commande /cal enregistrée via ChatLog.CHAT_COMMANDS`);
|
|
}
|
|
|
|
Hooks.once('init', () => {
|
|
const def = getDefaultCalendar();
|
|
|
|
game.settings.register(MODULE_ID, 'calendarYear', {
|
|
name: 'Année impériale',
|
|
scope: 'world',
|
|
config: false,
|
|
type: Number,
|
|
default: def.year,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarDay', {
|
|
name: 'Jour impérial (1-365)',
|
|
scope: 'world',
|
|
config: false,
|
|
type: Number,
|
|
default: def.day,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarHour', {
|
|
name: 'Heure locale',
|
|
scope: 'world',
|
|
config: false,
|
|
type: Number,
|
|
default: def.hour,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarMinute', {
|
|
name: 'Minute locale',
|
|
scope: 'world',
|
|
config: false,
|
|
type: Number,
|
|
default: def.minute,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarPlanet', {
|
|
name: 'Planète',
|
|
scope: 'world',
|
|
config: false,
|
|
type: String,
|
|
default: def.planet,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarAutoOpen', {
|
|
name: 'Calendrier impérial : auto-ouverture',
|
|
hint: 'Ouvre automatiquement la fenêtre du calendrier au démarrage',
|
|
scope: 'world',
|
|
config: true,
|
|
type: Boolean,
|
|
default: true,
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarJournalName', {
|
|
name: 'Journal de bord',
|
|
hint: 'Nom du journal utilisé pour les notes de session. Créé automatiquement s\'il n\'existe pas.',
|
|
scope: 'world',
|
|
config: true,
|
|
type: String,
|
|
default: 'Journal de bord',
|
|
});
|
|
game.settings.register(MODULE_ID, 'calendarPosition', {
|
|
scope: 'client',
|
|
config: false,
|
|
type: Object,
|
|
default: {},
|
|
});
|
|
|
|
const loadTemplatesFn = foundry.applications?.handlebars?.loadTemplates || loadTemplates;
|
|
if (loadTemplatesFn) {
|
|
loadTemplatesFn([
|
|
`modules/${MODULE_ID}/templates/calendar-app.hbs`,
|
|
`modules/${MODULE_ID}/templates/calendar-config.hbs`,
|
|
`modules/${MODULE_ID}/templates/journal-note-dialog.hbs`,
|
|
]);
|
|
}
|
|
|
|
registerCalCommand();
|
|
console.log(`${MODULE_ID} | Calendrier impérial initialisé`);
|
|
});
|
|
|
|
Hooks.once('ready', () => {
|
|
game.socket.on(`module.${MODULE_ID}`, (data) => {
|
|
if (game.user?.isGM) return;
|
|
if (data?._type !== 'calendarSync') return;
|
|
if (!_calendarApp) {
|
|
const { year, day, hour, minute, planet } = data;
|
|
_calendarApp = new CalendarApp({
|
|
onClose: () => { _calendarApp = null; },
|
|
});
|
|
_calendarApp.updateDisplay({ year, day, hour, minute, planet });
|
|
_calendarApp.render({ force: true });
|
|
return;
|
|
}
|
|
_calendarApp.updateDisplay(data);
|
|
});
|
|
|
|
if (game.settings.get(MODULE_ID, 'calendarAutoOpen')) {
|
|
openCalendarApp();
|
|
}
|
|
});
|
|
|
|
Hooks.on('preCreateChatMessage', (message, data, options) => {
|
|
const content = message.content?.trim()?.toLowerCase();
|
|
if (content === '/cal' || content?.startsWith('/cal ')) {
|
|
openCalendarApp();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
Hooks.on('chatMessage', (...args) => {
|
|
let message;
|
|
if (args[0]?.content !== undefined) {
|
|
message = args[0].content;
|
|
} else if (typeof args[1] === 'string') {
|
|
message = args[1];
|
|
} else {
|
|
return;
|
|
}
|
|
const trimmed = message?.trim()?.toLowerCase();
|
|
if (trimmed === '/cal' || trimmed?.startsWith('/cal ')) {
|
|
openCalendarApp();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
Hooks.on('renderChatInput', (app, html, data) => {
|
|
let input;
|
|
if (html?.element) {
|
|
input = $(html.element).find('textarea[name="content"]');
|
|
} else if (html?.find) {
|
|
input = html.find('textarea[name="content"]');
|
|
} else {
|
|
input = $(html).find('textarea[name="content"]');
|
|
}
|
|
if (input.data('mgt2-cal-listener')) return;
|
|
input.data('mgt2-cal-listener', true);
|
|
input.on('keydown', (event) => {
|
|
if (event.key === 'Enter' && !event.shiftKey) {
|
|
const content = input.val()?.trim();
|
|
if (content === '/cal' || content?.startsWith('/cal ')) {
|
|
event.preventDefault();
|
|
event.stopImmediatePropagation();
|
|
openCalendarApp();
|
|
input.val('');
|
|
}
|
|
}
|
|
});
|
|
});
|