How to integrate TyphonJS Actor sheet with 3rd party modules?

E.g. Tokenizer https://github.com/MrPrimate/tokenizer. I'm not sure if this is a TyphonJS / Svelte question or a more basic Foundry system dev question. What I'm trying to do is to get an Actor profile image similar to the default one in D&D 5e system, which can then support 3rd party modules that allow customisation of the profile. I'm not sure what approach to take for this, so some guidance would be much appreciated!
16 Replies
Unknown User
Unknown User17mo ago
Message Not Public
Sign In & Join Server To View
geoidesic
geoidesic17mo ago
Hmm... I don't know how... it's not working for me. I have this in my ActorSheet.svelte
setContext("#doc", documentStore); //<--- this is the Actor store

<img cleass="profile" src="{$documentStore.img}" data-tooltip="{$documentStore.name}" data-edit="img" />
setContext("#doc", documentStore); //<--- this is the Actor store

<img cleass="profile" src="{$documentStore.img}" data-tooltip="{$documentStore.name}" data-edit="img" />
And it renders the default profile image but clicking on it does nothing.
TyphonJS (Michael)
You should probably read the Tokenizer documentation and watch the overview video. That module doesn't integrate automatically into actor sheets of any given system at all. It also applies the tokenized image to I assume the prototype token and not the main image displayed in the actor sheet; you'll have to read the documentation to figure that out and perhaps the source code of Tokenizer to understand what it is doing. I gather if you activate tokenizer from the world actor directory and apply one and you have the standard actor data layout you'll see the tokenized version when you drag the actor to the scene.
geoidesic
geoidesic17mo ago
Well yes but more importantly when you click on your profile in the Actor sheet, it normally opens a window where you can add your profile image. Tokenizer hooks into that allowing some better artistic control over your profile image. However at this point clicking on the profile image does not open the expected prompt – even without Tokenizer installed. So I guess my question is do I have to manually build a token image manager or can I hook into the default system there provided by Foundry?
TyphonJS (Michael)
Why would it open anything when you haven't added event handlers to do so. You'll have to add a on:click handler and use the Foundry core API / file browser and then assign the result to your actor. If Tokenizer does hook into the Foundry core file browser then it should display as part of that.
geoidesic
geoidesic17mo ago
Ok thx, that gives me a starting point 🙂
Unknown User
Unknown User17mo ago
Message Not Public
Sign In & Join Server To View
TyphonJS (Michael)
Indeed once there is a standard TRL system reference some of the boiler plate aspects will be handled. The core ActorSheet only has this single handler for opening the file browser and setting the image. @geoidesic; perhaps examining the core ActorSheet class and what it does will help, but keep in mind that you are looking at stock Application v1 API and you need to adapt things to Svelte. You are currently completely in control of building out your own actor sheet without a base implementation. In the core actor sheet the click event listener for the image does this:
/**
* Handle changing the actor profile image by opening a FilePicker
* @param {Event} event The input field change event
* @private
*/
_onEditImage(event) {
const current = foundry.utils.getProperty(this.actor, attr);
const fp = new FilePicker({
type: "image",
current: current,
callback: path => {
event.currentTarget.src = path;
this._onSubmit(event);
},
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
/**
* Handle changing the actor profile image by opening a FilePicker
* @param {Event} event The input field change event
* @private
*/
_onEditImage(event) {
const current = foundry.utils.getProperty(this.actor, attr);
const fp = new FilePicker({
type: "image",
current: current,
callback: path => {
event.currentTarget.src = path;
this._onSubmit(event);
},
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
You'll have to modify this as it is JQuery usage first off. event is a JQuery event; there is no currentTarget in browser DOM events. It's event.target. You also don't necessarily need to put data attributes in your Svelte template as the benefit of a self contained component means that you have context for what document and what field you are targeting in the component vs the standard FormApplication / stock App v1 approach of using data attributes. You'll end up with something more like this (pseudo-code / I haven't tested this) :
<script>
import { getContext } from 'svelte';

const { application } = getContext('external');

function onEditImage()
{
const current = $documentStore.img;
const fp = new FilePicker({
type: "image",
current: current,
callback: (path) => {
$documentStore.update({ img: path });
},
top: application.position.top + 40,
left: application.position.left + 10
});
return fp.browse();
}
</script>

<img class="profile" src="{$documentStore.img}" data-tooltip="{$documentStore.name}" on:click={onEditImage} />
<script>
import { getContext } from 'svelte';

const { application } = getContext('external');

function onEditImage()
{
const current = $documentStore.img;
const fp = new FilePicker({
type: "image",
current: current,
callback: (path) => {
$documentStore.update({ img: path });
},
top: application.position.top + 40,
left: application.position.left + 10
});
return fp.browse();
}
</script>

<img class="profile" src="{$documentStore.img}" data-tooltip="{$documentStore.name}" on:click={onEditImage} />
When you make the document update call in the FilePicker callback the TJSDocument will update with an automatic render.
geoidesic
geoidesic17mo ago
Amazing! Thanks very much for that! I'll give it a go. I did have a look at the API documentation for Foundry and couldn't see anything about the FilePicker, so this is very useful info indeed. Nice! That worked with one small exception... it didn't recognise this.position, but stripping out those two lines left it in perfect working order. It only opens the default Foundry file browser, so apparently Tokenizer requires some other magic, which I think they have documented, so hopefully that won't be hard.
TyphonJS (Michael)
I updated the example to pull the external application reference / position... If you don't include that I assume the FilePicker will open in the center of the browser window. That is just to position the FilePicker closer to the relative position of the actor image usually being in the top left of the actor sheet.
Unknown User
Unknown User17mo ago
Message Not Public
Sign In & Join Server To View
TyphonJS (Michael)
Next up on the chopping block for TRL is sorting / drag and drop support for reactive embedded collections. This is the missing functionality IMHO that will lead to a standardized system reference. I don't want to put out a demo reference implementation before that is ready.
Unknown User
Unknown User17mo ago
Message Not Public
Sign In & Join Server To View
TyphonJS (Michael)
@geoidesic I do want to point out that the pseudo-code above is just the beginning and not the end. There are several avenues to improve UX. The first is protecting against a user clicking multiple times on the image and ignoring the file pickers that are launched. It's better to keep a reference to a single file picker app launched and manage it. If one is active and the user clicks on the actor image again bring it to top instead of creating another. Use the Svelte onDestroy callback mechanism to also close any existing file picker when the actor sheet closes. Also doing some basic data verification for the path returned is probably appropriate. So, there is always more to do beyond the basic snippets that can be offered easily in responding to a question.
geoidesic
geoidesic16mo ago
Got it working nicely with both the default FilePicker and the Tokenizer module 🔥
TyphonJS (Michael)
Excellent! At some point maybe a super slick Svelte based file picker will exist. 😄