Open kgar opened 7 months ago
hello @kgar , thanks for writing up, didn't know about the API, and that's awesome. I think I will need that for this and another module https://github.com/misthero/dnd5e-custom-skills.
That module adds skills and abilities and has been a litte hard to integrate it with tidy.
If you can throw a couple of hints at me, about where to start I hope I can figure out the rest.
Thanks for working with me on this.
First, you acquire the API through a Tidy custom hook:
Hooks.once("tidy5e-sheet.ready", (api) => {
// TODO: Add some awesome stuff!
});
Alternatively, and this is usually for the World Scripter crowd, the API can be acquired from the module, but there are caveats to this approach:
const api = game.modules.get('tidy5e-sheet')?.api ?? game.modules.get('tidy5e-sheet-kgar')?.api;
Caveats:
tidy5e-sheet-kgar
is my temporary module ID until I retire the original Tidy 5e Sheet repo and overtake the main module ID.ready
is called.If you have content that is meant to be placed in one location, you can use the content registration functions.
Here is an example of registering content for a character:
Hooks.once("tidy5e-sheet.ready", (api) => {
api.registerCharacterContent(
new api.models.HtmlContent({
html: `<a title="Example Button" class="my-custom-icon"><i class="fas fa-user"></i></a>`,
injectParams: {
selector: `[data-tidy-sheet-part="${api.constants.SHEET_PARTS.NAME_CONTAINER}"]`,
position: "beforebegin",
},
onRender: (params) => {
params.element
.querySelector(".my-custom-icon")
.addEventListener("click", () => alert("Clicked custom PC icon"));
},
})
);
});
When you register content in this way, Tidy knows to clear this content and refresh it any time the default sheets would normally have re-rendered the entire sheet.
If your content has HTML inputs with the name
attribute, changes to those inputs will automatically submit the sheets and save changes. Otherwise, if you normally have to wire events for your content, you can use onRender
to wire events, as onRender
is called after your content has been put in place.
I have deliberately chosen to use insertAdjacentHTML()
as the underlying mechanism for placing custom content. As such, the injectParams
prop's position
field is referring to these locations from the related MDN article:
I'm on a quest to provide data-tidy-sheet-part
attributes throughout my sheets so that most common injection sites are easily targetable. One reason for this is because classes can come and go, and I'm aiming to make multiple sheet layouts in the future, so I want attributes which are independent from potential CSS rule targeting. Additionally, I'll be using sheet parts when doing automated testing, so my aim for them to stick around and to be fairly reliable.
With that said, it's a work in progress. You'll see sheet parts throughout the sheets in the DOM:
Meanwhile, I also have a consolidated list of the sheet parts with general explanations in the API docs here: https://kgar.github.io/foundry-vtt-tidy-5e-sheets/classes/Tidy5eSheetsApi.html#constants
Below the constants section, each sheet part that currently exists in the wild has an explanation attached to it.
I'm in the business of adding more sheet parts. I'm on a fairly short release cycle (multiple per day if I have to, but usually 1 release every 2-4 days). I will make a special effort if a module developer needs API stuff and I'm certain how to provide it.
That's what I have for you for now. Let me know if you have any questions, comments, ideas, etc. I should really start that wiki sometime soon, having typed some of this out here...
Thanks for the heads up, I tried the implementation, and the tidy5e-sheet.ready works well, but I think in my case I should keep using the .renderActorSheet hook, since I need the current actor document before adding the html. I need to know if the sheet is for a player character and read the actor flags to change the icon. Any idea?
I see what you mean.
You can use a callback function when registering HTML content, which should give you the flexibility you need:
Hooks.once("tidy5e-sheet.ready", (api) => {
api.registerCharacterContent(
new api.models.HtmlContent({
html: (data) => { // π `data` is the actor sheet context data that comes with `renderActorSheet`
const myFlag = data.actor.flags['my-module.my-flag'];
return myFlag ? `<span class="my-content">π</span>` : `<span class="my-content">π±</span>`;
},
injectParams: {
selector: `[data-tidy-sheet-part="${api.constants.SHEET_PARTS.NAME_CONTAINER}"]`,
position: "beforebegin",
},
enabled: (data) => true, // π If you only show this content based on a setting, you can check that here; `data` is the actor sheet context data
onRender: (params) => {
params.element
.querySelector(".my-content")
?.addEventListener("click", () => alert("Clicked custom PC icon"));
},
})
);
});
In the previous example with using api.registerCharacterContent
, it is applying to Player Characters only.
There are other options like registerNpcContent
for NPCs, registerVehicleContent
for vehicles, and registerActorContent
for all supported Tidy actor sheets.
Was there any update on this? I would love to see it work with tidy5e sheets
If it helps, Tidy has a tidy5e-sheet.renderActorSheet
hook which gets called like the traditional renderActorSheet
hooks.
You can inject any content into the sheet from that hook, and as long as you put data-tidy-render-scheme="handlebars"
on the top-most HTML elements you inject, Tidy will make sure to remove the old content and inject the new content, in the style of Handlebars.
Hooks.on('tidy5e-sheet.renderActorSheet', (app, element, data) => {
const someHtml = `<h1 data-tidy-render-scheme="handlebars">Hello</h1>`;
$('.some-class').append(someHtml);
});
If you want to reuse your template without putting Tidy attributes on it, you can wrap your result template code as follows:
let rendered_html = '<p>rendered template here</p>';
// When type is "tidy", wrap it
if (type === 'tidy') {
rendered_html = `<div style="display: contents;" data-tidy-render-scheme="handlebars">${rendered_html}</div>`
}
I realize the API approach is a lot, so these days, I encourage using the tidy hook and the data-tidy-render-scheme
attribute for injecting stuff into Tidy sheets.
Was there any update on this? I would love to see it work with tidy5e sheets
the module works on tidy (by my testing) just the fancy spell points tracking bar of the dndv3 character sheet is not there, but functionally it should calculate spell points correctly, make sure you updated to version 2.2.1 of the spell points module.
for now you can just flag as favourite the spell points item to see it in the first page of the character sheet.
The user who reported this on my repo retested and is good to go. I'm good for this issue to close if everyone here is.
Hello, I am the author of the new Tidy 5e Sheets rewrite. The new sheets are using svelte and have their own rendering rules and HTML structure, so they do not integrate automatically the way default and default-like sheets do.
As a result, I have been going from module to module to request the opportunity to establish intentional compatibility with my sheets. I have an API for injecting content, and I will gladly volunteer a pull request and/or sample code for integrating.
Recently, I had a github issue requesting compatibility between our modules: https://github.com/kgar/foundry-vtt-tidy-5e-sheets/issues/247
If there is any content that is injected into the sheet during rendering, that would be what needs the API to be injected successfully. Also, I have special selectors available for injecting things.
For now, I just wanted to start the discussion, as I'm doing some compatibility work elsewhere, but I can provide you some neat options for where to put things like the "This character uses Spell Points" toggle.
Wherever possible, I try to make integration out-of-the-way and minimal, and my integration API / offerings are under active development and evolving based on module author needs.
I hope to work together. Our mutual users would love for us to team up.