mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-17 15:39:02 +01:00
FEAT: add context menus for all inventory-items
This commit is contained in:
parent
633998ed0b
commit
7d67461184
9 changed files with 342 additions and 138 deletions
21
lang/en.json
21
lang/en.json
|
|
@ -104,15 +104,6 @@
|
||||||
"Character": {
|
"Character": {
|
||||||
"age": "Age",
|
"age": "Age",
|
||||||
"companionFeatures": "Companion Features",
|
"companionFeatures": "Companion Features",
|
||||||
"contextMenu": {
|
|
||||||
"consume": "Consume Item",
|
|
||||||
"equip": "Equip",
|
|
||||||
"sendToChat": "Send To Chat",
|
|
||||||
"toLoadout": "Send to Loadout",
|
|
||||||
"toVault": "Send to Vault",
|
|
||||||
"unequip": "Unequip",
|
|
||||||
"useItem": "Use Item"
|
|
||||||
},
|
|
||||||
"faith": "Faith",
|
"faith": "Faith",
|
||||||
"levelUp": "You can level up",
|
"levelUp": "You can level up",
|
||||||
"pronouns": "Pronouns",
|
"pronouns": "Pronouns",
|
||||||
|
|
@ -189,6 +180,16 @@
|
||||||
"requestingSpotlight": "Requesting The Spotlight",
|
"requestingSpotlight": "Requesting The Spotlight",
|
||||||
"requestSpotlight": "Request The Spotlight"
|
"requestSpotlight": "Request The Spotlight"
|
||||||
},
|
},
|
||||||
|
"ContextMenu": {
|
||||||
|
"disableEffect": "Disable Effect",
|
||||||
|
"enableEffect": "Enable Effect",
|
||||||
|
"equip": "Equip",
|
||||||
|
"sendToChat": "Send To Chat",
|
||||||
|
"toLoadout": "Send to Loadout",
|
||||||
|
"toVault": "Send to Vault",
|
||||||
|
"unequip": "Unequip",
|
||||||
|
"useItem": "Use Item"
|
||||||
|
},
|
||||||
"Countdown": {
|
"Countdown": {
|
||||||
"addCountdown": "Add Countdown",
|
"addCountdown": "Add Countdown",
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
|
|
@ -1372,6 +1373,8 @@
|
||||||
"damageIgnore": "{character} did not take damage"
|
"damageIgnore": "{character} did not take damage"
|
||||||
},
|
},
|
||||||
"Tooltip": {
|
"Tooltip": {
|
||||||
|
"disableEffect": "Disable Effect",
|
||||||
|
"enableEffect": "Enable Effect",
|
||||||
"openItemWorld": "Open Item World",
|
"openItemWorld": "Open Item World",
|
||||||
"openActorWorld": "Open Actor World",
|
"openActorWorld": "Open Actor World",
|
||||||
"sendToChat": "Send to Chat",
|
"sendToChat": "Send to Chat",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
classes: ['character'],
|
classes: ['character'],
|
||||||
position: { width: 850, height: 800 },
|
position: { width: 850, height: 800 },
|
||||||
actions: {
|
actions: {
|
||||||
triggerContextMenu: CharacterSheet.#triggerContextMenu,
|
|
||||||
toggleVault: CharacterSheet.#toggleVault,
|
toggleVault: CharacterSheet.#toggleVault,
|
||||||
rollAttribute: CharacterSheet.#rollAttribute,
|
rollAttribute: CharacterSheet.#rollAttribute,
|
||||||
toggleHope: CharacterSheet.#toggleHope,
|
toggleHope: CharacterSheet.#toggleHope,
|
||||||
|
|
@ -29,16 +28,30 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
resizable: true
|
resizable: true
|
||||||
},
|
},
|
||||||
dragDrop: [],
|
dragDrop: [],
|
||||||
contextMenus: [
|
contextMenus: [{
|
||||||
{
|
handler: CharacterSheet.#getDomainCardContextOptions,
|
||||||
handler: CharacterSheet._getContextMenuOptions,
|
selector: '[data-item-uuid][data-type="domainCard"]',
|
||||||
selector: '[data-item-uuid]',
|
options: {
|
||||||
options: {
|
parentClassHooks: false,
|
||||||
parentClassHooks: false,
|
fixed: true
|
||||||
fixed: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
handler: CharacterSheet.#getEquipamentContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="armor"], [data-item-uuid][data-type="weapon"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handler: CharacterSheet.#getItemContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="consumable"], [data-item-uuid][data-type="miscellaneous"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
/**@override */
|
/**@override */
|
||||||
|
|
@ -208,77 +221,70 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options.
|
* Get the set of ContextMenu options for DomainCards.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
* @this {CharacterSheet}
|
* @this {CharacterSheet}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
static _getContextMenuOptions() {
|
static #getDomainCardContextOptions() {
|
||||||
return [
|
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||||
|
const options = [
|
||||||
{
|
{
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.useItem',
|
name: 'toLoadout',
|
||||||
icon: '<i class="fa-solid fa-burst"></i>',
|
icon: 'fa-solid fa-arrow-up',
|
||||||
condition: target => {
|
condition: target => getDocFromElement(target).system.inVault,
|
||||||
const doc = getDocFromElement(target);
|
|
||||||
return typeof doc.use === 'function';
|
|
||||||
},
|
|
||||||
callback: (target, event) => getDocFromElement(target).use(event)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.equip',
|
|
||||||
icon: '<i class="fa-solid fa-hands"></i>',
|
|
||||||
condition: target => {
|
|
||||||
const item = getDocFromElement(target);
|
|
||||||
return ['weapon', 'armor'].includes(item.type) && !item.system.equipped;
|
|
||||||
},
|
|
||||||
callback: CharacterSheet.#toggleEquipItem.bind(this)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.unequip',
|
|
||||||
icon: '<i class="fa-solid fa-hands"></i>',
|
|
||||||
condition: el => {
|
|
||||||
const item = getDocFromElement(el);
|
|
||||||
return ['weapon', 'armor'].includes(item.type) && item.system.equipped;
|
|
||||||
},
|
|
||||||
callback: CharacterSheet.#toggleEquipItem.bind(this)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.toLoadout',
|
|
||||||
icon: '<i class="fa-solid fa-arrow-up"></i>',
|
|
||||||
condition: target => {
|
|
||||||
const item = getDocFromElement(target);
|
|
||||||
return ['domainCard'].includes(item.type) && item.system.inVault;
|
|
||||||
},
|
|
||||||
callback: target => getDocFromElement(target).update({ 'system.inVault': false })
|
callback: target => getDocFromElement(target).update({ 'system.inVault': false })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.toVault',
|
name: 'toVault',
|
||||||
icon: '<i class="fa-solid fa-arrow-down"></i>',
|
icon: 'fa-solid fa-arrow-down',
|
||||||
condition: target => {
|
condition: target => !getDocFromElement(target).system.inVault,
|
||||||
const item = getDocFromElement(target);
|
|
||||||
return ['domainCard'].includes(item.type) && !item.system.inVault;
|
|
||||||
},
|
|
||||||
callback: target => getDocFromElement(target).update({ 'system.inVault': true })
|
callback: target => getDocFromElement(target).update({ 'system.inVault': true })
|
||||||
},
|
},
|
||||||
{
|
].map(option => ({
|
||||||
name: 'DAGGERHEART.ACTORS.Character.contextMenu.sendToChat',
|
...option,
|
||||||
icon: '<i class="fa-regular fa-message"></i>',
|
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||||
condition: target => {
|
icon: `<i class="${option.icon}"></i>`
|
||||||
return typeof getDocFromElement(target).toChat === 'function';
|
}));
|
||||||
},
|
|
||||||
callback: (target) => getDocFromElement(target).toChat(this.document.id),
|
return [...options, ...this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true })];
|
||||||
},
|
}
|
||||||
{
|
|
||||||
name: 'CONTROLS.CommonEdit',
|
/**
|
||||||
icon: '<i class="fa-solid fa-pen-to-square"></i>',
|
* Get the set of ContextMenu options for Armors and Weapons.
|
||||||
callback: target => getDocFromElement(target).sheet.render({ force: true })
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
},
|
* @this {CharacterSheet}
|
||||||
{
|
* @protected
|
||||||
name: 'CONTROLS.CommonDelete',
|
*/
|
||||||
icon: '<i class="fa-solid fa-trash"></i>',
|
static #getEquipamentContextOptions() {
|
||||||
callback: async el => getDocFromElement(el).deleteDialog(),
|
const options = [{
|
||||||
}
|
name: 'equip',
|
||||||
];
|
icon: 'fa-solid fa-hands',
|
||||||
|
condition: target => !getDocFromElement(target).system.equipped,
|
||||||
|
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'unequip',
|
||||||
|
icon: 'fa-solid fa-hands',
|
||||||
|
condition: target => getDocFromElement(target).system.equipped,
|
||||||
|
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target),
|
||||||
|
}].map(option => ({
|
||||||
|
...option,
|
||||||
|
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||||
|
icon: `<i class="${option.icon}"></i>`
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [...options, ...this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true })];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of ContextMenu options for Consumable and Miscellaneous.
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
* @this {CharacterSheet}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
static #getItemContextOptions() {
|
||||||
|
return this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true });
|
||||||
}
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Filter Tracking */
|
/* Filter Tracking */
|
||||||
|
|
@ -532,7 +538,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
this.document.diceRoll(config);
|
this.document.diceRoll(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: redo toggleEquipItem method
|
//TODO: redo toggleEquipItem method
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -593,14 +599,6 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
await doc?.update({ 'system.inVault': !doc.system.inVault });
|
await doc?.update({ 'system.inVault': !doc.system.inVault });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger the context menu.
|
|
||||||
* @type {ApplicationClickAction}
|
|
||||||
*/
|
|
||||||
static #triggerContextMenu(event, _) {
|
|
||||||
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDrop(event) {
|
async _onDrop(event) {
|
||||||
super._onDrop(event);
|
super._onDrop(event);
|
||||||
this._onDropItem(event, TextEditor.getDragEventData(event));
|
this._onDropItem(event, TextEditor.getDragEventData(event));
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { getDocFromElement, tagifyElement } from '../../../helpers/utils.mjs';
|
||||||
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('@client/applications/_types.mjs').ApplicationClickAction}
|
* @typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,13 +76,30 @@ export default function DHApplicationMixin(Base) {
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
classes: ['daggerheart', 'sheet', 'dh-style'],
|
classes: ['daggerheart', 'sheet', 'dh-style'],
|
||||||
actions: {
|
actions: {
|
||||||
|
triggerContextMenu: DHSheetV2.#triggerContextMenu,
|
||||||
createDoc: DHSheetV2.#createDoc,
|
createDoc: DHSheetV2.#createDoc,
|
||||||
editDoc: DHSheetV2.#editDoc,
|
editDoc: DHSheetV2.#editDoc,
|
||||||
deleteDoc: DHSheetV2.#deleteDoc,
|
deleteDoc: DHSheetV2.#deleteDoc,
|
||||||
toChat: DHSheetV2.#toChat,
|
toChat: DHSheetV2.#toChat,
|
||||||
useItem: DHSheetV2.#useItem,
|
useItem: DHSheetV2.#useItem,
|
||||||
|
toggleEffect: DHSheetV2.#toggleEffect,
|
||||||
},
|
},
|
||||||
contextMenus: [],
|
contextMenus: [{
|
||||||
|
handler: DHSheetV2.#getEffectContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="effect"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handler: DHSheetV2.#getActionContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="action"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
}],
|
||||||
dragDrop: [],
|
dragDrop: [],
|
||||||
tagifyConfigs: []
|
tagifyConfigs: []
|
||||||
};
|
};
|
||||||
|
|
@ -192,12 +209,134 @@ export default function DHApplicationMixin(Base) {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options which should be used for journal entry pages in the sidebar.
|
* Get the set of ContextMenu options for DomainCards.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]}
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
* @this {CharacterSheet}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
_getEntryContextOptions() {
|
static #getEffectContextOptions() {
|
||||||
return [];
|
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
name: 'disableEffect',
|
||||||
|
icon: 'fa-solid fa-lightbulb',
|
||||||
|
condition: target => !getDocFromElement(target).disabled,
|
||||||
|
callback: target => getDocFromElement(target).update({ disabled: true })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'enableEffect',
|
||||||
|
icon: 'fa-regular fa-lightbulb',
|
||||||
|
condition: target => getDocFromElement(target).disabled,
|
||||||
|
callback: target => getDocFromElement(target).update({ disabled: false })
|
||||||
|
},
|
||||||
|
].map(option => ({
|
||||||
|
...option,
|
||||||
|
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||||
|
icon: `<i class="${option.icon}"></i>`
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [...options, ...this._getContextMenuCommonOptions.call(this, { toChat: true })];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of ContextMenu options for Actions.
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
* @this {DHSheetV2}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
static #getActionContextOptions() {
|
||||||
|
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||||
|
const getAction = (target) => {
|
||||||
|
const { actionId } = target.closest('[data-action-id]').dataset;
|
||||||
|
const { actions, attack } = this.document.system;
|
||||||
|
return attack.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||||
|
icon: 'fa-solid fa-burst',
|
||||||
|
callback: (target, event) => getAction(target).use(event),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
||||||
|
icon: 'fa-solid fa-message',
|
||||||
|
callback: (target) => getAction(target).toChat(this.document.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CONTROLS.CommonEdit',
|
||||||
|
icon: 'fa-solid fa-pen-to-square',
|
||||||
|
callback: (target) => new DHActionConfig(getAction(target)).render({ force: true })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CONTROLS.CommonDelete',
|
||||||
|
icon: 'fa-solid fa-trash',
|
||||||
|
condition: (target) => {
|
||||||
|
const { actionId } = target.closest('[data-action-id]').dataset;
|
||||||
|
const { attack } = this.document.system;
|
||||||
|
return attack.id !== actionId
|
||||||
|
},
|
||||||
|
callback: async (target) => {
|
||||||
|
const action = getAction(target)
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||||
|
type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
|
||||||
|
name: action.name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: action.name })
|
||||||
|
});
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
return this.document.update({
|
||||||
|
'system.actions': this.document.system.actions.do.filter((a) => a.id !== action.id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
].map(option => ({
|
||||||
|
...option,
|
||||||
|
icon: `<i class="${option.icon}"></i>`
|
||||||
|
}));
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of ContextMenu options.
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
*/
|
||||||
|
_getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) {
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
name: 'CONTROLS.CommonEdit',
|
||||||
|
icon: 'fa-solid fa-pen-to-square',
|
||||||
|
callback: target => getDocFromElement(target).sheet.render({ force: true })
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (usable) options.unshift({
|
||||||
|
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||||
|
icon: 'fa-solid fa-burst',
|
||||||
|
callback: (target, event) => getDocFromElement(target).use(event),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (toChat) options.unshift({
|
||||||
|
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
||||||
|
icon: 'fa-solid fa-message',
|
||||||
|
callback: (target) => getDocFromElement(target).toChat(this.document.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deletable) options.push({
|
||||||
|
name: 'CONTROLS.CommonDelete',
|
||||||
|
icon: 'fa-solid fa-trash',
|
||||||
|
callback: target => getDocFromElement(target).deleteDialog(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return options.map(option => ({
|
||||||
|
...option,
|
||||||
|
icon: `<i class="${option.icon}"></i>`
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
@ -270,7 +409,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
const doc = await cls.create(data, { parent, renderSheet: !event.shiftKey });
|
const doc = await cls.create(data, { parent, renderSheet: !event.shiftKey });
|
||||||
if (parentIsItem && type === 'feature') {
|
if (parentIsItem && type === 'feature') {
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.features': [...this.document.system.features, doc]
|
'system.features': this.document.system.toObject().features.concat(doc.uuid)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
|
|
@ -357,6 +496,23 @@ export default function DHApplicationMixin(Base) {
|
||||||
await doc.use(event);
|
await doc.use(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle a ActiveEffect
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static async #toggleEffect(_, target) {
|
||||||
|
const doc = getDocFromElement(target);
|
||||||
|
await doc.update({ disabled: !doc.disabled });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger the context menu.
|
||||||
|
* @type {ApplicationClickAction}
|
||||||
|
*/
|
||||||
|
static #triggerContextMenu(event, _) {
|
||||||
|
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DHSheetV2;
|
return DHSheetV2;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,16 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||||
openSettings: DHBaseActorSheet.#openSettings,
|
openSettings: DHBaseActorSheet.#openSettings,
|
||||||
sendExpToChat: DHBaseActorSheet.#sendExpToChat,
|
sendExpToChat: DHBaseActorSheet.#sendExpToChat,
|
||||||
},
|
},
|
||||||
|
contextMenus: [
|
||||||
|
{
|
||||||
|
handler: DHBaseActorSheet.#getFeatureContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="feature"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
dragDrop: []
|
dragDrop: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -80,6 +90,21 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Context Menu */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of ContextMenu options for Features.
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
* @this {DHSheetV2}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
static #getFeatureContextOptions() {
|
||||||
|
return this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
import { getDocFromElement } from '../../../helpers/utils.mjs';
|
||||||
import DHApplicationMixin from './application-mixin.mjs';
|
import DHApplicationMixin from './application-mixin.mjs';
|
||||||
|
|
||||||
const { ItemSheetV2 } = foundry.applications.sheets;
|
const { ItemSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
@ -21,12 +21,21 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
removeAction: DHBaseItemSheet.#removeAction,
|
removeAction: DHBaseItemSheet.#removeAction,
|
||||||
addFeature: DHBaseItemSheet.#addFeature,
|
addFeature: DHBaseItemSheet.#addFeature
|
||||||
removeFeature: DHBaseItemSheet.#removeFeature
|
|
||||||
},
|
},
|
||||||
dragDrop: [
|
dragDrop: [
|
||||||
{ dragSelector: null, dropSelector: '.tab.features .drop-section' },
|
{ dragSelector: null, dropSelector: '.tab.features .drop-section' },
|
||||||
{ dragSelector: '.feature-item', dropSelector: null }
|
{ dragSelector: '.feature-item', dropSelector: null }
|
||||||
|
],
|
||||||
|
contextMenus: [
|
||||||
|
{
|
||||||
|
handler: DHBaseItemSheet.#getFeatureContextOptions,
|
||||||
|
selector: '[data-item-uuid][data-type="feature"]',
|
||||||
|
options: {
|
||||||
|
parentClassHooks: false,
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -62,6 +71,9 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
case "effects":
|
case "effects":
|
||||||
await this._prepareEffectsContext(context, options)
|
await this._prepareEffectsContext(context, options)
|
||||||
break;
|
break;
|
||||||
|
case "features":
|
||||||
|
context.isGM = game.user.isGM;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
@ -87,9 +99,46 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Application Clicks Actions */
|
/* Context Menu */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of ContextMenu options for Features.
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
|
* @this {DHSheetV2}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
static #getFeatureContextOptions() {
|
||||||
|
const options = this._getContextMenuCommonOptions({ usable: true, toChat: true, deletable: false })
|
||||||
|
options.push(
|
||||||
|
{
|
||||||
|
name: 'CONTROLS.CommonDelete',
|
||||||
|
icon: '<i class="fa-solid fa-trash"></i>',
|
||||||
|
callback: async (target) => {
|
||||||
|
const feature = getDocFromElement(target);
|
||||||
|
if (!feature) return;
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||||
|
type: game.i18n.localize(`TYPES.Item.feature`),
|
||||||
|
name: feature.name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: feature.name })
|
||||||
|
});
|
||||||
|
if (!confirmed) return;
|
||||||
|
await this.document.update({
|
||||||
|
'system.features': this.document.system.toObject().features.filter(uuid => uuid !== feature.uuid)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Application Clicks Actions */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an action from the item.
|
* Remove an action from the item.
|
||||||
|
|
@ -130,36 +179,6 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
'system.features': [...this.document.system.features, feature]
|
'system.features': [...this.document.system.features, feature]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a feature from the item.
|
|
||||||
* @type {ApplicationClickAction}
|
|
||||||
*/
|
|
||||||
static async #removeFeature(event, button) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const target = button.closest('.feature-item');
|
|
||||||
const feature = this.document.system.features.find(x => x && x.id === target.id);
|
|
||||||
|
|
||||||
if (feature) {
|
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
|
||||||
window: {
|
|
||||||
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
|
||||||
type: game.i18n.localize(`TYPES.Item.feature`),
|
|
||||||
name: feature.name
|
|
||||||
})
|
|
||||||
},
|
|
||||||
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: feature.name })
|
|
||||||
});
|
|
||||||
if (!confirmed) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': this.document.system.features
|
|
||||||
.filter(feature => feature && feature.id !== target.id)
|
|
||||||
.map(x => x.uuid)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Application Drag/Drop */
|
/* Application Drag/Drop */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ export default class DHContextMenu extends foundry.applications.ux.ContextMenu {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const { clientX, clientY } = event;
|
const { clientX, clientY } = event;
|
||||||
const selector = '[data-item-id]';
|
const selector = '[data-item-uuid]';
|
||||||
const target = event.target.closest(selector) ?? event.currentTarget.closest(selector);
|
const target = event.target.closest(selector) ?? event.currentTarget.closest(selector);
|
||||||
target?.dispatchEvent(
|
target?.dispatchEvent(
|
||||||
new PointerEvent('contextmenu', {
|
new PointerEvent('contextmenu', {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
</h4>
|
</h4>
|
||||||
{{#unless hideContrals}}
|
{{#unless hideContrals}}
|
||||||
<div class='controls'>
|
<div class='controls'>
|
||||||
<a class='effect-control' data-action='editDoc' data-action-path='{{actionPath}}'
|
<a class='effect-control' data-action='editDoc' data-tooltip="DAGGERHEART.UI.Tooltip.openItemWorld">
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.openItemWorld">
|
|
||||||
<i class="fa-solid fa-globe"></i>
|
<i class="fa-solid fa-globe"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class='effect-control' data-action='deleteFeature' data-item-uuid='{{feature.uuid}}' data-action-path='{{actionPath}}'
|
<a class='effect-control' data-action='deleteFeature' data-item-uuid='{{feature.uuid}}' data-action-path='{{actionPath}}'
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ Parameters:
|
||||||
- hideDescription {boolean} : If true, hides the item's description.
|
- hideDescription {boolean} : If true, hides the item's description.
|
||||||
--}}
|
--}}
|
||||||
|
|
||||||
<li class="inventory-item" {{#if (eq type 'action' ) }}data-action-id="{{item.id}}" {{/if}}
|
<li class="inventory-item" {{#if (eq type 'action' )}}data-action-id="{{item.id}}"{{/if}}
|
||||||
data-item-uuid="{{item.uuid}}">
|
data-item-uuid="{{item.uuid}}" data-type="{{type}}">
|
||||||
{{!-- Image --}}
|
{{!-- Image --}}
|
||||||
<img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}"
|
<img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}"
|
||||||
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}}
|
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}}
|
||||||
|
|
@ -172,6 +172,11 @@ Parameters:
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
||||||
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
||||||
</a>
|
</a>
|
||||||
|
{{else if (eq type 'effect')}}
|
||||||
|
<a data-action="toggleEffect"
|
||||||
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.disabled 'enableEffect' 'disableEffect' }}">
|
||||||
|
<i class="{{ifThen item.disabled 'fa-regular fa-lightbulb' 'fa-solid fa-lightbulb'}}"></i>
|
||||||
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}}
|
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}}
|
||||||
{{#unless (not item.toChat)}}
|
{{#unless (not item.toChat)}}
|
||||||
|
|
@ -179,7 +184,6 @@ Parameters:
|
||||||
<i class="fa-regular fa-message"></i>
|
<i class="fa-regular fa-message"></i>
|
||||||
</a>
|
</a>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<a data-action="triggerContextMenu" data-tooltip="DAGGERHEART.UI.Tooltip.moreOptions">
|
<a data-action="triggerContextMenu" data-tooltip="DAGGERHEART.UI.Tooltip.moreOptions">
|
||||||
<i class="fa-solid fa-ellipsis-vertical"></i>
|
<i class="fa-solid fa-ellipsis-vertical"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,6 @@
|
||||||
type='feature'
|
type='feature'
|
||||||
isGlassy=true
|
isGlassy=true
|
||||||
collection=document.system.features
|
collection=document.system.features
|
||||||
canCreate=true
|
canCreate=(or document.parent isGM)
|
||||||
}}
|
}}
|
||||||
</section>
|
</section>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue