mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 11:41:08 +01:00
* Refactor: handle button data attrs the same. A small refactor to handle `button.dataset.move` (which was assigned to a local const) and `button.dataset.category` (which was accessed directly) in the same way by assigning them both to local consts. * Fix right-click on downtime activities on macOS. On macOS with a single-button mouse (e.g. a laptop trackpad) it's common to trigger a right-click with ctrl+click. In Chrome, this triggers both a `contextmenu` event and a regular `click` event. In the context of downtime actions, this meant that we were deselecting an action in the `contextmenu` handler but then immediately re-selecting it again in the `click` handler. This commit works around the problem by stopping the event from propagating further. This fixes the bug, but also stops Foundry's default `contextmenu` handler from firing and preventing the browser context menu from appearing, so we also have prevent the event's default behaviour from firing.
168 lines
6.3 KiB
JavaScript
168 lines
6.3 KiB
JavaScript
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
|
|
|
export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV2) {
|
|
constructor(actor, shortrest) {
|
|
super({});
|
|
|
|
this.actor = actor;
|
|
this.shortrest = shortrest;
|
|
|
|
this.moveData = foundry.utils.deepClone(
|
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves
|
|
);
|
|
this.nrChoices = {
|
|
shortRest: {
|
|
max:
|
|
(shortrest ? this.moveData.shortRest.nrChoices : 0) +
|
|
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].shortMoves
|
|
},
|
|
longRest: {
|
|
max:
|
|
(!shortrest ? this.moveData.longRest.nrChoices : 0) +
|
|
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].longMoves
|
|
}
|
|
};
|
|
this.nrChoices.total = { max: this.nrChoices.shortRest.max + this.nrChoices.longRest.max };
|
|
}
|
|
|
|
get title() {
|
|
return '';
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
tag: 'form',
|
|
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'downtime'],
|
|
position: { width: 'auto', height: 'auto' },
|
|
actions: {
|
|
selectMove: this.selectMove,
|
|
takeDowntime: this.takeDowntime
|
|
},
|
|
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
|
};
|
|
|
|
static PARTS = {
|
|
application: {
|
|
id: 'downtime',
|
|
template: 'systems/daggerheart/templates/dialogs/downtime/downtime.hbs'
|
|
}
|
|
};
|
|
|
|
_attachPartListeners(partId, htmlElement, options) {
|
|
super._attachPartListeners(partId, htmlElement, options);
|
|
|
|
htmlElement
|
|
.querySelectorAll('.activity-container')
|
|
.forEach(element => element.addEventListener('contextmenu', this.deselectMove.bind(this)));
|
|
}
|
|
|
|
async _prepareContext(_options) {
|
|
const context = await super._prepareContext(_options);
|
|
context.title = game.i18n.localize(
|
|
`DAGGERHEART.APPLICATIONS.Downtime.${this.shortrest ? 'shortRest' : 'longRest'}.title`
|
|
);
|
|
context.selectedActivity = this.selectedActivity;
|
|
context.moveData = this.moveData;
|
|
context.nrCurrentChoices = Object.values(this.moveData).reduce((acc, category) => {
|
|
acc += Object.values(category.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
|
|
return acc;
|
|
}, 0);
|
|
|
|
context.nrChoices = {
|
|
...this.nrChoices,
|
|
shortRest: {
|
|
...this.nrChoices.shortRest,
|
|
current: Object.values(this.moveData.shortRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
|
|
},
|
|
longRest: {
|
|
...this.nrChoices.longRest,
|
|
current: Object.values(this.moveData.longRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
|
|
}
|
|
};
|
|
context.nrChoices.total = {
|
|
...this.nrChoices.total,
|
|
current: context.nrChoices.shortRest.current + context.nrChoices.longRest.current
|
|
};
|
|
|
|
context.shortRestMoves = this.nrChoices.shortRest.max > 0 ? this.moveData.shortRest : null;
|
|
context.longRestMoves = this.nrChoices.longRest.max > 0 ? this.moveData.longRest : null;
|
|
|
|
context.disabledDowntime = context.nrChoices.total.current < context.nrChoices.total.max;
|
|
|
|
return context;
|
|
}
|
|
|
|
static selectMove(_, target) {
|
|
const nrSelected = Object.values(this.moveData[target.dataset.category].moves).reduce(
|
|
(acc, x) => acc + (x.selected ?? 0),
|
|
0
|
|
);
|
|
|
|
if (nrSelected === this.nrChoices[target.dataset.category].max) {
|
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves'));
|
|
return;
|
|
}
|
|
|
|
const move = target.dataset.move;
|
|
this.moveData[target.dataset.category].moves[move].selected = this.moveData[target.dataset.category].moves[move]
|
|
.selected
|
|
? this.moveData[target.dataset.category].moves[move].selected + 1
|
|
: 1;
|
|
|
|
this.render();
|
|
}
|
|
|
|
deselectMove(event) {
|
|
const button = event.target.closest('.activity-container');
|
|
const { move, category } = button.dataset;
|
|
this.moveData[category].moves[move].selected = this.moveData[category].moves[move].selected
|
|
? this.moveData[category].moves[move].selected - 1
|
|
: 0;
|
|
|
|
this.render();
|
|
|
|
// On macOS with a single-button mouse (e.g. a laptop trackpad),
|
|
// right-click is triggered with ctrl+click, which triggers both a
|
|
// `contextmenu` event and a regular click event. We need to stop
|
|
// event propagation to prevent the click event from triggering the
|
|
// `selectMove` function and undoing the change we just made.
|
|
event.stopPropagation();
|
|
|
|
// Having stopped propagation, we're no longer subject to Foundry's
|
|
// default `contextmenu` handler, so we also have to prevent the
|
|
// default behaviour to prevent a context menu from appearing.
|
|
event.preventDefault();
|
|
}
|
|
|
|
static async takeDowntime() {
|
|
const moves = Object.values(this.moveData).flatMap(category => {
|
|
return Object.values(category.moves)
|
|
.filter(x => x.selected)
|
|
.flatMap(move => [...Array(move.selected).keys()].map(_ => move));
|
|
});
|
|
|
|
const cls = getDocumentClass('ChatMessage');
|
|
const msg = new cls({
|
|
user: game.user.id,
|
|
system: {
|
|
moves: moves,
|
|
actor: this.actor.uuid
|
|
},
|
|
content: await foundry.applications.handlebars.renderTemplate(
|
|
'systems/daggerheart/templates/ui/chat/downtime.hbs',
|
|
{
|
|
title: `${this.actor.name} - ${game.i18n.localize(`DAGGERHEART.APPLICATIONS.Downtime.${this.shortRest ? 'shortRest' : 'longRest'}.title`)}`,
|
|
moves: moves
|
|
}
|
|
)
|
|
});
|
|
|
|
cls.create(msg.toObject());
|
|
|
|
this.close();
|
|
}
|
|
|
|
static async updateData(event, element, formData) {
|
|
this.customActivity = foundry.utils.mergeObject(this.customActivity, formData.object);
|
|
this.render();
|
|
}
|
|
}
|