Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] Correctly creating link anchors in TextEditor & dragging items to hotbar #304

Merged
merged 12 commits into from
Jan 18, 2023
70 changes: 70 additions & 0 deletions src/e2e/actor/createItemMacro.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { createOseMacro } from '../../module/macros';
import { trashChat, waitForInput } from '../testUtils';


export const key = 'ose.actor.macro';
export const options = {
displayName: 'The Character Sheet: Item Macros'
};

export default ({ before, beforeEach, after, describe, it, expect, assert, ...context }) => {
const testCharacterName = 'Quench Test Character';
const prepareActor = async (data) => {
await trashChat();
await trashActor();

return Actor.create({
...data,
name: testCharacterName,
type: 'character'
});
};
const testActor = () => game.actors.getName(testCharacterName);
const trashActor = () => testActor()?.delete();
const trashMacro = async () => {
await game.macros.find(o => o.name === "Test Macro Item")?.delete();
await game.user.assignHotbarMacro(null, 1);
}
const createItem = (type) => { return testActor()?.createEmbeddedDocuments("Item", [{ type: type, name: "Test Macro Item" }]) };

const createItemMacroData = (item) => {
const dragData = item.toDragData();
dragData.item = item;
dragData.type = "Item"
return dragData
};

const canCreate = async (type) => {
await createItem(type);
const item = testActor().items.contents[0];
const data = createItemMacroData(item);
const macro = await createOseMacro(data, 1);
await waitForInput();

const createdMacro = game.user.getHotbarMacros()[0];
expect(createdMacro?.macro?.command.indexOf("game.ose.rollItemMacro")).not.equal(-1)
}

before(async () => {
await trashChat();
})

describe('Item Macro', () => {
before(async () => {
await prepareActor();
trashMacro();
})

after(async () => {
await trashChat();
await trashActor();
})

afterEach(() => {
trashMacro();
})

it('Create weapon macro', async () => { await canCreate("weapon") })
it('Create spell macro', async () => { await canCreate("spell") })
})
};
8 changes: 7 additions & 1 deletion src/e2e/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import characterItemMacroTests, {
key as characterItemMacroKey,
options as characterItemMacroOptions
} from './actor/createItemMacro.test';

import characterTests, {
key as characterKey,
options as characterOptions
Expand Down Expand Up @@ -46,7 +51,8 @@ type Quench = {
}

Hooks.on('quenchReady', async (quench: Quench) => {
quench.registerBatch(characterKey, characterTests, characterOptions)
quench.registerBatch(characterItemMacroKey, characterItemMacroTests, characterItemMacroOptions);
quench.registerBatch(characterKey, characterTests, characterOptions);
// Character data model classes
quench.registerBatch(dataModelCharacterACKey, dataModelCharacterACTests, dataModelCharacterACOptions);
quench.registerBatch(dataModelCharacterScoresKey, dataModelCharacterScoresTests, dataModelCharacterScoresOptions);
Expand Down
4 changes: 3 additions & 1 deletion src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,9 @@
"OSE.CombatFlag.SpellDeclared": "Spell Declared",
"OSE.CombatFlag.RetreatFromMeleeDeclared": "Retreat From Melee Declared",

"OSE.warn.moreThanOneItemWithName": "Your controlled Actor {actorName} has more than one Item with name ${itemName}. The first matched Item will be chosen.",
"OSE.warn.moreThanOneItemWithName": "Your controlled Actor {actorName} has more than one Item with name {itemName}. The first matched Item will be chosen.",
"OSE.warn.macrosOnlyForOwnedItems": "Only Items owned by Actor may be used to create macros.",
"OSE.warn.macrosNoTokenOwnedInScene": "No controlled token in scene",

"OSE.error.macrosOnlyForOwnedItems": "You can only create macro buttons for owned Items",
"OSE.error.noItemWithName": "Your controlled Actor {actorName} does not have an item named {itemName}.",
Expand Down
19 changes: 10 additions & 9 deletions src/module/actor/actor-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,25 +227,26 @@ export class OseActorSheet extends ActorSheet {
let itemIdsArray = [];
if (event.target.classList.contains("content-link")) return;

// Create drag data
const dragData = {
actorId: this.actor.id,
sceneId: this.actor.isToken ? canvas.scene?.id : null,
tokenId: this.actor.isToken ? this.actor.token.id : null,
pack: this.actor.pack,
};
let dragData;

// Owned Items
if (li.dataset.itemId) {
const item = this.actor.items.get(li.dataset.itemId);
dragData.type = "Item";
dragData.data = item;
dragData = item.toDragData();
dragData.item = item;
dragData.type = "Item";
if (item.type === "container" && item.system.itemIds.length) {
//otherwise JSON.stringify will quadruple stringify for some reason
itemIdsArray = item.system.itemIds;
}
}

// Create drag data
dragData.actorId = this.actor.id;
dragData.sceneId = this.actor.isToken ? canvas.scene?.id : null;
dragData.tokenId = this.actor.isToken ? this.actor.token.id : null;
dragData.pack = this.actor.pack;

// Active Effect
if (li.dataset.effectId) {
const effect = this.actor.effects.get(li.dataset.effectId);
Expand Down
12 changes: 8 additions & 4 deletions src/module/macros.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
*/
export async function createOseMacro(data, slot) {
if (data.type !== "Item") return;
if (!("data" in data))
if ( data.uuid.indexOf("Item.") <= 0 )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 clever haha

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes it happens :P

return ui.notifications.warn(
game.i18.localize("OSE.warn.macrosOnlyForOwnedItems")
game.i18n.localize("OSE.warn.macrosOnlyForOwnedItems")
);
const item = data.data;
const item = data.item;

// Create the macro command
const command = `game.ose.rollItemMacro("${item.name}");`;
Expand Down Expand Up @@ -45,6 +45,10 @@ export async function createOseMacro(data, slot) {
*/
export function rollItemMacro(itemName) {
const speaker = ChatMessage.getSpeaker();
// Active actor, or inactive actor + token on scene allowed
if (!(speaker.actor && speaker.scene))
return ui.notifications.warn(game.i18n.localize("OSE.warn.macrosNoTokenOwnedInScene"));

let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
if (!actor) actor = game.actors.get(speaker.actor);
Expand All @@ -60,7 +64,7 @@ export function rollItemMacro(itemName) {
);
} else if (items.length === 0) {
return ui.notifications.error(
game.i18n.format("OSE.warn.noItemWithName", {
game.i18n.format("OSE.error.noItemWithName", {
actorName: actor.name,
itemName: itemName,
})
Expand Down
8 changes: 5 additions & 3 deletions src/ose.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ Hooks.once("setup", function () {
});

Hooks.once("ready", async () => {
Hooks.on("hotbarDrop", (bar, data, slot) =>
macros.createOseMacro(data, slot)
);
Hooks.on("hotbarDrop", (bar, data, slot) => {
macros.createOseMacro(data, slot);
// Returning false to stop the rest of hotbarDrop handling.
return false;
});
});

// License info
Expand Down