Skip to content
This repository has been archived by the owner on Apr 8, 2021. It is now read-only.

Latest commit

 

History

History
69 lines (47 loc) · 4.67 KB

SD11.1-Creating-rollable-buttons-with-event-listeners.md

File metadata and controls

69 lines (47 loc) · 4.67 KB

To make things on your character sheet rollable, you'll need to add a class that you can listen for in your sheet's activateListeners() method. In the Boilerplate System, ability rolls have an example of this with a rollable class. Let's look at the ability modifier line from actor-sheet.html:

<span class="ability-mod rollable" data-roll="d20+@abilities.{{key}}.mod" data-label="{{key}}">{{numberFormat ability.mod decimals=0 sign=true}}</span>

We've added a rollable class along with a few different attributes for data-roll and data-label that our listener can then use to create the rolls. Those attributes aren't really necessary; because this is a character sheet we could just add the rollable class and then compute those rolls in the JS. However, by making them into attributes, we can just include the attributes with whatever formula we need, and the data-label will show up in the chat message as flavor text.

The formula in this example includes @abilities.{{key}}.mod, which would compute as @abilities.str.mod, for example. This should follow the same format if you were to write out inline rolls in chat or in macros, because in the roll method we're about to make, we're passing it this.actor.data.data just like core does for those scenarios.

Finally, the rollable class also includes some lightweight CSS for it to turn the mouse into a pointer and add a red text shadow on hover or focus.

activateListeners()

Next, let's take a look at actor-sheet.js where we've overridden the ActorSheet class. We need to add a new click listener inside our ActorSheet's activateListeners() method:

// Rollable abilities.
html.find('.rollable').click(this._onRoll.bind(this));

This will call a custom _onRoll() method on click. Because that method doesn't exist, we need to go down towards the end of our class and add a new method after the _onItemCreate() method:

/**
 * Handle clickable rolls.
 * @param {Event} event   The originating click event
 * @private
 */
_onRoll(event) {
  event.preventDefault();
  const element = event.currentTarget;
  const dataset = element.dataset;

  if (dataset.roll) {
    let roll = new Roll(dataset.roll, this.actor.data.data);
    let label = dataset.label ? `Rolling ${dataset.label}` : '';
    roll.roll().toMessage({
      speaker: ChatMessage.getSpeaker({ actor: this.actor }),
      flavor: label
    });
  }
}

First, we're preventing other click behaviors (such as if this were an <a> tag), and then we're grabbing both the element that was clicked and any data attributes that were included on that element (the data-roll and data-label attributes, specifically).

Next, if there is a dataset.roll attribute, we'll use that to build the roll. To create a roll, we use new Roll('formula'), and we've already written out the formula in our Handlebars template. The second argument of Roll() is the object to use for its data, so in this case we want to pass along the actor's data attributes.

After that, we get the label attribute if any. And with that we have everything we need to send it to chat. Creating a new roll doesn't actually rolling it, so we have to call the roll() method on our Roll object, and then call the toMessage() method on that result to send it to chat. We want this to reference the actor token as the speaker for the chat message, so we set the speaker and flavor properties to match what we need.

And with that, we've successfully made rollable attributes!