Skip to content

Commit

Permalink
Fixed bugs, added minor API method
Browse files Browse the repository at this point in the history
  • Loading branch information
Haxxer committed Jun 1, 2023
1 parent c8f4832 commit 05a4e15
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 13 deletions.
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Item Piles Changelog

## Version 2.6.14

- Added `game.itempiles.API.unrenderItemPileInterface` which can be used to remotely close item pile interfaces for players
- Fixed opening document sheets in compendiums would throw error and fail to open (Foundry v11)
- Fixed hovering over vault items sometimes throwing errors in the console
- Fixed not having any hotkeys configured would throw errors when opening item pile UIs

## Version 2.6.13

- Updated Portuguese (Brazil) localization (thank you mclemente on Weblate!)
Expand Down
17 changes: 17 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* [deleteItemPile](#deleteItemPile)
* [splitItemPileContents](#splitItemPileContents)
* [renderItemPileInterface](#renderItemPileInterface)
* [unrenderItemPileInterface](#unrenderItemPileInterface)


* [Item and attribute methods](#item-and-attribute-methods)
Expand Down Expand Up @@ -566,6 +567,22 @@ Renders the appropriate interface for a given actor.

---

### unrenderItemPileInterface

`game.itempiles.API.unrenderItemPileInterface(target, options)``Promise`

Closes any open interfaces from a given item pile actor

**Returns**: `Promise` - Returns a promise that resolves when all interfaces have been closed.

| Param | Type | Description |
|--------------------------|-----------------------|-------------------------------------|
| target | `Actor/TokenDocument` | The actor whose interface to potentially close |
| options | `object` | Options to pass to the function |
| [options.userIds] | `Array<User/string>` | `false` | An array of users or user ids for each user to close the interface for (defaults to only self) |

---

## Item and attribute methods

### addItems
Expand Down
51 changes: 51 additions & 0 deletions src/API/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1881,6 +1881,57 @@ class API {

}

/**
* Closes any open interfaces from a given item pile actor
*
* @param {Actor/TokenDocument} target The actor whose interface to potentially close
* @param {object} options An object containing the options for this method
* @param {Array<string/User>} [options.userIds] An array of users or user ids for each user to close the interface for (defaults to only self)
*
* @returns {Promise}
*/
static unrenderItemPileInterface(target, { userIds = null } = {}) {

const targetDocument = Utilities.getDocument(target);
const targetUuid = Utilities.getUuid(targetDocument);
if (!targetUuid) throw Helpers.custom_error(`unrenderItemPileInterface | Could not determine the UUID, please provide a valid target item pile`);

if (!PileUtilities.isValidItemPile(targetDocument)) {
throw Helpers.custom_error("unrenderItemPileInterface | This target is not a valid item pile")
}

if (!Array.isArray(userIds)) {
if (userIds === null) {
userIds = [game.user.id];
} else {
userIds = [userIds]
}
} else {
userIds = userIds.map(user => {
return user instanceof User ? user.id : user;
})
}

if (!game.user.isGM) {
if (userIds.length > 1 || !userIds.includes(game.user.id)) {
throw Helpers.custom_error(`unrenderItemPileInterface | You are not a GM, so you cannot force others to close an item pile's interface`);
}
userIds = [game.user.id];
}

if (userIds.length === 1 && userIds[0] === game.user.id) {
return PrivateAPI._unrenderItemPileInterface(targetUuid, { remote: true });
}

for (const userId of userIds) {
const user = game.users.get(userId);
if (!user) throw Helpers.custom_error(`unrenderItemPileInterface | No user with ID "${userId}" exists`);
}

return ItemPileSocket.executeForUsers(ItemPileSocket.HANDLERS.UNRENDER_INTERFACE, userIds, targetUuid, { remote: true });

}

/**
* Get the prices array for a given item
*
Expand Down
10 changes: 10 additions & 0 deletions src/API/private-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2134,6 +2134,16 @@ export default class PrivateAPI {

}

static async _unrenderItemPileInterface(targetUuid, { remote = false } = {}) {

const target = Utilities.getActor(targetUuid);

return Promise.allSettled(Object.values(ui.windows).filter(app => {
return app.id.includes(`-${target.id}-`) || app?.actor === target || app?.merchant === target;
}).map(app => app.close()));

}

static async _tradeItems(sellerUuid, buyerUuid, items, userId, { interactionId = false } = {}) {

const sellingActor = Utilities.getActor(sellerUuid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
.map(item => {
return {
_id: item.id,
quantity: settings.getUpdates ? Math.max(0, Math.min(item.quantity, item.currentQuantity - item.quantity)) : item.currentQuantity
quantity: settings.getUpdates ? Math.min(item.quantity, item.currentQuantity - item.quantity) : item.currentQuantity
}
})
Expand Down
5 changes: 2 additions & 3 deletions src/foundry-ui-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,9 @@ class FastTooltipManager extends TooltipManager {
if (!element.dataset.fastTooltip) {
// Check if the element has moved out from underneath the cursor and pointerenter has fired on a non-child of the
// tooltipped element.
if (this.#active && !this.element.contains(element)) this.#startDeactivation();
if (this.#active && this.element && !this.element.contains(element)) this.#startDeactivation();
return;
}
console.log(element.dataset.fastTooltip)

// Don't activate tooltips if the element contains an active context menu
if (element.matches("#context-menu") || element.querySelector("#context-menu")) return;
Expand All @@ -293,7 +292,7 @@ class FastTooltipManager extends TooltipManager {
// Mark the element as active
this.#active = true;
this.element = element;
element.setAttribute("aria-describedby", "tooltip");
element.setAttribute("aria-describedby", "fast-tooltip");
this.tooltip.innerHTML = text || game.i18n.localize(element.dataset.fastTooltip);

// Activate display of the tooltip
Expand Down
12 changes: 9 additions & 3 deletions src/hotkeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ const HOTKEYS = {

export const hotkeyActionState = {
get openPileInventory() {
const down = window.keyboard.downKeys.has(game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.FORCE_DEFAULT_SHEET)[0].key);
const down = game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.FORCE_DEFAULT_SHEET).some(key => {
return window.keyboard.downKeys.has(key);
});
return (
(!down && !game.settings.get(CONSTANTS.MODULE_NAME, "invertSheetOpen"))
||
Expand All @@ -19,11 +21,15 @@ export const hotkeyActionState = {
},

get forceDropItem() {
return window.keyboard.downKeys.has(game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.DROP)[0].key);
return game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.DROP).some(key => {
return window.keyboard.downKeys.has(key);
});
},

get forceDropOneItem() {
return window.keyboard.downKeys.has(game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.DROP_ONE)[0].key);
return game.keybindings.get(CONSTANTS.MODULE_NAME, HOTKEYS.DROP).some(key => {
return window.keyboard.downKeys.has(key);
});
}
}

Expand Down
13 changes: 7 additions & 6 deletions src/libwrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ export default function registerLibwrappers() {

libWrapper.register(CONSTANTS.MODULE_NAME, overrideMethod, function (wrapped, event) {
event.preventDefault();
const element = event.currentTarget;
const documentId = element.parentElement.dataset.documentId;
const document = this.constructor.collection.get(documentId);
if (PileUtilities.isValidItemPile(document)) {
const hookResult = Helpers.hooks.call(CONSTANTS.HOOKS.PILE.PRE_DIRECTORY_CLICK, document);
if (hookResult === false) return false;
if (!(this instanceof Compendium)) {
const documentId = element.parentElement.dataset.documentId;
const document = this.constructor.collection.get(documentId);
if (PileUtilities.isValidItemPile(document)) {
const hookResult = Helpers.hooks.call(CONSTANTS.HOOKS.PILE.PRE_DIRECTORY_CLICK, document);
if (hookResult === false) return false;
}
}
return wrapped(event);
}, "MIXED");
Expand Down
2 changes: 2 additions & 0 deletions src/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default class ItemPileSocket {
* UI sockets
*/
RENDER_INTERFACE: "renderItemPileApplication",
UNRENDER_INTERFACE: "unrenderItemPileApplication",
RERENDER_TOKEN_HUD: "rerenderTokenHud",
USER_OPENED_INTERFACE: "userOpenedInterface",
USER_CLOSED_INTERFACE: "userClosedInterface",
Expand Down Expand Up @@ -150,6 +151,7 @@ export default class ItemPileSocket {
[this.HANDLERS.DISABLE_CHAT_TRADE_BUTTON]: (...args) => ChatAPI._disableTradingButton(...args),

[this.HANDLERS.RENDER_INTERFACE]: (...args) => PrivateAPI._renderItemPileInterface(...args),
[this.HANDLERS.UNRENDER_INTERFACE]: (...args) => PrivateAPI._unrenderItemPileInterface(...args),
[this.HANDLERS.RERENDER_TOKEN_HUD]: (...args) => PrivateAPI._updateTokenHud(...args),
[this.HANDLERS.USER_OPENED_INTERFACE]: (...args) => InterfaceTracker.userOpened(...args),
[this.HANDLERS.USER_CLOSED_INTERFACE]: (...args) => InterfaceTracker.userClosed(...args),
Expand Down

0 comments on commit 05a4e15

Please sign in to comment.